test(all): switch tap runner for mocha
This commit is contained in:
Родитель
6aa8ef2f91
Коммит
6c815d0416
|
@ -58,6 +58,9 @@ function AppError(options, extra, headers) {
|
|||
this.message = options.message || DEFAULTS.message
|
||||
this.isBoom = true
|
||||
this.stack = options.stack
|
||||
if (!this.stack) {
|
||||
Error.captureStackTrace(this, AppError)
|
||||
}
|
||||
this.errno = options.errno || DEFAULTS.errno
|
||||
this.output = {
|
||||
statusCode: options.code || DEFAULTS.code,
|
||||
|
|
14
lib/log.js
14
lib/log.js
|
@ -262,19 +262,5 @@ module.exports = function (level, name, options) {
|
|||
}
|
||||
)
|
||||
|
||||
Object.keys(console).forEach(
|
||||
function (key) {
|
||||
console[key] = function () { // eslint-disable-line no-console
|
||||
var json = { op: 'console', message: util.format.apply(null, arguments) }
|
||||
if(log[key]) {
|
||||
log[key](json)
|
||||
}
|
||||
else {
|
||||
log.warn(json)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
return log
|
||||
}
|
||||
|
|
10
package.json
10
package.json
|
@ -13,9 +13,9 @@
|
|||
"start": "NODE_ENV=dev scripts/start-local.sh 2>&1",
|
||||
"start-mysql": "NODE_ENV=dev scripts/start-local-mysql.sh 2>&1",
|
||||
"test-quick": "npm run tq",
|
||||
"test-e2e": "NODE_ENV=dev tap test/e2e 2>/dev/null",
|
||||
"tq": "NODE_ENV=dev tap test/local 2>/dev/null && NODE_ENV=dev CORS_ORIGIN=https://bar scripts/test-remote-quick.js",
|
||||
"test-remote": "MAILER_HOST=restmail.net MAILER_PORT=80 CORS_ORIGIN=http://baz tap --timeout=300 --tap test/remote",
|
||||
"test-e2e": "NODE_ENV=dev mocha test/e2e",
|
||||
"tq": "NODE_ENV=dev mocha test/local 2>/dev/null && NODE_ENV=dev CORS_ORIGIN=https://bar scripts/test-remote-quick.js",
|
||||
"test-remote": "MAILER_HOST=restmail.net MAILER_PORT=80 CORS_ORIGIN=http://baz mocha --timeout=300000 test/remote",
|
||||
"prepush": "grunt quicklint"
|
||||
},
|
||||
"repository": {
|
||||
|
@ -77,16 +77,18 @@
|
|||
"grunt-nsp": "2.3.1",
|
||||
"hawk": "2.3.1",
|
||||
"husky": "0.11.7",
|
||||
"insist": "1.0.0",
|
||||
"jws": "3.1.3",
|
||||
"leftpad": "0.0.0",
|
||||
"load-grunt-tasks": "3.5.2",
|
||||
"mailparser": "0.6.1",
|
||||
"mocha": "3.1.2",
|
||||
"nock": "8.0.0",
|
||||
"nyc": "8.4.0",
|
||||
"proxyquire": "1.7.10",
|
||||
"simplesmtp": "0.3.35",
|
||||
"sinon": "1.17.5",
|
||||
"sjcl": "1.0.6",
|
||||
"tap": "7.1.2",
|
||||
"ws": "1.1.1"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
/* 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 path = require('path')
|
||||
const spawn = require('child_process').spawn
|
||||
|
||||
const MOCHA_BIN = path.join(path.dirname(__dirname), 'node_modules', '.bin', 'mocha')
|
||||
const NYC_BIN = path.join(path.dirname(__dirname), 'node_modules', '.bin', 'nyc')
|
||||
|
||||
let bin = NYC_BIN
|
||||
let argv = ['--cache', MOCHA_BIN]
|
||||
|
||||
if (process.env.NO_COVERAGE) {
|
||||
bin = MOCHA_BIN
|
||||
argv = []
|
||||
}
|
||||
|
||||
const p = spawn(bin, argv.concat(process.argv.slice(2)), { stdio: 'inherit', env: process.env })
|
||||
|
||||
// exit this process with the same exit code as the test process
|
||||
p.on('close', function (code) {
|
||||
process.exit(code)
|
||||
})
|
|
@ -1,21 +0,0 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
/* 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/. */
|
||||
|
||||
var path = require('path'),
|
||||
spawn = require('child_process').spawn
|
||||
|
||||
var COVERAGE_ARGS = ['--coverage', '--cov']
|
||||
if (process.env.NO_COVERAGE) {
|
||||
COVERAGE_ARGS = []
|
||||
}
|
||||
|
||||
var p = spawn(path.join(path.dirname(__dirname), 'node_modules', '.bin', 'tap'),
|
||||
process.argv.slice(2).concat(COVERAGE_ARGS), { stdio: 'inherit', env: process.env })
|
||||
|
||||
// exit this process with the same exit code as the test process
|
||||
p.on('close', function (code) {
|
||||
process.exit(code)
|
||||
})
|
|
@ -10,5 +10,5 @@ fi
|
|||
./scripts/gen_keys.js
|
||||
./scripts/gen_vapid_keys.js
|
||||
./scripts/check-i18n.js
|
||||
./scripts/tap-coverage.js $glob 2>/dev/null
|
||||
./scripts/mocha-coverage.js -R dot $glob
|
||||
grunt eslint copyright
|
||||
|
|
|
@ -12,13 +12,13 @@ var TestServer = require('../test/test_server')
|
|||
TestServer.start(config, false)
|
||||
.then(
|
||||
function (server) {
|
||||
var tap = spawn(
|
||||
path.join(path.dirname(__dirname), 'node_modules/.bin/tap'),
|
||||
var cp = spawn(
|
||||
path.join(path.dirname(__dirname), 'node_modules/.bin/mocha'),
|
||||
['test/remote'],
|
||||
{ stdio: 'inherit' }
|
||||
)
|
||||
|
||||
tap.on('close', function(code) {
|
||||
cp.on('close', function(code) {
|
||||
server.stop()
|
||||
})
|
||||
}
|
||||
|
|
|
@ -2,5 +2,8 @@ plugins:
|
|||
- fxa
|
||||
extends: ../.eslintrc
|
||||
|
||||
env:
|
||||
mocha: true
|
||||
|
||||
rules:
|
||||
fxa/async-crypto-random: 0
|
||||
|
|
|
@ -2,10 +2,11 @@
|
|||
* 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/. */
|
||||
|
||||
var tap = require('tap')
|
||||
'use strict'
|
||||
|
||||
const assert = require('insist')
|
||||
var proxyquire = require('proxyquire')
|
||||
|
||||
var test = tap.test
|
||||
var P = require('../../lib/promise')
|
||||
var config = require('../../config').getProperties()
|
||||
var spyLog = require('../mocks').spyLog
|
||||
|
@ -13,53 +14,58 @@ var mockUid = new Buffer('foo')
|
|||
|
||||
var PushManager = require('../push_helper').PushManager
|
||||
|
||||
var pushManager = new PushManager({
|
||||
server: 'wss://push.services.mozilla.com/',
|
||||
channelId: '9500b5e6-9954-40d5-8ac1-3920832e781e'
|
||||
})
|
||||
describe('e2e/push', () => {
|
||||
|
||||
test(
|
||||
'pushToAllDevices sends notifications using a real push server',
|
||||
function (t) {
|
||||
pushManager.getSubscription().then(function (subscription) { // eslint-disable-line no-unreachable
|
||||
var mockDbResult = {
|
||||
devices: function (/* uid */) {
|
||||
return P.resolve([
|
||||
{
|
||||
'id': '0f7aa00356e5416e82b3bef7bc409eef',
|
||||
'isCurrentDevice': true,
|
||||
'lastAccessTime': 1449235471335,
|
||||
'name': 'My Phone',
|
||||
'type': 'mobile',
|
||||
'pushCallback': subscription.endpoint,
|
||||
'pushPublicKey': 'BBXOKjUb84pzws1wionFpfCBjDuCh4-s_1b52WA46K5wYL2gCWEOmFKWn_NkS5nmJwTBuO8qxxdjAIDtNeklvQc',
|
||||
'pushAuthKey': 'GSsIiaD2Mr83iPqwFNK4rw'
|
||||
}
|
||||
])
|
||||
},
|
||||
updateDevice: function () {
|
||||
return P.resolve()
|
||||
}
|
||||
}
|
||||
let pushManager
|
||||
before(() => {
|
||||
pushManager = new PushManager({
|
||||
server: 'wss://push.services.mozilla.com/',
|
||||
channelId: '9500b5e6-9954-40d5-8ac1-3920832e781e'
|
||||
})
|
||||
})
|
||||
|
||||
var thisSpyLog = spyLog({
|
||||
info: function (log) {
|
||||
if (log.name === 'push.account_verify.success') {
|
||||
t.end()
|
||||
it(
|
||||
'pushToAllDevices sends notifications using a real push server',
|
||||
() => {
|
||||
return pushManager.getSubscription().then(function (subscription) { // eslint-disable-line no-unreachable
|
||||
var mockDbResult = {
|
||||
devices: function (/* uid */) {
|
||||
return P.resolve([
|
||||
{
|
||||
'id': '0f7aa00356e5416e82b3bef7bc409eef',
|
||||
'isCurrentDevice': true,
|
||||
'lastAccessTime': 1449235471335,
|
||||
'name': 'My Phone',
|
||||
'type': 'mobile',
|
||||
'pushCallback': subscription.endpoint,
|
||||
'pushPublicKey': 'BBXOKjUb84pzws1wionFpfCBjDuCh4-s_1b52WA46K5wYL2gCWEOmFKWn_NkS5nmJwTBuO8qxxdjAIDtNeklvQc',
|
||||
'pushAuthKey': 'GSsIiaD2Mr83iPqwFNK4rw'
|
||||
}
|
||||
])
|
||||
},
|
||||
updateDevice: function () {
|
||||
return P.resolve()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
var push = proxyquire('../../lib/push', {})(thisSpyLog, mockDbResult, config)
|
||||
var options = {
|
||||
data: new Buffer('foodata')
|
||||
}
|
||||
push.pushToAllDevices(mockUid, 'accountVerify', options).then(function() {
|
||||
if (thisSpyLog.error.callCount !== 0) {
|
||||
throw new Error('No errors should have been logged')
|
||||
let count = 0
|
||||
var thisSpyLog = spyLog({
|
||||
info: function (log) {
|
||||
if (log.name === 'push.account_verify.success') {
|
||||
count++
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
var push = proxyquire('../../lib/push', {})(thisSpyLog, mockDbResult, config)
|
||||
var options = {
|
||||
data: new Buffer('foodata')
|
||||
}
|
||||
return push.pushToAllDevices(mockUid, 'accountVerify', options).then(function() {
|
||||
assert.equal(thisSpyLog.error.callCount, 0, 'No errors should have been logged')
|
||||
assert.equal(count, 1)
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
})
|
||||
|
|
|
@ -2,58 +2,60 @@
|
|||
* 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/. */
|
||||
|
||||
var test = require('../ptaptest')
|
||||
var log = { trace: function() {} }
|
||||
'use strict'
|
||||
|
||||
var tokens = require('../../lib/tokens')(log)
|
||||
var AccountResetToken = tokens.AccountResetToken
|
||||
const assert = require('insist')
|
||||
|
||||
var ACCOUNT = {
|
||||
const log = { trace() {} }
|
||||
const tokens = require('../../lib/tokens')(log)
|
||||
const AccountResetToken = tokens.AccountResetToken
|
||||
|
||||
const ACCOUNT = {
|
||||
uid: 'xxx'
|
||||
}
|
||||
|
||||
describe('account reset tokens', () => {
|
||||
|
||||
test(
|
||||
're-creation from tokenData works',
|
||||
function (t) {
|
||||
var token = null
|
||||
return AccountResetToken.create(ACCOUNT)
|
||||
.then(
|
||||
function (x) {
|
||||
token = x
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
return AccountResetToken.fromHex(token.data, ACCOUNT)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (token2) {
|
||||
t.deepEqual(token.data, token2.data)
|
||||
t.deepEqual(token.id, token2.id)
|
||||
t.deepEqual(token.authKey, token2.authKey)
|
||||
t.deepEqual(token.bundleKey, token2.bundleKey)
|
||||
t.deepEqual(token.uid, token2.uid)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
it(
|
||||
'should re-create from tokenData',
|
||||
() => {
|
||||
let token = null
|
||||
return AccountResetToken.create(ACCOUNT)
|
||||
.then(
|
||||
(x) => {
|
||||
token = x
|
||||
}
|
||||
)
|
||||
.then(
|
||||
() => AccountResetToken.fromHex(token.data, ACCOUNT)
|
||||
)
|
||||
.then(
|
||||
(token2) => {
|
||||
assert.deepEqual(token.data, token2.data)
|
||||
assert.deepEqual(token.id, token2.id)
|
||||
assert.deepEqual(token.authKey, token2.authKey)
|
||||
assert.deepEqual(token.bundleKey, token2.bundleKey)
|
||||
assert.deepEqual(token.uid, token2.uid)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'accountResetToken key derivations are test-vector compliant',
|
||||
function (t) {
|
||||
var token = null
|
||||
var tokenData = 'c0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedf'
|
||||
return AccountResetToken.fromHex(tokenData, ACCOUNT)
|
||||
.then(
|
||||
function (x) {
|
||||
token = x
|
||||
t.equal(token.data.toString('hex'), tokenData)
|
||||
t.equal(token.id.toString('hex'), '46ec557e56e531a058620e9344ca9c75afac0d0bcbdd6f8c3c2f36055d9540cf')
|
||||
t.equal(token.authKey.toString('hex'), '716ebc28f5122ef48670a48209190a1605263c3188dfe45256265929d1c45e48')
|
||||
t.equal(token.bundleKey.toString('hex'), 'aa5906d2318c6e54ecebfa52f10df4c036165c230cc78ee859f546c66ea3c126')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
it(
|
||||
'should have test-vector compliant key derivations',
|
||||
() => {
|
||||
let token = null
|
||||
const tokenData = 'c0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedf'
|
||||
return AccountResetToken.fromHex(tokenData, ACCOUNT)
|
||||
.then(
|
||||
(x) => {
|
||||
token = x
|
||||
assert.equal(token.data.toString('hex'), tokenData)
|
||||
assert.equal(token.id.toString('hex'), '46ec557e56e531a058620e9344ca9c75afac0d0bcbdd6f8c3c2f36055d9540cf')
|
||||
assert.equal(token.authKey.toString('hex'), '716ebc28f5122ef48670a48209190a1605263c3188dfe45256265929d1c45e48')
|
||||
assert.equal(token.bundleKey.toString('hex'), 'aa5906d2318c6e54ecebfa52f10df4c036165c230cc78ee859f546c66ea3c126')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
})
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -2,26 +2,27 @@
|
|||
* 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/. */
|
||||
|
||||
const test = require('tap').test
|
||||
const assert = require('insist')
|
||||
const base32 = require('../../lib/crypto/base32')
|
||||
|
||||
test('base32 takes 1 integer argument, returns a function', (t) => {
|
||||
t.equal(typeof base32, 'function')
|
||||
t.equal(base32.length, 1)
|
||||
const gen = base32(10)
|
||||
t.equal(typeof gen, 'function')
|
||||
t.equal(gen.length, 0)
|
||||
t.end()
|
||||
})
|
||||
describe('base32', () => {
|
||||
it('takes 1 integer argument, returns a function', () => {
|
||||
assert.equal(typeof base32, 'function')
|
||||
assert.equal(base32.length, 1)
|
||||
const gen = base32(10)
|
||||
assert.equal(typeof gen, 'function')
|
||||
assert.equal(gen.length, 0)
|
||||
})
|
||||
|
||||
test('base32 output', (t) => {
|
||||
const gen = base32(10)
|
||||
return gen().then(code => {
|
||||
t.equal(code.length, 10, 'matches length')
|
||||
t.ok(/^[0-9A-Z]+$/.test(code), 'no lowercase letters')
|
||||
t.equal(code.indexOf('I'), -1, 'no I')
|
||||
t.equal(code.indexOf('L'), -1, 'no L')
|
||||
t.equal(code.indexOf('O'), -1, 'no O')
|
||||
t.equal(code.indexOf('U'), -1, 'no U')
|
||||
it('should have correct output', () => {
|
||||
const gen = base32(10)
|
||||
return gen().then(code => {
|
||||
assert.equal(code.length, 10, 'matches length')
|
||||
assert.ok(/^[0-9A-Z]+$/.test(code), 'no lowercase letters')
|
||||
assert.equal(code.indexOf('I'), -1, 'no I')
|
||||
assert.equal(code.indexOf('L'), -1, 'no L')
|
||||
assert.equal(code.indexOf('O'), -1, 'no O')
|
||||
assert.equal(code.indexOf('U'), -1, 'no U')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
@ -2,9 +2,10 @@
|
|||
* 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/. */
|
||||
|
||||
const assert = require('insist')
|
||||
|
||||
var EventEmitter = require('events').EventEmitter
|
||||
var sinon = require('sinon')
|
||||
var test = require('../ptaptest')
|
||||
var spyLog = require('../mocks').spyLog
|
||||
var error = require('../../lib/error')
|
||||
var P = require('../../lib/promise')
|
||||
|
@ -22,302 +23,304 @@ function mockedBounces(log, db) {
|
|||
return bounces(log, error)(mockBounceQueue, db)
|
||||
}
|
||||
|
||||
test(
|
||||
'unknown message types are silently ignored',
|
||||
function (t) {
|
||||
var mockLog = spyLog()
|
||||
var mockDB = {}
|
||||
return mockedBounces(mockLog, mockDB).handleBounce(mockMessage({
|
||||
junk: 'message'
|
||||
})).then(function () {
|
||||
t.equal(mockLog.messages.length, 0)
|
||||
})
|
||||
}
|
||||
)
|
||||
describe('bounce messages', () => {
|
||||
it(
|
||||
'should ignore unknown message types',
|
||||
() => {
|
||||
var mockLog = spyLog()
|
||||
var mockDB = {}
|
||||
return mockedBounces(mockLog, mockDB).handleBounce(mockMessage({
|
||||
junk: 'message'
|
||||
})).then(function () {
|
||||
assert.equal(mockLog.messages.length, 0)
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'multiple recipients are all handled in turn',
|
||||
function (t) {
|
||||
var mockLog = spyLog()
|
||||
var mockDB = {
|
||||
emailRecord: sinon.spy(function (email) {
|
||||
return P.resolve({
|
||||
uid: '123456',
|
||||
email: email,
|
||||
emailVerified: false
|
||||
it(
|
||||
'should handle multiple recipients in turn',
|
||||
() => {
|
||||
var mockLog = spyLog()
|
||||
var mockDB = {
|
||||
emailRecord: sinon.spy(function (email) {
|
||||
return P.resolve({
|
||||
uid: '123456',
|
||||
email: email,
|
||||
emailVerified: false
|
||||
})
|
||||
}),
|
||||
deleteAccount: sinon.spy(function (record) {
|
||||
return P.resolve({ })
|
||||
})
|
||||
}),
|
||||
deleteAccount: sinon.spy(function (record) {
|
||||
return P.resolve({ })
|
||||
})
|
||||
}
|
||||
var mockMsg = mockMessage({
|
||||
bounce: {
|
||||
bounceType: 'Permanent',
|
||||
bouncedRecipients: [
|
||||
{ emailAddress: 'test@example.com' },
|
||||
{ emailAddress: 'foobar@example.com'}
|
||||
]
|
||||
}
|
||||
})
|
||||
return mockedBounces(mockLog, mockDB).handleBounce(mockMsg).then(function () {
|
||||
t.equal(mockDB.emailRecord.callCount, 2)
|
||||
t.equal(mockDB.deleteAccount.callCount, 2)
|
||||
t.equal(mockDB.emailRecord.args[0][0], 'test@example.com')
|
||||
t.equal(mockDB.emailRecord.args[1][0], 'foobar@example.com')
|
||||
t.equal(mockLog.messages.length, 6, 'messages logged')
|
||||
t.equal(mockLog.messages[1].level, 'increment')
|
||||
t.equal(mockLog.messages[1].args[0], 'account.email_bounced')
|
||||
t.equal(mockLog.messages[5].level, 'info')
|
||||
t.equal(mockLog.messages[5].args[0].op, 'accountDeleted')
|
||||
t.equal(mockLog.messages[5].args[0].email, 'foobar@example.com')
|
||||
t.equal(mockMsg.del.callCount, 1)
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'abuse complaints are treated like bounces',
|
||||
function (t) {
|
||||
var mockLog = spyLog()
|
||||
var mockDB = {
|
||||
emailRecord: sinon.spy(function (email) {
|
||||
return P.resolve({
|
||||
uid: '123456',
|
||||
email: email,
|
||||
emailVerified: false
|
||||
})
|
||||
}),
|
||||
deleteAccount: sinon.spy(function (record) {
|
||||
return P.resolve({ })
|
||||
})
|
||||
}
|
||||
return mockedBounces(mockLog, mockDB).handleBounce(mockMessage({
|
||||
complaint: {
|
||||
complaintFeedbackType: 'abuse',
|
||||
complainedRecipients: [
|
||||
{ emailAddress: 'test@example.com' },
|
||||
{ emailAddress: 'foobar@example.com'}
|
||||
]
|
||||
}
|
||||
})).then(function () {
|
||||
t.equal(mockDB.emailRecord.callCount, 2)
|
||||
t.equal(mockDB.deleteAccount.callCount, 2)
|
||||
t.equal(mockDB.emailRecord.args[0][0], 'test@example.com')
|
||||
t.equal(mockDB.emailRecord.args[1][0], 'foobar@example.com')
|
||||
t.equal(mockLog.messages.length, 6)
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'verified accounts are not deleted on bounce',
|
||||
function (t) {
|
||||
var mockLog = spyLog()
|
||||
var mockDB = {
|
||||
emailRecord: sinon.spy(function (email) {
|
||||
return P.resolve({
|
||||
uid: '123456',
|
||||
email: email,
|
||||
emailVerified: (email === 'verified@example.com')
|
||||
})
|
||||
}),
|
||||
deleteAccount: sinon.spy(function (record) {
|
||||
return P.resolve({ })
|
||||
})
|
||||
}
|
||||
return mockedBounces(mockLog, mockDB).handleBounce(mockMessage({
|
||||
bounce: {
|
||||
bounceType: 'Permanent',
|
||||
// docs: http://docs.aws.amazon.com/ses/latest/DeveloperGuide/notification-contents.html#bounced-recipients
|
||||
bouncedRecipients: [
|
||||
{ emailAddress: 'test@example.com', action: 'failed', status: '5.0.0', diagnosticCode: 'smtp; 550 user unknown' },
|
||||
{ emailAddress: 'verified@example.com', status: '4.0.0' }
|
||||
]
|
||||
}
|
||||
})).then(function () {
|
||||
t.equal(mockDB.emailRecord.callCount, 2)
|
||||
t.equal(mockDB.emailRecord.args[0][0], 'test@example.com')
|
||||
t.equal(mockDB.emailRecord.args[1][0], 'verified@example.com')
|
||||
t.equal(mockDB.deleteAccount.callCount, 1)
|
||||
t.equal(mockDB.deleteAccount.args[0][0].email, 'test@example.com')
|
||||
t.equal(mockLog.messages.length, 6)
|
||||
t.equal(mockLog.messages[0].args[0].op, 'handleBounce')
|
||||
t.equal(mockLog.messages[0].args[0].email, 'test@example.com')
|
||||
t.equal(mockLog.messages[0].args[0].status, '5.0.0')
|
||||
t.equal(mockLog.messages[0].args[0].action, 'failed')
|
||||
t.equal(mockLog.messages[0].args[0].diagnosticCode, 'smtp; 550 user unknown')
|
||||
t.equal(mockLog.messages[1].args[0], 'account.email_bounced')
|
||||
t.equal(mockLog.messages[2].args[0].op, 'accountDeleted')
|
||||
t.equal(mockLog.messages[2].args[0].email, 'test@example.com')
|
||||
t.equal(mockLog.messages[3].args[0].op, 'handleBounce')
|
||||
t.equal(mockLog.messages[3].args[0].email, 'verified@example.com')
|
||||
t.equal(mockLog.messages[3].args[0].status, '4.0.0')
|
||||
t.notOk(mockLog.messages[3].args[0].diagnosticCode)
|
||||
t.equal(mockLog.messages[4].args[0], 'account.email_bounced')
|
||||
t.equal(mockLog.messages[5].level, 'increment')
|
||||
t.equal(mockLog.messages[5].args[0], 'account.email_bounced.already_verified')
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'errors when looking up the email record are logged',
|
||||
function (t) {
|
||||
var mockLog = spyLog()
|
||||
var mockDB = {
|
||||
emailRecord: sinon.spy(function (email) {
|
||||
return P.reject(new error({}))
|
||||
})
|
||||
}
|
||||
var mockMsg = mockMessage({
|
||||
bounce: {
|
||||
bounceType: 'Permanent',
|
||||
bouncedRecipients: [
|
||||
{ emailAddress: 'test@example.com' },
|
||||
]
|
||||
}
|
||||
})
|
||||
return mockedBounces(mockLog, mockDB).handleBounce(mockMsg).then(function () {
|
||||
t.equal(mockDB.emailRecord.callCount, 1)
|
||||
t.equal(mockDB.emailRecord.args[0][0], 'test@example.com')
|
||||
t.equal(mockLog.messages.length, 3)
|
||||
t.equal(mockLog.messages[0].args[0].op, 'handleBounce')
|
||||
t.equal(mockLog.messages[0].args[0].email, 'test@example.com')
|
||||
t.equal(mockLog.messages[1].args[0], 'account.email_bounced')
|
||||
t.equal(mockLog.messages[2].args[0].op, 'databaseError')
|
||||
t.equal(mockLog.messages[2].args[0].email, 'test@example.com')
|
||||
t.equal(mockMsg.del.callCount, 1)
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'errors when deleting the email record are logged',
|
||||
function (t) {
|
||||
var mockLog = spyLog()
|
||||
var mockDB = {
|
||||
emailRecord: sinon.spy(function (email) {
|
||||
return P.resolve({
|
||||
uid: '123456',
|
||||
email: email,
|
||||
emailVerified: false
|
||||
})
|
||||
}),
|
||||
deleteAccount: sinon.spy(function (record) {
|
||||
return P.reject(new error.unknownAccount('test@example.com'))
|
||||
})
|
||||
}
|
||||
var mockMsg = mockMessage({
|
||||
bounce: {
|
||||
bounceType: 'Permanent',
|
||||
bouncedRecipients: [
|
||||
{ emailAddress: 'test@example.com' },
|
||||
]
|
||||
}
|
||||
})
|
||||
return mockedBounces(mockLog, mockDB).handleBounce(mockMsg).then(function () {
|
||||
t.equal(mockDB.emailRecord.callCount, 1)
|
||||
t.equal(mockDB.emailRecord.args[0][0], 'test@example.com')
|
||||
t.equal(mockDB.deleteAccount.callCount, 1)
|
||||
t.equal(mockDB.deleteAccount.args[0][0].email, 'test@example.com')
|
||||
t.equal(mockLog.messages.length, 3)
|
||||
t.equal(mockLog.messages[0].args[0].op, 'handleBounce')
|
||||
t.equal(mockLog.messages[0].args[0].email, 'test@example.com')
|
||||
t.equal(mockLog.messages[1].args[0], 'account.email_bounced')
|
||||
t.equal(mockLog.messages[2].args[0].op, 'databaseError')
|
||||
t.equal(mockLog.messages[2].args[0].email, 'test@example.com')
|
||||
t.equal(mockLog.messages[2].args[0].err.errno, error.ERRNO.ACCOUNT_UNKNOWN)
|
||||
t.equal(mockMsg.del.callCount, 1)
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'quoted email addresses are normalized for lookup',
|
||||
function (t) {
|
||||
var mockLog = spyLog()
|
||||
var mockDB = {
|
||||
emailRecord: sinon.spy(function (email) {
|
||||
// Lookup only succeeds when using original, unquoted email addr.
|
||||
if (email !== 'test.@example.com') {
|
||||
return P.reject(new error.unknownAccount(email))
|
||||
var mockMsg = mockMessage({
|
||||
bounce: {
|
||||
bounceType: 'Permanent',
|
||||
bouncedRecipients: [
|
||||
{ emailAddress: 'test@example.com' },
|
||||
{ emailAddress: 'foobar@example.com'}
|
||||
]
|
||||
}
|
||||
return P.resolve({
|
||||
uid: '123456',
|
||||
email: email,
|
||||
emailVerified: false
|
||||
})
|
||||
}),
|
||||
deleteAccount: sinon.spy(function (record) {
|
||||
return P.resolve({ })
|
||||
})
|
||||
return mockedBounces(mockLog, mockDB).handleBounce(mockMsg).then(function () {
|
||||
assert.equal(mockDB.emailRecord.callCount, 2)
|
||||
assert.equal(mockDB.deleteAccount.callCount, 2)
|
||||
assert.equal(mockDB.emailRecord.args[0][0], 'test@example.com')
|
||||
assert.equal(mockDB.emailRecord.args[1][0], 'foobar@example.com')
|
||||
assert.equal(mockLog.messages.length, 6, 'messages logged')
|
||||
assert.equal(mockLog.messages[1].level, 'increment')
|
||||
assert.equal(mockLog.messages[1].args[0], 'account.email_bounced')
|
||||
assert.equal(mockLog.messages[5].level, 'info')
|
||||
assert.equal(mockLog.messages[5].args[0].op, 'accountDeleted')
|
||||
assert.equal(mockLog.messages[5].args[0].email, 'foobar@example.com')
|
||||
assert.equal(mockMsg.del.callCount, 1)
|
||||
})
|
||||
}
|
||||
return mockedBounces(mockLog, mockDB).handleBounce(mockMessage({
|
||||
bounce: {
|
||||
bounceType: 'Permanent',
|
||||
bouncedRecipients: [
|
||||
// Bounce message has email addr in quoted form, since some
|
||||
// mail agents normalize it in this way.
|
||||
{ emailAddress: '"test."@example.com' },
|
||||
]
|
||||
}
|
||||
})).then(function () {
|
||||
t.equal(mockDB.emailRecord.callCount, 2)
|
||||
t.equal(mockDB.emailRecord.args[0][0], '"test."@example.com')
|
||||
t.equal(mockDB.emailRecord.args[1][0], 'test.@example.com')
|
||||
t.equal(mockDB.deleteAccount.callCount, 1)
|
||||
t.equal(mockDB.deleteAccount.args[0][0].email, 'test.@example.com')
|
||||
})
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
test(
|
||||
'can log email template name and bounceType',
|
||||
function (t) {
|
||||
var mockLog = spyLog()
|
||||
var mockDB = {
|
||||
emailRecord: sinon.spy(function (email) {
|
||||
return P.resolve({
|
||||
uid: '123456',
|
||||
email: email,
|
||||
emailVerified: false
|
||||
it(
|
||||
'should treat abuse complaints like bounces',
|
||||
() => {
|
||||
var mockLog = spyLog()
|
||||
var mockDB = {
|
||||
emailRecord: sinon.spy(function (email) {
|
||||
return P.resolve({
|
||||
uid: '123456',
|
||||
email: email,
|
||||
emailVerified: false
|
||||
})
|
||||
}),
|
||||
deleteAccount: sinon.spy(function (record) {
|
||||
return P.resolve({ })
|
||||
})
|
||||
}),
|
||||
deleteAccount: sinon.spy(function () {
|
||||
return P.resolve({ })
|
||||
}
|
||||
return mockedBounces(mockLog, mockDB).handleBounce(mockMessage({
|
||||
complaint: {
|
||||
complaintFeedbackType: 'abuse',
|
||||
complainedRecipients: [
|
||||
{ emailAddress: 'test@example.com' },
|
||||
{ emailAddress: 'foobar@example.com'}
|
||||
]
|
||||
}
|
||||
})).then(function () {
|
||||
assert.equal(mockDB.emailRecord.callCount, 2)
|
||||
assert.equal(mockDB.deleteAccount.callCount, 2)
|
||||
assert.equal(mockDB.emailRecord.args[0][0], 'test@example.com')
|
||||
assert.equal(mockDB.emailRecord.args[1][0], 'foobar@example.com')
|
||||
assert.equal(mockLog.messages.length, 6)
|
||||
})
|
||||
}
|
||||
var mockMsg = mockMessage({
|
||||
bounce: {
|
||||
bounceType: 'Permanent',
|
||||
bounceSubType: 'General',
|
||||
bouncedRecipients: [
|
||||
{emailAddress: 'test@example.com'}
|
||||
]
|
||||
},
|
||||
mail: {
|
||||
headers: [
|
||||
{
|
||||
name: 'X-Template-Name',
|
||||
value: 'verifyLoginEmail'
|
||||
)
|
||||
|
||||
it(
|
||||
'should not delete verified accounts on bounce',
|
||||
() => {
|
||||
var mockLog = spyLog()
|
||||
var mockDB = {
|
||||
emailRecord: sinon.spy(function (email) {
|
||||
return P.resolve({
|
||||
uid: '123456',
|
||||
email: email,
|
||||
emailVerified: (email === 'verified@example.com')
|
||||
})
|
||||
}),
|
||||
deleteAccount: sinon.spy(function (record) {
|
||||
return P.resolve({ })
|
||||
})
|
||||
}
|
||||
return mockedBounces(mockLog, mockDB).handleBounce(mockMessage({
|
||||
bounce: {
|
||||
bounceType: 'Permanent',
|
||||
// docs: http://docs.aws.amazon.com/ses/latest/DeveloperGuide/notification-contents.html#bounced-recipients
|
||||
bouncedRecipients: [
|
||||
{ emailAddress: 'test@example.com', action: 'failed', status: '5.0.0', diagnosticCode: 'smtp; 550 user unknown' },
|
||||
{ emailAddress: 'verified@example.com', status: '4.0.0' }
|
||||
]
|
||||
}
|
||||
})).then(function () {
|
||||
assert.equal(mockDB.emailRecord.callCount, 2)
|
||||
assert.equal(mockDB.emailRecord.args[0][0], 'test@example.com')
|
||||
assert.equal(mockDB.emailRecord.args[1][0], 'verified@example.com')
|
||||
assert.equal(mockDB.deleteAccount.callCount, 1)
|
||||
assert.equal(mockDB.deleteAccount.args[0][0].email, 'test@example.com')
|
||||
assert.equal(mockLog.messages.length, 6)
|
||||
assert.equal(mockLog.messages[0].args[0].op, 'handleBounce')
|
||||
assert.equal(mockLog.messages[0].args[0].email, 'test@example.com')
|
||||
assert.equal(mockLog.messages[0].args[0].status, '5.0.0')
|
||||
assert.equal(mockLog.messages[0].args[0].action, 'failed')
|
||||
assert.equal(mockLog.messages[0].args[0].diagnosticCode, 'smtp; 550 user unknown')
|
||||
assert.equal(mockLog.messages[1].args[0], 'account.email_bounced')
|
||||
assert.equal(mockLog.messages[2].args[0].op, 'accountDeleted')
|
||||
assert.equal(mockLog.messages[2].args[0].email, 'test@example.com')
|
||||
assert.equal(mockLog.messages[3].args[0].op, 'handleBounce')
|
||||
assert.equal(mockLog.messages[3].args[0].email, 'verified@example.com')
|
||||
assert.equal(mockLog.messages[3].args[0].status, '4.0.0')
|
||||
assert(!mockLog.messages[3].args[0].diagnosticCode)
|
||||
assert.equal(mockLog.messages[4].args[0], 'account.email_bounced')
|
||||
assert.equal(mockLog.messages[5].level, 'increment')
|
||||
assert.equal(mockLog.messages[5].args[0], 'account.email_bounced.already_verified')
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
it(
|
||||
'should log errors when looking up the email record',
|
||||
() => {
|
||||
var mockLog = spyLog()
|
||||
var mockDB = {
|
||||
emailRecord: sinon.spy(function (email) {
|
||||
return P.reject(new error({}))
|
||||
})
|
||||
}
|
||||
var mockMsg = mockMessage({
|
||||
bounce: {
|
||||
bounceType: 'Permanent',
|
||||
bouncedRecipients: [
|
||||
{ emailAddress: 'test@example.com' },
|
||||
]
|
||||
}
|
||||
})
|
||||
return mockedBounces(mockLog, mockDB).handleBounce(mockMsg).then(function () {
|
||||
assert.equal(mockDB.emailRecord.callCount, 1)
|
||||
assert.equal(mockDB.emailRecord.args[0][0], 'test@example.com')
|
||||
assert.equal(mockLog.messages.length, 3)
|
||||
assert.equal(mockLog.messages[0].args[0].op, 'handleBounce')
|
||||
assert.equal(mockLog.messages[0].args[0].email, 'test@example.com')
|
||||
assert.equal(mockLog.messages[1].args[0], 'account.email_bounced')
|
||||
assert.equal(mockLog.messages[2].args[0].op, 'databaseError')
|
||||
assert.equal(mockLog.messages[2].args[0].email, 'test@example.com')
|
||||
assert.equal(mockMsg.del.callCount, 1)
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
it(
|
||||
'should log errors when deleting the email record',
|
||||
() => {
|
||||
var mockLog = spyLog()
|
||||
var mockDB = {
|
||||
emailRecord: sinon.spy(function (email) {
|
||||
return P.resolve({
|
||||
uid: '123456',
|
||||
email: email,
|
||||
emailVerified: false
|
||||
})
|
||||
}),
|
||||
deleteAccount: sinon.spy(function (record) {
|
||||
return P.reject(new error.unknownAccount('test@example.com'))
|
||||
})
|
||||
}
|
||||
var mockMsg = mockMessage({
|
||||
bounce: {
|
||||
bounceType: 'Permanent',
|
||||
bouncedRecipients: [
|
||||
{ emailAddress: 'test@example.com' },
|
||||
]
|
||||
}
|
||||
})
|
||||
return mockedBounces(mockLog, mockDB).handleBounce(mockMsg).then(function () {
|
||||
assert.equal(mockDB.emailRecord.callCount, 1)
|
||||
assert.equal(mockDB.emailRecord.args[0][0], 'test@example.com')
|
||||
assert.equal(mockDB.deleteAccount.callCount, 1)
|
||||
assert.equal(mockDB.deleteAccount.args[0][0].email, 'test@example.com')
|
||||
assert.equal(mockLog.messages.length, 3)
|
||||
assert.equal(mockLog.messages[0].args[0].op, 'handleBounce')
|
||||
assert.equal(mockLog.messages[0].args[0].email, 'test@example.com')
|
||||
assert.equal(mockLog.messages[1].args[0], 'account.email_bounced')
|
||||
assert.equal(mockLog.messages[2].args[0].op, 'databaseError')
|
||||
assert.equal(mockLog.messages[2].args[0].email, 'test@example.com')
|
||||
assert.equal(mockLog.messages[2].args[0].err.errno, error.ERRNO.ACCOUNT_UNKNOWN)
|
||||
assert.equal(mockMsg.del.callCount, 1)
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
it(
|
||||
'should normalize quoted email addresses for lookup',
|
||||
() => {
|
||||
var mockLog = spyLog()
|
||||
var mockDB = {
|
||||
emailRecord: sinon.spy(function (email) {
|
||||
// Lookup only succeeds when using original, unquoted email addr.
|
||||
if (email !== 'test.@example.com') {
|
||||
return P.reject(new error.unknownAccount(email))
|
||||
}
|
||||
]
|
||||
return P.resolve({
|
||||
uid: '123456',
|
||||
email: email,
|
||||
emailVerified: false
|
||||
})
|
||||
}),
|
||||
deleteAccount: sinon.spy(function (record) {
|
||||
return P.resolve({ })
|
||||
})
|
||||
}
|
||||
})
|
||||
return mockedBounces(mockLog, mockDB).handleBounce(mockMessage({
|
||||
bounce: {
|
||||
bounceType: 'Permanent',
|
||||
bouncedRecipients: [
|
||||
// Bounce message has email addr in quoted form, since some
|
||||
// mail agents normalize it in this way.
|
||||
{ emailAddress: '"test."@example.com' },
|
||||
]
|
||||
}
|
||||
})).then(function () {
|
||||
assert.equal(mockDB.emailRecord.callCount, 2)
|
||||
assert.equal(mockDB.emailRecord.args[0][0], '"test."@example.com')
|
||||
assert.equal(mockDB.emailRecord.args[1][0], 'test.@example.com')
|
||||
assert.equal(mockDB.deleteAccount.callCount, 1)
|
||||
assert.equal(mockDB.deleteAccount.args[0][0].email, 'test.@example.com')
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
return mockedBounces(mockLog, mockDB).handleBounce(mockMsg).then(function () {
|
||||
t.equal(mockDB.emailRecord.callCount, 1)
|
||||
t.equal(mockDB.emailRecord.args[0][0], 'test@example.com')
|
||||
t.equal(mockDB.deleteAccount.callCount, 1)
|
||||
t.equal(mockDB.deleteAccount.args[0][0].email, 'test@example.com')
|
||||
t.equal(mockLog.messages.length, 3)
|
||||
t.equal(mockLog.messages[0].args[0].op, 'handleBounce')
|
||||
t.equal(mockLog.messages[0].args[0].email, 'test@example.com')
|
||||
t.equal(mockLog.messages[0].args[0].template, 'verifyLoginEmail')
|
||||
t.equal(mockLog.messages[0].args[0].bounceType, 'Permanent')
|
||||
t.equal(mockLog.messages[0].args[0].bounceSubType, 'General')
|
||||
t.equal(mockLog.messages[1].args[0], 'account.email_bounced')
|
||||
})
|
||||
}
|
||||
)
|
||||
it(
|
||||
'should log email template name and bounceType',
|
||||
() => {
|
||||
var mockLog = spyLog()
|
||||
var mockDB = {
|
||||
emailRecord: sinon.spy(function (email) {
|
||||
return P.resolve({
|
||||
uid: '123456',
|
||||
email: email,
|
||||
emailVerified: false
|
||||
})
|
||||
}),
|
||||
deleteAccount: sinon.spy(function () {
|
||||
return P.resolve({ })
|
||||
})
|
||||
}
|
||||
var mockMsg = mockMessage({
|
||||
bounce: {
|
||||
bounceType: 'Permanent',
|
||||
bounceSubType: 'General',
|
||||
bouncedRecipients: [
|
||||
{emailAddress: 'test@example.com'}
|
||||
]
|
||||
},
|
||||
mail: {
|
||||
headers: [
|
||||
{
|
||||
name: 'X-Template-Name',
|
||||
value: 'verifyLoginEmail'
|
||||
}
|
||||
]
|
||||
}
|
||||
})
|
||||
|
||||
return mockedBounces(mockLog, mockDB).handleBounce(mockMsg).then(function () {
|
||||
assert.equal(mockDB.emailRecord.callCount, 1)
|
||||
assert.equal(mockDB.emailRecord.args[0][0], 'test@example.com')
|
||||
assert.equal(mockDB.deleteAccount.callCount, 1)
|
||||
assert.equal(mockDB.deleteAccount.args[0][0].email, 'test@example.com')
|
||||
assert.equal(mockLog.messages.length, 3)
|
||||
assert.equal(mockLog.messages[0].args[0].op, 'handleBounce')
|
||||
assert.equal(mockLog.messages[0].args[0].email, 'test@example.com')
|
||||
assert.equal(mockLog.messages[0].args[0].template, 'verifyLoginEmail')
|
||||
assert.equal(mockLog.messages[0].args[0].bounceType, 'Permanent')
|
||||
assert.equal(mockLog.messages[0].args[0].bounceSubType, 'General')
|
||||
assert.equal(mockLog.messages[1].args[0], 'account.email_bounced')
|
||||
})
|
||||
}
|
||||
)
|
||||
})
|
||||
|
|
|
@ -2,100 +2,105 @@
|
|||
* 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/. */
|
||||
|
||||
var test = require('tap').test
|
||||
var butil = require('../../lib/crypto/butil')
|
||||
'use strict'
|
||||
|
||||
test(
|
||||
'buffersAreEqual returns false if lengths are different',
|
||||
function (t) {
|
||||
t.equal(butil.buffersAreEqual(Buffer(2), Buffer(4)), false)
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
const assert = require('assert')
|
||||
const butil = require('../../lib/crypto/butil')
|
||||
|
||||
test(
|
||||
'buffersAreEqual returns true if buffers have same bytes',
|
||||
function (t) {
|
||||
var b1 = Buffer('abcd', 'hex')
|
||||
var b2 = Buffer('abcd', 'hex')
|
||||
t.equal(butil.buffersAreEqual(b1, b2), true)
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
describe('butil', () => {
|
||||
|
||||
test(
|
||||
'xorBuffers throws an Error if lengths are different',
|
||||
function (t) {
|
||||
try {
|
||||
butil.xorBuffers(Buffer(2), Buffer(4))
|
||||
}
|
||||
catch (e) {
|
||||
return t.end()
|
||||
}
|
||||
t.fail('did not throw')
|
||||
}
|
||||
)
|
||||
describe('.buffersAreEqual', () => {
|
||||
|
||||
test(
|
||||
'xorBuffers works',
|
||||
function (t) {
|
||||
var b1 = Buffer('e5', 'hex')
|
||||
var b2 = Buffer('5e', 'hex')
|
||||
t.deepEqual(butil.xorBuffers(b1, b2), Buffer('bb', 'hex'))
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
it(
|
||||
'returns false if lengths are different',
|
||||
() => {
|
||||
assert.equal(butil.buffersAreEqual(Buffer(2), Buffer(4)), false)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'bufferize works',
|
||||
function (t) {
|
||||
var argument = { foo: 'bar', baz: 'f00d' }
|
||||
var result = butil.bufferize(argument)
|
||||
t.notEqual(result, argument)
|
||||
t.equal(Object.keys(result).length, Object.keys(argument).length)
|
||||
t.equal(typeof result.foo, 'string')
|
||||
t.equal(result.foo, argument.foo)
|
||||
t.ok(Buffer.isBuffer(result.baz))
|
||||
t.equal(result.baz.length, 2)
|
||||
t.equal(result.baz[0], 0xf0)
|
||||
t.equal(result.baz[1], 0x0d)
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
it(
|
||||
'returns true if buffers have same bytes',
|
||||
() => {
|
||||
const b1 = Buffer('abcd', 'hex')
|
||||
const b2 = Buffer('abcd', 'hex')
|
||||
assert.equal(butil.buffersAreEqual(b1, b2), true)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'bufferize works in-place',
|
||||
function (t) {
|
||||
var argument = { foo: 'beef', bar: 'baz' }
|
||||
var result = butil.bufferize(argument, { inplace: true })
|
||||
t.equal(result, argument)
|
||||
t.equal(Object.keys(result).length, 2)
|
||||
t.ok(Buffer.isBuffer(result.foo))
|
||||
t.equal(result.foo.length, 2)
|
||||
t.equal(result.foo[0], 0xbe)
|
||||
t.equal(result.foo[1], 0xef)
|
||||
t.equal(typeof result.bar, 'string')
|
||||
t.equal(result.bar, 'baz')
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
test(
|
||||
'bufferize ignores exceptions',
|
||||
function (t) {
|
||||
var argument = { foo: 'bar', baz: 'f00d', qux: 'beef' }
|
||||
var result = butil.bufferize(argument, { ignore: [ 'baz' ] })
|
||||
t.notEqual(argument, result)
|
||||
t.equal(Object.keys(result).length, Object.keys(argument).length)
|
||||
t.equal(typeof result.foo, 'string')
|
||||
t.equal(result.foo, argument.foo)
|
||||
t.equal(typeof result.baz, 'string')
|
||||
t.equal(result.baz, argument.baz)
|
||||
t.ok(Buffer.isBuffer(result.qux))
|
||||
t.equal(result.qux.length, 2)
|
||||
t.equal(result.qux[0], 0xbe)
|
||||
t.equal(result.qux[1], 0xef)
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
describe('.xorBuffers', () => {
|
||||
|
||||
it(
|
||||
'throws an Error if lengths are different',
|
||||
() => {
|
||||
assert.throws(() => {
|
||||
butil.xorBuffers(Buffer(2), Buffer(4))
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
it(
|
||||
'should return a Buffer with bits ORed',
|
||||
() => {
|
||||
const b1 = Buffer('e5', 'hex')
|
||||
const b2 = Buffer('5e', 'hex')
|
||||
assert.deepEqual(butil.xorBuffers(b1, b2), Buffer('bb', 'hex'))
|
||||
}
|
||||
)
|
||||
|
||||
})
|
||||
|
||||
describe('.bufferize', () => {
|
||||
it(
|
||||
'should bufferize hex-looking values',
|
||||
() => {
|
||||
const argument = { foo: 'bar', baz: 'f00d' }
|
||||
const result = butil.bufferize(argument)
|
||||
assert.notEqual(result, argument)
|
||||
assert.equal(Object.keys(result).length, Object.keys(argument).length)
|
||||
assert.equal(typeof result.foo, 'string')
|
||||
assert.equal(result.foo, argument.foo)
|
||||
assert.ok(Buffer.isBuffer(result.baz))
|
||||
assert.equal(result.baz.length, 2)
|
||||
assert.equal(result.baz[0], 0xf0)
|
||||
assert.equal(result.baz[1], 0x0d)
|
||||
}
|
||||
)
|
||||
|
||||
it(
|
||||
'should convert in-place',
|
||||
() => {
|
||||
const argument = { foo: 'beef', bar: 'baz' }
|
||||
const result = butil.bufferize(argument, { inplace: true })
|
||||
assert.equal(result, argument)
|
||||
assert.equal(Object.keys(result).length, 2)
|
||||
assert.ok(Buffer.isBuffer(result.foo))
|
||||
assert.equal(result.foo.length, 2)
|
||||
assert.equal(result.foo[0], 0xbe)
|
||||
assert.equal(result.foo[1], 0xef)
|
||||
assert.equal(typeof result.bar, 'string')
|
||||
assert.equal(result.bar, 'baz')
|
||||
}
|
||||
)
|
||||
|
||||
it(
|
||||
'should ignore exceptions',
|
||||
() => {
|
||||
const argument = { foo: 'bar', baz: 'f00d', qux: 'beef' }
|
||||
const result = butil.bufferize(argument, { ignore: [ 'baz' ] })
|
||||
assert.notEqual(argument, result)
|
||||
assert.equal(Object.keys(result).length, Object.keys(argument).length)
|
||||
assert.equal(typeof result.foo, 'string')
|
||||
assert.equal(result.foo, argument.foo)
|
||||
assert.equal(typeof result.baz, 'string')
|
||||
assert.equal(result.baz, argument.baz)
|
||||
assert.ok(Buffer.isBuffer(result.qux))
|
||||
assert.equal(result.qux.length, 2)
|
||||
assert.equal(result.qux[0], 0xbe)
|
||||
assert.equal(result.qux[1], 0xef)
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
})
|
||||
|
|
|
@ -2,12 +2,12 @@
|
|||
* 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/. */
|
||||
|
||||
var test = require('../ptaptest')
|
||||
const assert = require('insist')
|
||||
const log = {
|
||||
trace: () => {},
|
||||
activityEvent: () => {},
|
||||
flowEvent: () => {},
|
||||
error: console.error, // eslint-disable-line no-console
|
||||
error() {}
|
||||
}
|
||||
const mocks = require('../mocks')
|
||||
var error = require('../../lib/error.js')
|
||||
|
@ -27,434 +27,372 @@ var customsServer = nock(CUSTOMS_URL_REAL)
|
|||
'Content-Type': 'application/json'
|
||||
})
|
||||
|
||||
test(
|
||||
"can create a customs object with url as 'none'",
|
||||
function (t) {
|
||||
t.plan(7)
|
||||
describe('Customs', () => {
|
||||
it(
|
||||
"can create a customs object with url as 'none'",
|
||||
() => {
|
||||
customsNoUrl = new Customs('none')
|
||||
|
||||
customsNoUrl = new Customs('none')
|
||||
assert.ok(customsNoUrl, 'got a customs object with a none url')
|
||||
|
||||
t.ok(customsNoUrl, 'got a customs object with a none url')
|
||||
var request = newRequest()
|
||||
var ip = request.app.clientAddress
|
||||
var email = newEmail()
|
||||
var action = newAction()
|
||||
|
||||
var request = newRequest()
|
||||
var ip = request.app.clientAddress
|
||||
var email = newEmail()
|
||||
var action = newAction()
|
||||
|
||||
return customsNoUrl.check(request, email, action)
|
||||
.then(function(result) {
|
||||
t.equal(result, undefined, 'Nothing is returned when /check succeeds')
|
||||
t.pass('Passed /check (no url)')
|
||||
}, function(error) {
|
||||
t.fail('We should have failed open (no url provided) for /check')
|
||||
})
|
||||
.then(function() {
|
||||
return customsNoUrl.flag(ip, { email: email, uid: '12345' })
|
||||
})
|
||||
.then(function(result) {
|
||||
t.equal(result, undefined, 'Nothing is returned when /failedLoginAttempt succeeds')
|
||||
t.pass('Passed /failedLoginAttempt')
|
||||
}, function(error) {
|
||||
t.fail('We should have failed open for /failedLoginAttempt')
|
||||
})
|
||||
.then(function() {
|
||||
return customsNoUrl.reset(email)
|
||||
})
|
||||
.then(function(result) {
|
||||
t.equal(result, undefined, 'Nothing is returned when /passwordReset succeeds')
|
||||
t.pass('Passed /passwordReset')
|
||||
}, function(error) {
|
||||
t.fail('We should have failed open (no url provided) for /failedLoginAttempt')
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'can create a customs object with a url',
|
||||
function (t) {
|
||||
t.plan(29)
|
||||
|
||||
customsWithUrl = new Customs(CUSTOMS_URL_REAL)
|
||||
|
||||
t.ok(customsWithUrl, 'got a customs object with a valid url')
|
||||
|
||||
var request = newRequest()
|
||||
var ip = request.app.clientAddress
|
||||
var email = newEmail()
|
||||
var action = newAction()
|
||||
|
||||
// Mock a check that does not get blocked.
|
||||
customsServer.post('/check', function (body) {
|
||||
t.deepEqual(body, {
|
||||
ip: ip,
|
||||
email: email,
|
||||
action: action,
|
||||
headers: request.headers,
|
||||
query: request.query,
|
||||
payload: request.payload,
|
||||
}, 'first call to /check had expected request params')
|
||||
return true
|
||||
}).reply(200, {
|
||||
block: false,
|
||||
retryAfter: 0
|
||||
})
|
||||
return customsWithUrl.check(request, email, action)
|
||||
.then(function(result) {
|
||||
t.equal(result, undefined, 'Nothing is returned when /check succeeds')
|
||||
t.pass('Passed /check (with url)')
|
||||
}, function(error) {
|
||||
t.fail('We should not have failed here for /check : err=' + error)
|
||||
})
|
||||
.then(function() {
|
||||
// Mock a report of a failed login attempt
|
||||
customsServer.post('/failedLoginAttempt', function (body) {
|
||||
t.deepEqual(body, {
|
||||
ip: ip,
|
||||
email: email,
|
||||
errno: error.ERRNO.UNEXPECTED_ERROR
|
||||
}, 'first call to /failedLoginAttempt had expected request params')
|
||||
return true
|
||||
}).reply(200, {})
|
||||
return customsWithUrl.flag(ip, { email: email, uid: '12345' })
|
||||
})
|
||||
.then(function(result) {
|
||||
t.equal(result, undefined, 'Nothing is returned when /failedLoginAttempt succeeds')
|
||||
t.pass('Passed /failedLoginAttempt')
|
||||
}, function(error) {
|
||||
t.fail('We should not have failed here for /failedLoginAttempt : err=' + error)
|
||||
})
|
||||
.then(function() {
|
||||
// Mock a report of a password reset.
|
||||
customsServer.post('/passwordReset', function (body) {
|
||||
t.deepEqual(body, {
|
||||
email: email,
|
||||
}, 'first call to /passwordReset had expected request params')
|
||||
return true
|
||||
}).reply(200, {})
|
||||
return customsWithUrl.reset(email)
|
||||
})
|
||||
.then(function(result) {
|
||||
t.equal(result, undefined, 'Nothing is returned when /passwordReset succeeds')
|
||||
t.pass('Passed /passwordReset')
|
||||
}, function(error) {
|
||||
t.fail('We should not have failed here for /passwordReset : err=' + error)
|
||||
})
|
||||
.then(function() {
|
||||
// Mock a check that does get blocked, with a retryAfter.
|
||||
customsServer.post('/check', function (body) {
|
||||
t.deepEqual(body, {
|
||||
ip: ip,
|
||||
email: email,
|
||||
action: action,
|
||||
headers: request.headers,
|
||||
query: request.query,
|
||||
payload: request.payload,
|
||||
}, 'second call to /check had expected request params')
|
||||
return true
|
||||
}).reply(200, {
|
||||
block: true,
|
||||
retryAfter: 10001
|
||||
return customsNoUrl.check(request, email, action)
|
||||
.then(function(result) {
|
||||
assert.equal(result, undefined, 'Nothing is returned when /check succeeds')
|
||||
})
|
||||
return customsWithUrl.check(request, email, action)
|
||||
.then(function() {
|
||||
return customsNoUrl.flag(ip, { email: email, uid: '12345' })
|
||||
})
|
||||
.then(function(result) {
|
||||
assert.equal(result, undefined, 'Nothing is returned when /failedLoginAttempt succeeds')
|
||||
})
|
||||
.then(function() {
|
||||
return customsNoUrl.reset(email)
|
||||
})
|
||||
.then(function(result) {
|
||||
assert.equal(result, undefined, 'Nothing is returned when /passwordReset succeeds')
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
it(
|
||||
'can create a customs object with a url',
|
||||
() => {
|
||||
customsWithUrl = new Customs(CUSTOMS_URL_REAL)
|
||||
|
||||
assert.ok(customsWithUrl, 'got a customs object with a valid url')
|
||||
|
||||
var request = newRequest()
|
||||
var ip = request.app.clientAddress
|
||||
var email = newEmail()
|
||||
var action = newAction()
|
||||
|
||||
// Mock a check that does not get blocked.
|
||||
customsServer.post('/check', function (body) {
|
||||
assert.deepEqual(body, {
|
||||
ip: ip,
|
||||
email: email,
|
||||
action: action,
|
||||
headers: request.headers,
|
||||
query: request.query,
|
||||
payload: request.payload,
|
||||
}, 'first call to /check had expected request params')
|
||||
return true
|
||||
}).reply(200, {
|
||||
block: false,
|
||||
retryAfter: 0
|
||||
})
|
||||
.then(function(result) {
|
||||
t.fail('This should have failed the check since it should be blocked')
|
||||
}, function(err) {
|
||||
t.pass('Since we faked a block, we should have arrived here')
|
||||
t.equal(err.errno, error.ERRNO.THROTTLED, 'Error number is correct')
|
||||
t.equal(err.message, 'Client has sent too many requests', 'Error message is correct')
|
||||
t.ok(err.isBoom, 'The error causes a boom')
|
||||
t.equal(err.output.statusCode, 429, 'Status Code is correct')
|
||||
t.equal(err.output.payload.retryAfter, 10001, 'retryAfter is correct')
|
||||
t.equal(err.output.headers['retry-after'], 10001, 'retryAfter header is correct')
|
||||
})
|
||||
.then(function() {
|
||||
// Mock a report of a failed login attempt that does trigger lockout.
|
||||
customsServer.post('/failedLoginAttempt', function (body) {
|
||||
t.deepEqual(body, {
|
||||
ip: ip,
|
||||
return customsWithUrl.check(request, email, action)
|
||||
.then(function(result) {
|
||||
assert.equal(result, undefined, 'Nothing is returned when /check succeeds')
|
||||
})
|
||||
.then(function() {
|
||||
// Mock a report of a failed login attempt
|
||||
customsServer.post('/failedLoginAttempt', function (body) {
|
||||
assert.deepEqual(body, {
|
||||
ip: ip,
|
||||
email: email,
|
||||
errno: error.ERRNO.UNEXPECTED_ERROR
|
||||
}, 'first call to /failedLoginAttempt had expected request params')
|
||||
return true
|
||||
}).reply(200, {})
|
||||
return customsWithUrl.flag(ip, { email: email, uid: '12345' })
|
||||
})
|
||||
.then(function(result) {
|
||||
assert.equal(result, undefined, 'Nothing is returned when /failedLoginAttempt succeeds')
|
||||
})
|
||||
.then(function() {
|
||||
// Mock a report of a password reset.
|
||||
customsServer.post('/passwordReset', function (body) {
|
||||
assert.deepEqual(body, {
|
||||
email: email,
|
||||
}, 'first call to /passwordReset had expected request params')
|
||||
return true
|
||||
}).reply(200, {})
|
||||
return customsWithUrl.reset(email)
|
||||
})
|
||||
.then(function(result) {
|
||||
assert.equal(result, undefined, 'Nothing is returned when /passwordReset succeeds')
|
||||
})
|
||||
.then(function() {
|
||||
// Mock a check that does get blocked, with a retryAfter.
|
||||
customsServer.post('/check', function (body) {
|
||||
assert.deepEqual(body, {
|
||||
ip: ip,
|
||||
email: email,
|
||||
action: action,
|
||||
headers: request.headers,
|
||||
query: request.query,
|
||||
payload: request.payload,
|
||||
}, 'second call to /check had expected request params')
|
||||
return true
|
||||
}).reply(200, {
|
||||
block: true,
|
||||
retryAfter: 10001
|
||||
})
|
||||
return customsWithUrl.check(request, email, action)
|
||||
})
|
||||
.then(function(result) {
|
||||
assert(false, 'This should have failed the check since it should be blocked')
|
||||
}, function(err) {
|
||||
assert.equal(err.errno, error.ERRNO.THROTTLED, 'Error number is correct')
|
||||
assert.equal(err.message, 'Client has sent too many requests', 'Error message is correct')
|
||||
assert.ok(err.isBoom, 'The error causes a boom')
|
||||
assert.equal(err.output.statusCode, 429, 'Status Code is correct')
|
||||
assert.equal(err.output.payload.retryAfter, 10001, 'retryAfter is correct')
|
||||
assert.equal(err.output.headers['retry-after'], 10001, 'retryAfter header is correct')
|
||||
})
|
||||
.then(function() {
|
||||
// Mock a report of a failed login attempt that does trigger lockout.
|
||||
customsServer.post('/failedLoginAttempt', function (body) {
|
||||
assert.deepEqual(body, {
|
||||
ip: ip,
|
||||
email: email,
|
||||
errno: error.ERRNO.INCORRECT_PASSWORD
|
||||
}, 'second call to /failedLoginAttempt had expected request params')
|
||||
return true
|
||||
}).reply(200, { })
|
||||
return customsWithUrl.flag(ip, {
|
||||
email: email,
|
||||
errno: error.ERRNO.INCORRECT_PASSWORD
|
||||
}, 'second call to /failedLoginAttempt had expected request params')
|
||||
return true
|
||||
}).reply(200, { })
|
||||
return customsWithUrl.flag(ip, {
|
||||
})
|
||||
})
|
||||
.then(function(result) {
|
||||
assert.equal(result, undefined, 'Nothing is returned when /failedLoginAttempt succeeds')
|
||||
})
|
||||
.then(function() {
|
||||
// Mock a check that does get blocked, with no retryAfter.
|
||||
request.headers['user-agent'] = 'test passing through headers'
|
||||
request.payload['foo'] = 'bar'
|
||||
customsServer.post('/check', function (body) {
|
||||
assert.deepEqual(body, {
|
||||
ip: ip,
|
||||
email: email,
|
||||
action: action,
|
||||
headers: request.headers,
|
||||
query: request.query,
|
||||
payload: request.payload,
|
||||
}, 'third call to /check had expected request params')
|
||||
return true
|
||||
}).reply(200, {
|
||||
block: true
|
||||
})
|
||||
return customsWithUrl.check(request, email, action)
|
||||
})
|
||||
.then(function(result) {
|
||||
assert(false, 'This should have failed the check since it should be blocked')
|
||||
}, function(err) {
|
||||
assert.equal(err.errno, error.ERRNO.REQUEST_BLOCKED, 'Error number is correct')
|
||||
assert.equal(err.message, 'The request was blocked for security reasons', 'Error message is correct')
|
||||
assert.ok(err.isBoom, 'The error causes a boom')
|
||||
assert.equal(err.output.statusCode, 400, 'Status Code is correct')
|
||||
assert(!err.output.payload.retryAfter, 'retryAfter field is not present')
|
||||
assert(!err.output.headers['retry-after'], 'retryAfter header is not present')
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
it(
|
||||
'can create a customs object with non-existant customs service',
|
||||
() => {
|
||||
customsInvalidUrl = new Customs(CUSTOMS_URL_MISSING)
|
||||
|
||||
assert.ok(customsInvalidUrl, 'got a customs object with a non-existant service url')
|
||||
|
||||
var request = newRequest()
|
||||
var ip = request.app.clientAddress
|
||||
var email = newEmail()
|
||||
var action = newAction()
|
||||
|
||||
return customsInvalidUrl.check(request, email, action)
|
||||
.then(function(result) {
|
||||
assert.equal(result, undefined, 'Nothing is returned when /check succeeds even when service is non-existant')
|
||||
})
|
||||
.then(function() {
|
||||
return customsInvalidUrl.flag(ip, { email: email, uid: '12345' })
|
||||
})
|
||||
.then(function(result) {
|
||||
assert.equal(result, undefined, 'Nothing is returned when /failedLoginAttempt succeeds')
|
||||
})
|
||||
.then(function() {
|
||||
return customsInvalidUrl.reset(email)
|
||||
})
|
||||
.then(function(result) {
|
||||
assert.equal(result, undefined, 'Nothing is returned when /passwordReset succeeds')
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
it(
|
||||
'can rate limit checkAccountStatus /check',
|
||||
() => {
|
||||
customsWithUrl = new Customs(CUSTOMS_URL_REAL)
|
||||
|
||||
assert.ok(customsWithUrl, 'can rate limit checkAccountStatus /check')
|
||||
|
||||
var request = newRequest()
|
||||
var ip = request.app.clientAddress
|
||||
var email = newEmail()
|
||||
var action = 'accountStatusCheck'
|
||||
|
||||
function checkRequestBody (body) {
|
||||
assert.deepEqual(body, {
|
||||
ip: ip,
|
||||
email: email,
|
||||
errno: error.ERRNO.INCORRECT_PASSWORD
|
||||
action: action,
|
||||
headers: request.headers,
|
||||
query: request.query,
|
||||
payload: request.payload,
|
||||
}, 'call to /check had expected request params')
|
||||
return true
|
||||
}
|
||||
|
||||
customsServer
|
||||
.post('/check', checkRequestBody).reply(200, '{"block":false,"retryAfter":0}')
|
||||
.post('/check', checkRequestBody).reply(200, '{"block":false,"retryAfter":0}')
|
||||
.post('/check', checkRequestBody).reply(200, '{"block":false,"retryAfter":0}')
|
||||
.post('/check', checkRequestBody).reply(200, '{"block":false,"retryAfter":0}')
|
||||
.post('/check', checkRequestBody).reply(200, '{"block":false,"retryAfter":0}')
|
||||
.post('/check', checkRequestBody).reply(200, '{"block":true,"retryAfter":10001}')
|
||||
|
||||
return customsWithUrl.check(request, email, action)
|
||||
.then(function(result) {
|
||||
assert.equal(result, undefined, 'Nothing is returned when /check succeeds - 1')
|
||||
return customsWithUrl.check(request, email, action)
|
||||
})
|
||||
})
|
||||
.then(function(result) {
|
||||
t.equal(result, undefined, 'Nothing is returned when /failedLoginAttempt succeeds')
|
||||
t.pass('Passed /failedLoginAttempt')
|
||||
}, function(error) {
|
||||
t.fail('We should not have failed here for /failedLoginAttempt : err=' + error)
|
||||
})
|
||||
.then(function() {
|
||||
// Mock a check that does get blocked, with no retryAfter.
|
||||
request.headers['user-agent'] = 'test passing through headers'
|
||||
request.payload['foo'] = 'bar'
|
||||
customsServer.post('/check', function (body) {
|
||||
t.deepEqual(body, {
|
||||
ip: ip,
|
||||
email: email,
|
||||
action: action,
|
||||
headers: request.headers,
|
||||
query: request.query,
|
||||
payload: request.payload,
|
||||
}, 'third call to /check had expected request params')
|
||||
return true
|
||||
}).reply(200, {
|
||||
block: true
|
||||
.then(function(result) {
|
||||
assert.equal(result, undefined, 'Nothing is returned when /check succeeds - 2')
|
||||
return customsWithUrl.check(request, email, action)
|
||||
})
|
||||
.then(function(result) {
|
||||
assert.equal(result, undefined, 'Nothing is returned when /check succeeds - 3')
|
||||
return customsWithUrl.check(request, email, action)
|
||||
})
|
||||
.then(function(result) {
|
||||
assert.equal(result, undefined, 'Nothing is returned when /check succeeds - 4')
|
||||
return customsWithUrl.check(request, email, action)
|
||||
})
|
||||
.then(function() {
|
||||
// request is blocked
|
||||
return customsWithUrl.check(request, email, action)
|
||||
})
|
||||
.then(function() {
|
||||
assert(false, 'This should have failed the check since it should be blocked')
|
||||
}, function(error) {
|
||||
assert.equal(error.errno, 114, 'Error number is correct')
|
||||
assert.equal(error.message, 'Client has sent too many requests', 'Error message is correct')
|
||||
assert.ok(error.isBoom, 'The error causes a boom')
|
||||
assert.equal(error.output.statusCode, 429, 'Status Code is correct')
|
||||
assert.equal(error.output.payload.retryAfter, 10001, 'retryAfter is correct')
|
||||
assert.equal(error.output.payload.retryAfterLocalized, 'in 3 hours', 'retryAfterLocalized is correct')
|
||||
assert.equal(error.output.headers['retry-after'], 10001, 'retryAfter header is correct')
|
||||
})
|
||||
return customsWithUrl.check(request, email, action)
|
||||
})
|
||||
.then(function(result) {
|
||||
t.fail('This should have failed the check since it should be blocked')
|
||||
}, function(err) {
|
||||
t.pass('Since we faked a block, we should have arrived here')
|
||||
t.equal(err.errno, error.ERRNO.REQUEST_BLOCKED, 'Error number is correct')
|
||||
t.equal(err.message, 'The request was blocked for security reasons', 'Error message is correct')
|
||||
t.ok(err.isBoom, 'The error causes a boom')
|
||||
t.equal(err.output.statusCode, 400, 'Status Code is correct')
|
||||
t.notOk(err.output.payload.retryAfter, 'retryAfter field is not present')
|
||||
t.notOk(err.output.headers['retry-after'], 'retryAfter header is not present')
|
||||
})
|
||||
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'can create a customs object with non-existant customs service',
|
||||
function (t) {
|
||||
t.plan(7)
|
||||
|
||||
customsInvalidUrl = new Customs(CUSTOMS_URL_MISSING)
|
||||
|
||||
t.ok(customsInvalidUrl, 'got a customs object with a non-existant service url')
|
||||
|
||||
var request = newRequest()
|
||||
var ip = request.app.clientAddress
|
||||
var email = newEmail()
|
||||
var action = newAction()
|
||||
|
||||
return customsInvalidUrl.check(request, email, action)
|
||||
.then(function(result) {
|
||||
t.equal(result, undefined, 'Nothing is returned when /check succeeds even when service is non-existant')
|
||||
t.pass('Passed /check (no url)')
|
||||
}, function(error) {
|
||||
t.fail('We should have failed open (non-existant service url provided) for /check')
|
||||
})
|
||||
.then(function() {
|
||||
return customsInvalidUrl.flag(ip, { email: email, uid: '12345' })
|
||||
})
|
||||
.then(function(result) {
|
||||
t.equal(result, undefined, 'Nothing is returned when /failedLoginAttempt succeeds')
|
||||
t.pass('Passed /failedLoginAttempt')
|
||||
}, function(error) {
|
||||
t.fail('We should have failed open (no url provided) for /failedLoginAttempt')
|
||||
})
|
||||
.then(function() {
|
||||
return customsInvalidUrl.reset(email)
|
||||
})
|
||||
.then(function(result) {
|
||||
t.equal(result, undefined, 'Nothing is returned when /passwordReset succeeds')
|
||||
t.pass('Passed /passwordReset')
|
||||
}, function(error) {
|
||||
t.fail('We should have failed open (no url provided) for /failedLoginAttempt')
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'can rate limit checkAccountStatus /check',
|
||||
function (t) {
|
||||
t.plan(19)
|
||||
|
||||
customsWithUrl = new Customs(CUSTOMS_URL_REAL)
|
||||
|
||||
t.ok(customsWithUrl, 'can rate limit checkAccountStatus /check')
|
||||
|
||||
var request = newRequest()
|
||||
var ip = request.app.clientAddress
|
||||
var email = newEmail()
|
||||
var action = 'accountStatusCheck'
|
||||
|
||||
function checkRequestBody (body) {
|
||||
t.deepEqual(body, {
|
||||
ip: ip,
|
||||
email: email,
|
||||
action: action,
|
||||
headers: request.headers,
|
||||
query: request.query,
|
||||
payload: request.payload,
|
||||
}, 'call to /check had expected request params')
|
||||
return true
|
||||
}
|
||||
)
|
||||
|
||||
customsServer
|
||||
.post('/check', checkRequestBody).reply(200, '{"block":false,"retryAfter":0}')
|
||||
.post('/check', checkRequestBody).reply(200, '{"block":false,"retryAfter":0}')
|
||||
.post('/check', checkRequestBody).reply(200, '{"block":false,"retryAfter":0}')
|
||||
.post('/check', checkRequestBody).reply(200, '{"block":false,"retryAfter":0}')
|
||||
.post('/check', checkRequestBody).reply(200, '{"block":false,"retryAfter":0}')
|
||||
.post('/check', checkRequestBody).reply(200, '{"block":true,"retryAfter":10001}')
|
||||
it(
|
||||
'can rate limit devicesNotify /checkAuthenticated',
|
||||
() => {
|
||||
customsWithUrl = new Customs(CUSTOMS_URL_REAL)
|
||||
|
||||
return customsWithUrl.check(request, email, action)
|
||||
.then(function(result) {
|
||||
t.equal(result, undefined, 'Nothing is returned when /check succeeds - 1')
|
||||
return customsWithUrl.check(request, email, action)
|
||||
}, function(error) {
|
||||
t.fail('We should not have failed here for /check : err=' + error)
|
||||
})
|
||||
.then(function(result) {
|
||||
t.equal(result, undefined, 'Nothing is returned when /check succeeds - 2')
|
||||
return customsWithUrl.check(request, email, action)
|
||||
}, function(error) {
|
||||
t.fail('We should not have failed here for /check : err=' + error)
|
||||
})
|
||||
.then(function(result) {
|
||||
t.equal(result, undefined, 'Nothing is returned when /check succeeds - 3')
|
||||
return customsWithUrl.check(request, email, action)
|
||||
}, function(error) {
|
||||
t.fail('We should not have failed here for /check : err=' + error)
|
||||
})
|
||||
.then(function(result) {
|
||||
t.equal(result, undefined, 'Nothing is returned when /check succeeds - 4')
|
||||
return customsWithUrl.check(request, email, action)
|
||||
}, function(error) {
|
||||
t.fail('We should not have failed here for /check : err=' + error)
|
||||
})
|
||||
.then(function() {
|
||||
// request is blocked
|
||||
return customsWithUrl.check(request, email, action)
|
||||
})
|
||||
.then(function() {
|
||||
t.fail('This should have failed the check since it should be blocked')
|
||||
}, function(error) {
|
||||
t.pass('Since we faked a block, we should have arrived here')
|
||||
t.equal(error.errno, 114, 'Error number is correct')
|
||||
t.equal(error.message, 'Client has sent too many requests', 'Error message is correct')
|
||||
t.ok(error.isBoom, 'The error causes a boom')
|
||||
t.equal(error.output.statusCode, 429, 'Status Code is correct')
|
||||
t.equal(error.output.payload.retryAfter, 10001, 'retryAfter is correct')
|
||||
t.equal(error.output.payload.retryAfterLocalized, 'in 3 hours', 'retryAfterLocalized is correct')
|
||||
t.equal(error.output.headers['retry-after'], 10001, 'retryAfter header is correct')
|
||||
})
|
||||
}
|
||||
)
|
||||
assert.ok(customsWithUrl, 'can rate limit /checkAuthenticated')
|
||||
|
||||
test(
|
||||
'can rate limit devicesNotify /checkAuthenticated',
|
||||
function (t) {
|
||||
t.plan(18)
|
||||
var request = newRequest()
|
||||
var action = 'devicesNotify'
|
||||
var ip = request.app.clientAddress
|
||||
var uid = 'foo'
|
||||
|
||||
customsWithUrl = new Customs(CUSTOMS_URL_REAL)
|
||||
function checkRequestBody (body) {
|
||||
assert.deepEqual(body, {
|
||||
action: action,
|
||||
ip: ip,
|
||||
uid: uid,
|
||||
}, 'call to /checkAuthenticated had expected request params')
|
||||
return true
|
||||
}
|
||||
|
||||
t.ok(customsWithUrl, 'can rate limit /checkAuthenticated')
|
||||
customsServer
|
||||
.post('/checkAuthenticated', checkRequestBody).reply(200, '{"block":false,"retryAfter":0}')
|
||||
.post('/checkAuthenticated', checkRequestBody).reply(200, '{"block":false,"retryAfter":0}')
|
||||
.post('/checkAuthenticated', checkRequestBody).reply(200, '{"block":false,"retryAfter":0}')
|
||||
.post('/checkAuthenticated', checkRequestBody).reply(200, '{"block":false,"retryAfter":0}')
|
||||
.post('/checkAuthenticated', checkRequestBody).reply(200, '{"block":false,"retryAfter":0}')
|
||||
.post('/checkAuthenticated', checkRequestBody).reply(200, '{"block":true,"retryAfter":10001}')
|
||||
|
||||
var request = newRequest()
|
||||
var action = 'devicesNotify'
|
||||
var ip = request.app.clientAddress
|
||||
var uid = 'foo'
|
||||
|
||||
function checkRequestBody (body) {
|
||||
t.deepEqual(body, {
|
||||
action: action,
|
||||
ip: ip,
|
||||
uid: uid,
|
||||
}, 'call to /checkAuthenticated had expected request params')
|
||||
return true
|
||||
return customsWithUrl.checkAuthenticated(action, ip, uid)
|
||||
.then(function(result) {
|
||||
assert.equal(result, undefined, 'Nothing is returned when /checkAuthenticated succeeds - 1')
|
||||
return customsWithUrl.checkAuthenticated(action, ip, uid)
|
||||
})
|
||||
.then(function(result) {
|
||||
assert.equal(result, undefined, 'Nothing is returned when /checkAuthenticated succeeds - 2')
|
||||
return customsWithUrl.checkAuthenticated(action, ip, uid)
|
||||
})
|
||||
.then(function(result) {
|
||||
assert.equal(result, undefined, 'Nothing is returned when /checkAuthenticated succeeds - 3')
|
||||
return customsWithUrl.checkAuthenticated(action, ip, uid)
|
||||
})
|
||||
.then(function(result) {
|
||||
assert.equal(result, undefined, 'Nothing is returned when /checkAuthenticated succeeds - 4')
|
||||
return customsWithUrl.checkAuthenticated(action, ip, uid)
|
||||
})
|
||||
.then(function() {
|
||||
// request is blocked
|
||||
return customsWithUrl.checkAuthenticated(action, ip, uid)
|
||||
})
|
||||
.then(function() {
|
||||
assert(false, 'This should have failed the check since it should be blocked')
|
||||
}, function(error) {
|
||||
assert.equal(error.errno, 114, 'Error number is correct')
|
||||
assert.equal(error.message, 'Client has sent too many requests', 'Error message is correct')
|
||||
assert.ok(error.isBoom, 'The error causes a boom')
|
||||
assert.equal(error.output.statusCode, 429, 'Status Code is correct')
|
||||
assert.equal(error.output.payload.retryAfter, 10001, 'retryAfter is correct')
|
||||
assert.equal(error.output.headers['retry-after'], 10001, 'retryAfter header is correct')
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
customsServer
|
||||
.post('/checkAuthenticated', checkRequestBody).reply(200, '{"block":false,"retryAfter":0}')
|
||||
.post('/checkAuthenticated', checkRequestBody).reply(200, '{"block":false,"retryAfter":0}')
|
||||
.post('/checkAuthenticated', checkRequestBody).reply(200, '{"block":false,"retryAfter":0}')
|
||||
.post('/checkAuthenticated', checkRequestBody).reply(200, '{"block":false,"retryAfter":0}')
|
||||
.post('/checkAuthenticated', checkRequestBody).reply(200, '{"block":false,"retryAfter":0}')
|
||||
.post('/checkAuthenticated', checkRequestBody).reply(200, '{"block":true,"retryAfter":10001}')
|
||||
it(
|
||||
'can scrub customs request object',
|
||||
() => {
|
||||
customsWithUrl = new Customs(CUSTOMS_URL_REAL)
|
||||
|
||||
return customsWithUrl.checkAuthenticated(action, ip, uid)
|
||||
.then(function(result) {
|
||||
t.equal(result, undefined, 'Nothing is returned when /checkAuthenticated succeeds - 1')
|
||||
return customsWithUrl.checkAuthenticated(action, ip, uid)
|
||||
}, function(error) {
|
||||
t.fail('We should not have failed here for /checkAuthenticated : err=' + error)
|
||||
assert.ok(customsWithUrl, 'got a customs object with a valid url')
|
||||
|
||||
var request = newRequest()
|
||||
request.payload.authPW = 'asdfasdfadsf'
|
||||
var ip = request.app.clientAddress
|
||||
var email = newEmail()
|
||||
var action = newAction()
|
||||
|
||||
customsServer.post('/check', function (body) {
|
||||
assert.deepEqual(body, {
|
||||
ip: ip,
|
||||
email: email,
|
||||
action: action,
|
||||
headers: request.headers,
|
||||
query: request.query,
|
||||
payload: {}
|
||||
}, 'should not have authPW in payload')
|
||||
return true
|
||||
}).reply(200, {
|
||||
block: false,
|
||||
retryAfter: 0
|
||||
})
|
||||
.then(function(result) {
|
||||
t.equal(result, undefined, 'Nothing is returned when /checkAuthenticated succeeds - 2')
|
||||
return customsWithUrl.checkAuthenticated(action, ip, uid)
|
||||
}, function(error) {
|
||||
t.fail('We should not have failed here for /checkAuthenticated : err=' + error)
|
||||
})
|
||||
.then(function(result) {
|
||||
t.equal(result, undefined, 'Nothing is returned when /checkAuthenticated succeeds - 3')
|
||||
return customsWithUrl.checkAuthenticated(action, ip, uid)
|
||||
}, function(error) {
|
||||
t.fail('We should not have failed here for /checkAuthenticated : err=' + error)
|
||||
})
|
||||
.then(function(result) {
|
||||
t.equal(result, undefined, 'Nothing is returned when /checkAuthenticated succeeds - 4')
|
||||
return customsWithUrl.checkAuthenticated(action, ip, uid)
|
||||
}, function(error) {
|
||||
t.fail('We should not have failed here for /checkAuthenticated : err=' + error)
|
||||
})
|
||||
.then(function() {
|
||||
// request is blocked
|
||||
return customsWithUrl.checkAuthenticated(action, ip, uid)
|
||||
})
|
||||
.then(function() {
|
||||
t.fail('This should have failed the check since it should be blocked')
|
||||
}, function(error) {
|
||||
t.pass('Since we faked a block, we should have arrived here')
|
||||
t.equal(error.errno, 114, 'Error number is correct')
|
||||
t.equal(error.message, 'Client has sent too many requests', 'Error message is correct')
|
||||
t.ok(error.isBoom, 'The error causes a boom')
|
||||
t.equal(error.output.statusCode, 429, 'Status Code is correct')
|
||||
t.equal(error.output.payload.retryAfter, 10001, 'retryAfter is correct')
|
||||
t.equal(error.output.headers['retry-after'], 10001, 'retryAfter header is correct')
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'can scrub customs request object',
|
||||
function (t) {
|
||||
t.plan(3)
|
||||
return customsWithUrl.check(request, email, action)
|
||||
.then(function (result) {
|
||||
assert.equal(result, undefined, 'nothing is returned when /check succeeds - 1')
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
customsWithUrl = new Customs(CUSTOMS_URL_REAL)
|
||||
|
||||
t.ok(customsWithUrl, 'got a customs object with a valid url')
|
||||
|
||||
var request = newRequest()
|
||||
request.payload.authPW = 'asdfasdfadsf'
|
||||
var ip = request.app.clientAddress
|
||||
var email = newEmail()
|
||||
var action = newAction()
|
||||
|
||||
customsServer.post('/check', function (body) {
|
||||
t.deepEqual(body, {
|
||||
ip: ip,
|
||||
email: email,
|
||||
action: action,
|
||||
headers: request.headers,
|
||||
query: request.query,
|
||||
payload: {}
|
||||
}, 'should not have authPW in payload')
|
||||
return true
|
||||
}).reply(200, {
|
||||
block: false,
|
||||
retryAfter: 0
|
||||
})
|
||||
|
||||
return customsWithUrl.check(request, email, action)
|
||||
.then(function (result) {
|
||||
t.equal(result, undefined, 'nothing is returned when /check succeeds - 1')
|
||||
}, function (error) {
|
||||
t.fail('should not have failed here for /check : err=' + error)
|
||||
})
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
function newEmail() {
|
||||
return Math.random().toString().substr(2) + '@example.com'
|
||||
|
@ -489,3 +427,4 @@ function newAction() {
|
|||
|
||||
return EMAIL_ACTIONS[Math.floor(Math.random() * EMAIL_ACTIONS.length)]
|
||||
}
|
||||
|
||||
|
|
|
@ -4,20 +4,20 @@
|
|||
|
||||
'use strict'
|
||||
|
||||
const assert = require('insist')
|
||||
var uuid = require('uuid')
|
||||
var crypto = require('crypto')
|
||||
var test = require('../ptaptest')
|
||||
var mocks = require('../mocks')
|
||||
|
||||
var modulePath = '../../lib/devices'
|
||||
|
||||
test('require', function (t) {
|
||||
t.plan(3)
|
||||
t.equal(typeof require(modulePath), 'function', 'require returns function')
|
||||
t.equal(require(modulePath).length, 3, 'returned function expects three arguments')
|
||||
describe('devices', () => {
|
||||
it('should be an exported function', () => {
|
||||
assert.equal(typeof require(modulePath), 'function', 'require returns function')
|
||||
assert.equal(require(modulePath).length, 3, 'returned function expects three arguments')
|
||||
})
|
||||
|
||||
t.test('instantiate', function (t) {
|
||||
t.plan(8)
|
||||
describe('instance', () => {
|
||||
var log = mocks.spyLog()
|
||||
var deviceCreatedAt = Date.now()
|
||||
var deviceId = crypto.randomBytes(16)
|
||||
|
@ -33,17 +33,20 @@ test('require', function (t) {
|
|||
var push = mocks.mockPush()
|
||||
var devices = require(modulePath)(log, db, push)
|
||||
|
||||
t.equal(typeof devices, 'object', 'devices is object')
|
||||
t.equal(Object.keys(devices).length, 2, 'devices has two properties')
|
||||
it('should instantiate', () => {
|
||||
|
||||
t.equal(typeof devices.upsert, 'function', 'devices has upsert method')
|
||||
t.equal(devices.upsert.length, 3, 'devices.upsert expects three arguments')
|
||||
assert.equal(typeof devices, 'object', 'devices is object')
|
||||
assert.equal(Object.keys(devices).length, 2, 'devices has two properties')
|
||||
|
||||
t.equal(typeof devices.synthesizeName, 'function', 'devices has synthesizeName method')
|
||||
t.equal(devices.synthesizeName.length, 1, 'devices.synthesizeName expects 1 argument')
|
||||
assert.equal(typeof devices.upsert, 'function', 'devices has upsert method')
|
||||
assert.equal(devices.upsert.length, 3, 'devices.upsert expects three arguments')
|
||||
|
||||
t.test('devices.upsert', function (t) {
|
||||
t.plan(3)
|
||||
assert.equal(typeof devices.synthesizeName, 'function', 'devices has synthesizeName method')
|
||||
assert.equal(devices.synthesizeName.length, 1, 'devices.synthesizeName expects 1 argument')
|
||||
|
||||
})
|
||||
|
||||
describe('.upsert', () => {
|
||||
const request = mocks.mockRequest({
|
||||
log: log
|
||||
})
|
||||
|
@ -52,44 +55,44 @@ test('require', function (t) {
|
|||
uid: uuid.v4('binary')
|
||||
}
|
||||
|
||||
t.test('create', function (t) {
|
||||
it('should create', () => {
|
||||
return devices.upsert(request, sessionToken, device)
|
||||
.then(function (result) {
|
||||
t.deepEqual(result, {
|
||||
assert.deepEqual(result, {
|
||||
id: deviceId,
|
||||
name: device.name,
|
||||
type: device.type,
|
||||
createdAt: deviceCreatedAt
|
||||
}, 'result was correct')
|
||||
|
||||
t.equal(db.updateDevice.callCount, 0, 'db.updateDevice was not called')
|
||||
assert.equal(db.updateDevice.callCount, 0, 'db.updateDevice was not called')
|
||||
|
||||
t.equal(db.createDevice.callCount, 1, 'db.createDevice was called once')
|
||||
assert.equal(db.createDevice.callCount, 1, 'db.createDevice was called once')
|
||||
var args = db.createDevice.args[0]
|
||||
t.equal(args.length, 3, 'db.createDevice was passed three arguments')
|
||||
t.deepEqual(args[0], sessionToken.uid, 'first argument was uid')
|
||||
t.deepEqual(args[1], sessionToken.tokenId, 'second argument was sessionTokenId')
|
||||
t.equal(args[2], device, 'third argument was device')
|
||||
assert.equal(args.length, 3, 'db.createDevice was passed three arguments')
|
||||
assert.deepEqual(args[0], sessionToken.uid, 'first argument was uid')
|
||||
assert.deepEqual(args[1], sessionToken.tokenId, 'second argument was sessionTokenId')
|
||||
assert.equal(args[2], device, 'third argument was device')
|
||||
|
||||
t.equal(log.activityEvent.callCount, 1, 'log.activityEvent was called once')
|
||||
assert.equal(log.activityEvent.callCount, 1, 'log.activityEvent was called once')
|
||||
args = log.activityEvent.args[0]
|
||||
t.equal(args.length, 3, 'log.activityEvent was passed three arguments')
|
||||
t.equal(args[0], 'device.created', 'first argument was event name')
|
||||
t.equal(args[1], request, 'second argument was request object')
|
||||
t.deepEqual(args[2], {
|
||||
assert.equal(args.length, 3, 'log.activityEvent was passed three arguments')
|
||||
assert.equal(args[0], 'device.created', 'first argument was event name')
|
||||
assert.equal(args[1], request, 'second argument was request object')
|
||||
assert.deepEqual(args[2], {
|
||||
uid: sessionToken.uid.toString('hex'),
|
||||
device_id: deviceId.toString('hex'),
|
||||
is_placeholder: false
|
||||
}, 'third argument contained uid, device_id and is_placeholder')
|
||||
|
||||
t.equal(log.info.callCount, 0, 'log.info was not called')
|
||||
assert.equal(log.info.callCount, 0, 'log.info was not called')
|
||||
|
||||
t.equal(log.notifyAttachedServices.callCount, 1, 'log.notifyAttachedServices was called once')
|
||||
assert.equal(log.notifyAttachedServices.callCount, 1, 'log.notifyAttachedServices was called once')
|
||||
args = log.notifyAttachedServices.args[0]
|
||||
t.equal(args.length, 3, 'log.notifyAttachedServices was passed three arguments')
|
||||
t.equal(args[0], 'device:create', 'first argument was event name')
|
||||
t.equal(args[1], request, 'second argument was request object')
|
||||
t.deepEqual(args[2], {
|
||||
assert.equal(args.length, 3, 'log.notifyAttachedServices was passed three arguments')
|
||||
assert.equal(args[0], 'device:create', 'first argument was event name')
|
||||
assert.equal(args[1], request, 'second argument was request object')
|
||||
assert.deepEqual(args[2], {
|
||||
uid: sessionToken.uid,
|
||||
id: deviceId,
|
||||
type: device.type,
|
||||
|
@ -97,12 +100,12 @@ test('require', function (t) {
|
|||
isPlaceholder: false
|
||||
}, 'third argument was event data')
|
||||
|
||||
t.equal(push.notifyDeviceConnected.callCount, 1, 'push.notifyDeviceConnected was called once')
|
||||
assert.equal(push.notifyDeviceConnected.callCount, 1, 'push.notifyDeviceConnected was called once')
|
||||
args = push.notifyDeviceConnected.args[0]
|
||||
t.equal(args.length, 3, 'push.notifyDeviceConnected was passed three arguments')
|
||||
t.equal(args[0], sessionToken.uid, 'first argument was uid')
|
||||
t.equal(args[1], device.name, 'second arguent was device name')
|
||||
t.equal(args[2], deviceId.toString('hex'), 'third argument was device id')
|
||||
assert.equal(args.length, 3, 'push.notifyDeviceConnected was passed three arguments')
|
||||
assert.equal(args[0], sessionToken.uid, 'first argument was uid')
|
||||
assert.equal(args[1], device.name, 'second arguent was device name')
|
||||
assert.equal(args[2], deviceId.toString('hex'), 'third argument was device id')
|
||||
})
|
||||
.then(function () {
|
||||
db.createDevice.reset()
|
||||
|
@ -112,27 +115,27 @@ test('require', function (t) {
|
|||
})
|
||||
})
|
||||
|
||||
t.test('create placeholder', function (t) {
|
||||
it('should create placeholders', () => {
|
||||
return devices.upsert(request, sessionToken, {})
|
||||
.then(function (result) {
|
||||
t.equal(db.updateDevice.callCount, 0, 'db.updateDevice was not called')
|
||||
t.equal(db.createDevice.callCount, 1, 'db.createDevice was called once')
|
||||
assert.equal(db.updateDevice.callCount, 0, 'db.updateDevice was not called')
|
||||
assert.equal(db.createDevice.callCount, 1, 'db.createDevice was called once')
|
||||
|
||||
t.equal(log.activityEvent.callCount, 1, 'log.activityEvent was called once')
|
||||
t.equal(log.activityEvent.args[0][2].is_placeholder, true, 'is_placeholder was correct')
|
||||
assert.equal(log.activityEvent.callCount, 1, 'log.activityEvent was called once')
|
||||
assert.equal(log.activityEvent.args[0][2].is_placeholder, true, 'is_placeholder was correct')
|
||||
|
||||
t.equal(log.info.callCount, 1, 'log.info was called once')
|
||||
t.equal(log.info.args[0].length, 1, 'log.info was passed one argument')
|
||||
t.deepEqual(log.info.args[0][0], {
|
||||
assert.equal(log.info.callCount, 1, 'log.info was called once')
|
||||
assert.equal(log.info.args[0].length, 1, 'log.info was passed one argument')
|
||||
assert.deepEqual(log.info.args[0][0], {
|
||||
op: 'device:createPlaceholder',
|
||||
uid: sessionToken.uid,
|
||||
id: result.id
|
||||
}, 'argument was event data')
|
||||
|
||||
t.equal(log.notifyAttachedServices.callCount, 1, 'log.notifyAttachedServices was called once')
|
||||
t.equal(log.notifyAttachedServices.args[0][2].isPlaceholder, true, 'isPlaceholder was correct')
|
||||
assert.equal(log.notifyAttachedServices.callCount, 1, 'log.notifyAttachedServices was called once')
|
||||
assert.equal(log.notifyAttachedServices.args[0][2].isPlaceholder, true, 'isPlaceholder was correct')
|
||||
|
||||
t.equal(push.notifyDeviceConnected.callCount, 1, 'push.notifyDeviceConnected was called once')
|
||||
assert.equal(push.notifyDeviceConnected.callCount, 1, 'push.notifyDeviceConnected was called once')
|
||||
})
|
||||
.then(function () {
|
||||
db.createDevice.reset()
|
||||
|
@ -143,7 +146,7 @@ test('require', function (t) {
|
|||
})
|
||||
})
|
||||
|
||||
t.test('update', function (t) {
|
||||
it('should update', () => {
|
||||
var deviceInfo = {
|
||||
id: deviceId,
|
||||
name: device.name,
|
||||
|
@ -151,37 +154,37 @@ test('require', function (t) {
|
|||
}
|
||||
return devices.upsert(request, sessionToken, deviceInfo)
|
||||
.then(function (result) {
|
||||
t.equal(result, deviceInfo, 'result was correct')
|
||||
assert.equal(result, deviceInfo, 'result was correct')
|
||||
|
||||
t.equal(db.createDevice.callCount, 0, 'db.createDevice was not called')
|
||||
assert.equal(db.createDevice.callCount, 0, 'db.createDevice was not called')
|
||||
|
||||
t.equal(db.updateDevice.callCount, 1, 'db.updateDevice was called once')
|
||||
assert.equal(db.updateDevice.callCount, 1, 'db.updateDevice was called once')
|
||||
var args = db.updateDevice.args[0]
|
||||
t.equal(args.length, 3, 'db.createDevice was passed three arguments')
|
||||
t.deepEqual(args[0], sessionToken.uid, 'first argument was uid')
|
||||
t.deepEqual(args[1], sessionToken.tokenId, 'second argument was sessionTokenId')
|
||||
t.deepEqual(args[2], {
|
||||
assert.equal(args.length, 3, 'db.createDevice was passed three arguments')
|
||||
assert.deepEqual(args[0], sessionToken.uid, 'first argument was uid')
|
||||
assert.deepEqual(args[1], sessionToken.tokenId, 'second argument was sessionTokenId')
|
||||
assert.deepEqual(args[2], {
|
||||
id: deviceId,
|
||||
name: device.name,
|
||||
type: device.type
|
||||
}, 'device info was unmodified')
|
||||
|
||||
t.equal(log.activityEvent.callCount, 1, 'log.activityEvent was called once')
|
||||
assert.equal(log.activityEvent.callCount, 1, 'log.activityEvent was called once')
|
||||
args = log.activityEvent.args[0]
|
||||
t.equal(args.length, 3, 'log.activityEvent was passed three arguments')
|
||||
t.equal(args[0], 'device.updated', 'first argument was event name')
|
||||
t.equal(args[1], request, 'second argument was request object')
|
||||
t.deepEqual(args[2], {
|
||||
assert.equal(args.length, 3, 'log.activityEvent was passed three arguments')
|
||||
assert.equal(args[0], 'device.updated', 'first argument was event name')
|
||||
assert.equal(args[1], request, 'second argument was request object')
|
||||
assert.deepEqual(args[2], {
|
||||
uid: sessionToken.uid.toString('hex'),
|
||||
device_id: deviceId.toString('hex'),
|
||||
is_placeholder: false
|
||||
}, 'third argument contained uid and device_id')
|
||||
|
||||
t.equal(log.info.callCount, 0, 'log.info was not called')
|
||||
assert.equal(log.info.callCount, 0, 'log.info was not called')
|
||||
|
||||
t.equal(log.notifyAttachedServices.callCount, 0, 'log.notifyAttachedServices was not called')
|
||||
assert.equal(log.notifyAttachedServices.callCount, 0, 'log.notifyAttachedServices was not called')
|
||||
|
||||
t.equal(push.notifyDeviceConnected.callCount, 0, 'push.notifyDeviceConnected was not called')
|
||||
assert.equal(push.notifyDeviceConnected.callCount, 0, 'push.notifyDeviceConnected was not called')
|
||||
})
|
||||
.then(function () {
|
||||
db.createDevice.reset()
|
||||
|
@ -191,53 +194,50 @@ test('require', function (t) {
|
|||
})
|
||||
})
|
||||
|
||||
t.test('devices.synthesizeName', function (t) {
|
||||
t.equal(devices.synthesizeName({
|
||||
it('should synthesizeName', () => {
|
||||
assert.equal(devices.synthesizeName({
|
||||
uaBrowser: 'foo',
|
||||
uaBrowserVersion: 'bar',
|
||||
uaOS: 'baz',
|
||||
uaOSVersion: 'qux'
|
||||
}), 'foo bar, baz qux', 'result is correct when all ua properties are set')
|
||||
|
||||
t.equal(devices.synthesizeName({
|
||||
assert.equal(devices.synthesizeName({
|
||||
uaBrowserVersion: 'foo',
|
||||
uaOS: 'bar',
|
||||
uaOSVersion: 'baz'
|
||||
}), 'bar baz', 'result is correct when uaBrowser property is missing')
|
||||
|
||||
t.equal(devices.synthesizeName({
|
||||
assert.equal(devices.synthesizeName({
|
||||
uaBrowser: 'foo',
|
||||
uaOS: 'bar',
|
||||
uaOSVersion: 'baz'
|
||||
}), 'foo, bar baz', 'result is correct when uaBrowserVersion property is missing')
|
||||
|
||||
t.equal(devices.synthesizeName({
|
||||
assert.equal(devices.synthesizeName({
|
||||
uaBrowser: 'foo',
|
||||
uaBrowserVersion: 'bar',
|
||||
uaOSVersion: 'baz'
|
||||
}), 'foo bar', 'result is correct when uaOS property is missing')
|
||||
|
||||
t.equal(devices.synthesizeName({
|
||||
assert.equal(devices.synthesizeName({
|
||||
uaBrowser: 'foo',
|
||||
uaBrowserVersion: 'bar',
|
||||
uaOS: 'baz'
|
||||
}), 'foo bar, baz', 'result is correct when uaOSVersion property is missing')
|
||||
|
||||
t.equal(devices.synthesizeName({
|
||||
assert.equal(devices.synthesizeName({
|
||||
uaBrowser: 'wibble',
|
||||
uaBrowserVersion: 'blee'
|
||||
}), 'wibble blee', 'result is correct when both uaOS properties are missing')
|
||||
|
||||
t.equal(devices.synthesizeName({
|
||||
assert.equal(devices.synthesizeName({
|
||||
uaOS: 'foo'
|
||||
}), 'foo', 'result is correct when only uaOS property is present')
|
||||
|
||||
t.equal(devices.synthesizeName({
|
||||
assert.equal(devices.synthesizeName({
|
||||
uaOSVersion: 'foo'
|
||||
}), '', 'result defaults to the empty string')
|
||||
|
||||
t.end()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
|
|
|
@ -2,97 +2,95 @@
|
|||
* 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/. */
|
||||
|
||||
var test = require('../ptaptest')
|
||||
const assert = require('insist')
|
||||
var messages = require('joi/lib/language')
|
||||
var AppError = require('../../lib/error')
|
||||
|
||||
test(
|
||||
'tightly-coupled joi message hack is okay',
|
||||
function (t) {
|
||||
t.equal(typeof messages.errors.any.required, 'string')
|
||||
t.not(messages.errors.any.required, '')
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
describe('AppErrors', () => {
|
||||
|
||||
test(
|
||||
'exported functions exist',
|
||||
function (t) {
|
||||
t.equal(typeof AppError, 'function')
|
||||
t.equal(AppError.length, 3)
|
||||
t.equal(typeof AppError.translate, 'function')
|
||||
t.equal(AppError.translate.length, 1)
|
||||
t.equal(typeof AppError.invalidRequestParameter, 'function')
|
||||
t.equal(AppError.invalidRequestParameter.length, 1)
|
||||
t.equal(typeof AppError.missingRequestParameter, 'function')
|
||||
t.equal(AppError.missingRequestParameter.length, 1)
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
it(
|
||||
'tightly-coupled joi message hack is okay',
|
||||
() => {
|
||||
assert.equal(typeof messages.errors.any.required, 'string')
|
||||
assert.notEqual(messages.errors.any.required, '')
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'error.translate with missing required parameters',
|
||||
function (t) {
|
||||
var result = AppError.translate({
|
||||
output: {
|
||||
payload: {
|
||||
message: 'foo' + messages.errors.any.required,
|
||||
validation: {
|
||||
keys: [ 'bar', 'baz' ]
|
||||
it(
|
||||
'exported functions exist',
|
||||
() => {
|
||||
assert.equal(typeof AppError, 'function')
|
||||
assert.equal(AppError.length, 3)
|
||||
assert.equal(typeof AppError.translate, 'function')
|
||||
assert.equal(AppError.translate.length, 1)
|
||||
assert.equal(typeof AppError.invalidRequestParameter, 'function')
|
||||
assert.equal(AppError.invalidRequestParameter.length, 1)
|
||||
assert.equal(typeof AppError.missingRequestParameter, 'function')
|
||||
assert.equal(AppError.missingRequestParameter.length, 1)
|
||||
}
|
||||
)
|
||||
|
||||
it(
|
||||
'should translate with missing required parameters',
|
||||
() => {
|
||||
var result = AppError.translate({
|
||||
output: {
|
||||
payload: {
|
||||
message: 'foo' + messages.errors.any.required,
|
||||
validation: {
|
||||
keys: [ 'bar', 'baz' ]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
t.ok(result instanceof AppError, 'instanceof AppError')
|
||||
t.equal(result.errno, 108)
|
||||
t.equal(result.message, 'Missing parameter in request body: bar')
|
||||
t.equal(result.output.statusCode, 400)
|
||||
t.equal(result.output.payload.error, 'Bad Request')
|
||||
t.equal(result.output.payload.errno, result.errno)
|
||||
t.equal(result.output.payload.message, result.message)
|
||||
t.equal(result.output.payload.param, 'bar')
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
})
|
||||
assert.ok(result instanceof AppError, 'instanceof AppError')
|
||||
assert.equal(result.errno, 108)
|
||||
assert.equal(result.message, 'Missing parameter in request body: bar')
|
||||
assert.equal(result.output.statusCode, 400)
|
||||
assert.equal(result.output.payload.error, 'Bad Request')
|
||||
assert.equal(result.output.payload.errno, result.errno)
|
||||
assert.equal(result.output.payload.message, result.message)
|
||||
assert.equal(result.output.payload.param, 'bar')
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'error.translate with invalid parameter',
|
||||
function (t) {
|
||||
var result = AppError.translate({
|
||||
output: {
|
||||
payload: {
|
||||
validation: 'foo'
|
||||
it(
|
||||
'should translate with invalid parameter',
|
||||
() => {
|
||||
var result = AppError.translate({
|
||||
output: {
|
||||
payload: {
|
||||
validation: 'foo'
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
t.ok(result instanceof AppError, 'instanceof AppError')
|
||||
t.equal(result.errno, 107)
|
||||
t.equal(result.message, 'Invalid parameter in request body')
|
||||
t.equal(result.output.statusCode, 400)
|
||||
t.equal(result.output.payload.error, 'Bad Request')
|
||||
t.equal(result.output.payload.errno, result.errno)
|
||||
t.equal(result.output.payload.message, result.message)
|
||||
t.equal(result.output.payload.validation, 'foo')
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
})
|
||||
assert.ok(result instanceof AppError, 'instanceof AppError')
|
||||
assert.equal(result.errno, 107)
|
||||
assert.equal(result.message, 'Invalid parameter in request body')
|
||||
assert.equal(result.output.statusCode, 400)
|
||||
assert.equal(result.output.payload.error, 'Bad Request')
|
||||
assert.equal(result.output.payload.errno, result.errno)
|
||||
assert.equal(result.output.payload.message, result.message)
|
||||
assert.equal(result.output.payload.validation, 'foo')
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'tooManyRequests',
|
||||
function (t) {
|
||||
var result = AppError.tooManyRequests(900, 'in 15 minutes')
|
||||
t.ok(result instanceof AppError, 'instanceof AppError')
|
||||
t.equal(result.errno, 114)
|
||||
t.equal(result.message, 'Client has sent too many requests')
|
||||
t.equal(result.output.statusCode, 429)
|
||||
t.equal(result.output.payload.error, 'Too Many Requests')
|
||||
t.equal(result.output.payload.retryAfter, 900)
|
||||
t.equal(result.output.payload.retryAfterLocalized, 'in 15 minutes')
|
||||
it(
|
||||
'tooManyRequests',
|
||||
() => {
|
||||
var result = AppError.tooManyRequests(900, 'in 15 minutes')
|
||||
assert.ok(result instanceof AppError, 'instanceof AppError')
|
||||
assert.equal(result.errno, 114)
|
||||
assert.equal(result.message, 'Client has sent too many requests')
|
||||
assert.equal(result.output.statusCode, 429)
|
||||
assert.equal(result.output.payload.error, 'Too Many Requests')
|
||||
assert.equal(result.output.payload.retryAfter, 900)
|
||||
assert.equal(result.output.payload.retryAfterLocalized, 'in 15 minutes')
|
||||
|
||||
result = AppError.tooManyRequests(900)
|
||||
t.equal(result.output.payload.retryAfter, 900)
|
||||
t.notOk(result.output.payload.retryAfterLocalized)
|
||||
result = AppError.tooManyRequests(900)
|
||||
assert.equal(result.output.payload.retryAfter, 900)
|
||||
assert(!result.output.payload.retryAfterLocalized)
|
||||
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
})
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
'use strict'
|
||||
|
||||
const test = require('../ptaptest')
|
||||
const assert = require('insist')
|
||||
const sinon = require('sinon')
|
||||
const proxyquire = require('proxyquire')
|
||||
|
||||
|
@ -27,255 +27,246 @@ const features = proxyquire('../../lib/features', {
|
|||
crypto: crypto
|
||||
})(config)
|
||||
|
||||
test(
|
||||
'interface is correct',
|
||||
t => {
|
||||
t.equal(typeof features, 'object', 'object type should be exported')
|
||||
t.equal(Object.keys(features).length, 4, 'object should have four properties')
|
||||
t.equal(typeof features.isSampledUser, 'function', 'isSampledUser should be function')
|
||||
t.equal(typeof features.isLastAccessTimeEnabledForUser, 'function', 'isLastAccessTimeEnabledForUser should be function')
|
||||
t.equal(typeof features.isSigninConfirmationEnabledForUser, 'function', 'isSigninConfirmationEnabledForUser should be function')
|
||||
t.equal(typeof features.isSigninUnblockEnabledForUser, 'function', 'isSigninUnblockEnabledForUser should be function')
|
||||
describe('features', () => {
|
||||
it(
|
||||
'interface is correct',
|
||||
() => {
|
||||
assert.equal(typeof features, 'object', 'object type should be exported')
|
||||
assert.equal(Object.keys(features).length, 4, 'object should have four properties')
|
||||
assert.equal(typeof features.isSampledUser, 'function', 'isSampledUser should be function')
|
||||
assert.equal(typeof features.isLastAccessTimeEnabledForUser, 'function', 'isLastAccessTimeEnabledForUser should be function')
|
||||
assert.equal(typeof features.isSigninConfirmationEnabledForUser, 'function', 'isSigninConfirmationEnabledForUser should be function')
|
||||
assert.equal(typeof features.isSigninUnblockEnabledForUser, 'function', 'isSigninUnblockEnabledForUser should be function')
|
||||
|
||||
t.equal(crypto.createHash.callCount, 1, 'crypto.createHash should have been called once on require')
|
||||
let args = crypto.createHash.args[0]
|
||||
t.equal(args.length, 1, 'crypto.createHash should have been passed one argument')
|
||||
t.equal(args[0], 'sha1', 'crypto.createHash algorithm should have been sha1')
|
||||
assert.equal(crypto.createHash.callCount, 1, 'crypto.createHash should have been called once on require')
|
||||
let args = crypto.createHash.args[0]
|
||||
assert.equal(args.length, 1, 'crypto.createHash should have been passed one argument')
|
||||
assert.equal(args[0], 'sha1', 'crypto.createHash algorithm should have been sha1')
|
||||
|
||||
t.equal(hash.update.callCount, 2, 'hash.update should have been called twice on require')
|
||||
args = hash.update.args[0]
|
||||
t.equal(args.length, 1, 'hash.update should have been passed one argument first time')
|
||||
t.equal(typeof args[0], 'string', 'hash.update data should have been a string first time')
|
||||
args = hash.update.args[1]
|
||||
t.equal(args.length, 1, 'hash.update should have been passed one argument second time')
|
||||
t.equal(typeof args[0], 'string', 'hash.update data should have been a string second time')
|
||||
assert.equal(hash.update.callCount, 2, 'hash.update should have been called twice on require')
|
||||
args = hash.update.args[0]
|
||||
assert.equal(args.length, 1, 'hash.update should have been passed one argument first time')
|
||||
assert.equal(typeof args[0], 'string', 'hash.update data should have been a string first time')
|
||||
args = hash.update.args[1]
|
||||
assert.equal(args.length, 1, 'hash.update should have been passed one argument second time')
|
||||
assert.equal(typeof args[0], 'string', 'hash.update data should have been a string second time')
|
||||
|
||||
t.equal(hash.digest.callCount, 1, 'hash.digest should have been called once on require')
|
||||
args = hash.digest.args[0]
|
||||
t.equal(args.length, 1, 'hash.digest should have been passed one argument')
|
||||
t.equal(args[0], 'hex', 'hash.digest ecnoding should have been hex')
|
||||
assert.equal(hash.digest.callCount, 1, 'hash.digest should have been called once on require')
|
||||
args = hash.digest.args[0]
|
||||
assert.equal(args.length, 1, 'hash.digest should have been passed one argument')
|
||||
assert.equal(args[0], 'hex', 'hash.digest ecnoding should have been hex')
|
||||
|
||||
crypto.createHash.reset()
|
||||
hash.update.reset()
|
||||
hash.digest.reset()
|
||||
crypto.createHash.reset()
|
||||
hash.update.reset()
|
||||
hash.digest.reset()
|
||||
}
|
||||
)
|
||||
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
it(
|
||||
'isSampledUser',
|
||||
() => {
|
||||
let uid = Buffer.alloc(32, 0xff)
|
||||
let sampleRate = 1
|
||||
hashResult = Array(40).fill('f').join('')
|
||||
|
||||
test(
|
||||
'isSampledUser',
|
||||
t => {
|
||||
let uid = Buffer.alloc(32, 0xff)
|
||||
let sampleRate = 1
|
||||
hashResult = Array(40).fill('f').join('')
|
||||
assert.equal(features.isSampledUser(sampleRate, uid, 'foo'), true, 'should always return true if sample rate is 1')
|
||||
|
||||
t.equal(features.isSampledUser(sampleRate, uid, 'foo'), true, 'should always return true if sample rate is 1')
|
||||
assert.equal(crypto.createHash.callCount, 0, 'crypto.createHash should not have been called')
|
||||
assert.equal(hash.update.callCount, 0, 'hash.update should not have been called')
|
||||
assert.equal(hash.digest.callCount, 0, 'hash.digest should not have been called')
|
||||
|
||||
t.equal(crypto.createHash.callCount, 0, 'crypto.createHash should not have been called')
|
||||
t.equal(hash.update.callCount, 0, 'hash.update should not have been called')
|
||||
t.equal(hash.digest.callCount, 0, 'hash.digest should not have been called')
|
||||
sampleRate = 0
|
||||
hashResult = Array(40).fill('0').join('')
|
||||
|
||||
sampleRate = 0
|
||||
hashResult = Array(40).fill('0').join('')
|
||||
assert.equal(features.isSampledUser(sampleRate, uid, 'foo'), false, 'should always return false if sample rate is 0')
|
||||
|
||||
t.equal(features.isSampledUser(sampleRate, uid, 'foo'), false, 'should always return false if sample rate is 0')
|
||||
assert.equal(crypto.createHash.callCount, 0, 'crypto.createHash should not have been called')
|
||||
assert.equal(hash.update.callCount, 0, 'hash.update should not have been called')
|
||||
assert.equal(hash.digest.callCount, 0, 'hash.digest should not have been called')
|
||||
|
||||
t.equal(crypto.createHash.callCount, 0, 'crypto.createHash should not have been called')
|
||||
t.equal(hash.update.callCount, 0, 'hash.update should not have been called')
|
||||
t.equal(hash.digest.callCount, 0, 'hash.digest should not have been called')
|
||||
sampleRate = 0.05
|
||||
// First 27 characters are ignored, last 13 are 0.04 * 0xfffffffffffff
|
||||
hashResult = '0000000000000000000000000000a3d70a3d70a6'
|
||||
|
||||
sampleRate = 0.05
|
||||
// First 27 characters are ignored, last 13 are 0.04 * 0xfffffffffffff
|
||||
hashResult = '0000000000000000000000000000a3d70a3d70a6'
|
||||
assert.equal(features.isSampledUser(sampleRate, uid, 'foo'), true, 'should return true if sample rate is greater than the extracted cohort value')
|
||||
|
||||
t.equal(features.isSampledUser(sampleRate, uid, 'foo'), true, 'should return true if sample rate is greater than the extracted cohort value')
|
||||
assert.equal(crypto.createHash.callCount, 1, 'crypto.createHash should have been called once')
|
||||
let args = crypto.createHash.args[0]
|
||||
assert.equal(args.length, 1, 'crypto.createHash should have been passed one argument')
|
||||
assert.equal(args[0], 'sha1', 'crypto.createHash algorithm should have been sha1')
|
||||
|
||||
t.equal(crypto.createHash.callCount, 1, 'crypto.createHash should have been called once')
|
||||
let args = crypto.createHash.args[0]
|
||||
t.equal(args.length, 1, 'crypto.createHash should have been passed one argument')
|
||||
t.equal(args[0], 'sha1', 'crypto.createHash algorithm should have been sha1')
|
||||
assert.equal(hash.update.callCount, 2, 'hash.update should have been called twice')
|
||||
args = hash.update.args[0]
|
||||
assert.equal(args.length, 1, 'hash.update should have been passed one argument first time')
|
||||
assert.equal(args[0], uid.toString('hex'), 'hash.update data should have been stringified uid first time')
|
||||
args = hash.update.args[1]
|
||||
assert.equal(args.length, 1, 'hash.update should have been passed one argument second time')
|
||||
assert.equal(args[0], 'foo', 'hash.update data should have been key second time')
|
||||
|
||||
t.equal(hash.update.callCount, 2, 'hash.update should have been called twice')
|
||||
args = hash.update.args[0]
|
||||
t.equal(args.length, 1, 'hash.update should have been passed one argument first time')
|
||||
t.equal(args[0], uid.toString('hex'), 'hash.update data should have been stringified uid first time')
|
||||
args = hash.update.args[1]
|
||||
t.equal(args.length, 1, 'hash.update should have been passed one argument second time')
|
||||
t.equal(args[0], 'foo', 'hash.update data should have been key second time')
|
||||
assert.equal(hash.digest.callCount, 1, 'hash.digest should have been called once')
|
||||
args = hash.digest.args[0]
|
||||
assert.equal(args.length, 1, 'hash.digest should have been passed one argument')
|
||||
assert.equal(args[0], 'hex', 'hash.digest ecnoding should have been hex')
|
||||
|
||||
t.equal(hash.digest.callCount, 1, 'hash.digest should have been called once')
|
||||
args = hash.digest.args[0]
|
||||
t.equal(args.length, 1, 'hash.digest should have been passed one argument')
|
||||
t.equal(args[0], 'hex', 'hash.digest ecnoding should have been hex')
|
||||
crypto.createHash.reset()
|
||||
hash.update.reset()
|
||||
hash.digest.reset()
|
||||
|
||||
crypto.createHash.reset()
|
||||
hash.update.reset()
|
||||
hash.digest.reset()
|
||||
sampleRate = 0.04
|
||||
|
||||
sampleRate = 0.04
|
||||
assert.equal(features.isSampledUser(sampleRate, uid, 'bar'), false, 'should return false if sample rate is equal to the extracted cohort value')
|
||||
|
||||
t.equal(features.isSampledUser(sampleRate, uid, 'bar'), false, 'should return false if sample rate is equal to the extracted cohort value')
|
||||
assert.equal(crypto.createHash.callCount, 1, 'crypto.createHash should have been called once')
|
||||
assert.equal(hash.update.callCount, 2, 'hash.update should have been called twice')
|
||||
assert.equal(hash.update.args[0][0], uid.toString('hex'), 'hash.update data should have been stringified uid first time')
|
||||
assert.equal(hash.update.args[1][0], 'bar', 'hash.update data should have been key second time')
|
||||
assert.equal(hash.digest.callCount, 1, 'hash.digest should have been called once')
|
||||
|
||||
t.equal(crypto.createHash.callCount, 1, 'crypto.createHash should have been called once')
|
||||
t.equal(hash.update.callCount, 2, 'hash.update should have been called twice')
|
||||
t.equal(hash.update.args[0][0], uid.toString('hex'), 'hash.update data should have been stringified uid first time')
|
||||
t.equal(hash.update.args[1][0], 'bar', 'hash.update data should have been key second time')
|
||||
t.equal(hash.digest.callCount, 1, 'hash.digest should have been called once')
|
||||
crypto.createHash.reset()
|
||||
hash.update.reset()
|
||||
hash.digest.reset()
|
||||
|
||||
crypto.createHash.reset()
|
||||
hash.update.reset()
|
||||
hash.digest.reset()
|
||||
sampleRate = 0.03
|
||||
|
||||
sampleRate = 0.03
|
||||
assert.equal(features.isSampledUser(sampleRate, uid, 'foo'), false, 'should return false if sample rate is less than the extracted cohort value')
|
||||
|
||||
t.equal(features.isSampledUser(sampleRate, uid, 'foo'), false, 'should return false if sample rate is less than the extracted cohort value')
|
||||
crypto.createHash.reset()
|
||||
hash.update.reset()
|
||||
hash.digest.reset()
|
||||
|
||||
crypto.createHash.reset()
|
||||
hash.update.reset()
|
||||
hash.digest.reset()
|
||||
uid = Array(64).fill('7').join('')
|
||||
sampleRate = 0.03
|
||||
// First 27 characters are ignored, last 13 are 0.02 * 0xfffffffffffff
|
||||
hashResult = '000000000000000000000000000051eb851eb852'
|
||||
|
||||
uid = Array(64).fill('7').join('')
|
||||
sampleRate = 0.03
|
||||
// First 27 characters are ignored, last 13 are 0.02 * 0xfffffffffffff
|
||||
hashResult = '000000000000000000000000000051eb851eb852'
|
||||
assert.equal(features.isSampledUser(sampleRate, uid, 'wibble'), true, 'should return true if sample rate is greater than the extracted cohort value')
|
||||
|
||||
t.equal(features.isSampledUser(sampleRate, uid, 'wibble'), true, 'should return true if sample rate is greater than the extracted cohort value')
|
||||
assert.equal(hash.update.callCount, 2, 'hash.update should have been called twice')
|
||||
assert.equal(hash.update.args[0][0], uid, 'hash.update data should have been stringified uid first time')
|
||||
assert.equal(hash.update.args[1][0], 'wibble', 'hash.update data should have been key second time')
|
||||
|
||||
t.equal(hash.update.callCount, 2, 'hash.update should have been called twice')
|
||||
t.equal(hash.update.args[0][0], uid, 'hash.update data should have been stringified uid first time')
|
||||
t.equal(hash.update.args[1][0], 'wibble', 'hash.update data should have been key second time')
|
||||
crypto.createHash.reset()
|
||||
hash.update.reset()
|
||||
hash.digest.reset()
|
||||
}
|
||||
)
|
||||
|
||||
crypto.createHash.reset()
|
||||
hash.update.reset()
|
||||
hash.digest.reset()
|
||||
it(
|
||||
'isLastAccessTimeEnabledForUser',
|
||||
() => {
|
||||
const uid = 'foo'
|
||||
const email = 'bar@mozilla.com'
|
||||
// First 27 characters are ignored, last 13 are 0.02 * 0xfffffffffffff
|
||||
hashResult = '000000000000000000000000000051eb851eb852'
|
||||
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
config.lastAccessTimeUpdates.enabled = true
|
||||
config.lastAccessTimeUpdates.sampleRate = 0
|
||||
config.lastAccessTimeUpdates.enabledEmailAddresses = /.+@mozilla\.com$/
|
||||
assert.equal(features.isLastAccessTimeEnabledForUser(uid, email), true, 'should return true when email address matches')
|
||||
|
||||
test(
|
||||
'isLastAccessTimeEnabledForUser',
|
||||
t => {
|
||||
const uid = 'foo'
|
||||
const email = 'bar@mozilla.com'
|
||||
// First 27 characters are ignored, last 13 are 0.02 * 0xfffffffffffff
|
||||
hashResult = '000000000000000000000000000051eb851eb852'
|
||||
config.lastAccessTimeUpdates.enabledEmailAddresses = /.+@mozilla\.org$/
|
||||
assert.equal(features.isLastAccessTimeEnabledForUser(uid, email), false, 'should return false when email address does not match')
|
||||
|
||||
config.lastAccessTimeUpdates.enabled = true
|
||||
config.lastAccessTimeUpdates.sampleRate = 0
|
||||
config.lastAccessTimeUpdates.enabledEmailAddresses = /.+@mozilla\.com$/
|
||||
t.equal(features.isLastAccessTimeEnabledForUser(uid, email), true, 'should return true when email address matches')
|
||||
config.lastAccessTimeUpdates.sampleRate = 0.03
|
||||
assert.equal(features.isLastAccessTimeEnabledForUser(uid, email), true, 'should return true when sample rate matches')
|
||||
|
||||
config.lastAccessTimeUpdates.enabledEmailAddresses = /.+@mozilla\.org$/
|
||||
t.equal(features.isLastAccessTimeEnabledForUser(uid, email), false, 'should return false when email address does not match')
|
||||
config.lastAccessTimeUpdates.sampleRate = 0.02
|
||||
assert.equal(features.isLastAccessTimeEnabledForUser(uid, email), false, 'should return false when sample rate does not match')
|
||||
|
||||
config.lastAccessTimeUpdates.sampleRate = 0.03
|
||||
t.equal(features.isLastAccessTimeEnabledForUser(uid, email), true, 'should return true when sample rate matches')
|
||||
config.lastAccessTimeUpdates.enabled = false
|
||||
config.lastAccessTimeUpdates.sampleRate = 0.03
|
||||
config.lastAccessTimeUpdates.enabledEmailAddresses = /.+@mozilla\.com$/
|
||||
assert.equal(features.isLastAccessTimeEnabledForUser(uid, email), false, 'should return false when feature is disabled')
|
||||
}
|
||||
)
|
||||
|
||||
config.lastAccessTimeUpdates.sampleRate = 0.02
|
||||
t.equal(features.isLastAccessTimeEnabledForUser(uid, email), false, 'should return false when sample rate does not match')
|
||||
|
||||
config.lastAccessTimeUpdates.enabled = false
|
||||
config.lastAccessTimeUpdates.sampleRate = 0.03
|
||||
config.lastAccessTimeUpdates.enabledEmailAddresses = /.+@mozilla\.com$/
|
||||
t.equal(features.isLastAccessTimeEnabledForUser(uid, email), false, 'should return false when feature is disabled')
|
||||
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'isSigninConfirmationEnabledForUser',
|
||||
t => {
|
||||
const uid = 'wibble'
|
||||
const email = 'blee@mozilla.com'
|
||||
const request = {
|
||||
app: {
|
||||
isSuspiciousRequest: true
|
||||
},
|
||||
payload: {
|
||||
metricsContext: {
|
||||
context: 'iframe'
|
||||
it(
|
||||
'isSigninConfirmationEnabledForUser',
|
||||
() => {
|
||||
const uid = 'wibble'
|
||||
const email = 'blee@mozilla.com'
|
||||
const request = {
|
||||
app: {
|
||||
isSuspiciousRequest: true
|
||||
},
|
||||
payload: {
|
||||
metricsContext: {
|
||||
context: 'iframe'
|
||||
}
|
||||
}
|
||||
}
|
||||
// First 27 characters are ignored, last 13 are 0.02 * 0xfffffffffffff
|
||||
hashResult = '000000000000000000000000000051eb851eb852'
|
||||
|
||||
config.signinConfirmation.enabled = true
|
||||
config.signinConfirmation.sample_rate = 0.03
|
||||
config.signinConfirmation.enabledEmailAddresses = /.+@mozilla\.com$/
|
||||
config.signinConfirmation.supportedClients = [ 'wibble', 'iframe' ]
|
||||
assert.equal(features.isSigninConfirmationEnabledForUser(uid, email, request), true, 'should return true when request is suspicious')
|
||||
|
||||
config.signinConfirmation.sample_rate = 0.02
|
||||
request.app.isSuspiciousRequest = false
|
||||
assert.equal(features.isSigninConfirmationEnabledForUser(uid, email, request), true, 'should return true when email address matches')
|
||||
|
||||
config.signinConfirmation.enabledEmailAddresses = /.+@mozilla\.org$/
|
||||
request.payload.metricsContext.context = 'iframe'
|
||||
assert.equal(features.isSigninConfirmationEnabledForUser(uid, email, request), false, 'should return false when email address and sample rate do not match')
|
||||
|
||||
config.signinConfirmation.sample_rate = 0.03
|
||||
assert.equal(features.isSigninConfirmationEnabledForUser(uid, email, request), true, 'should return true when sample rate and context match')
|
||||
|
||||
request.payload.metricsContext.context = ''
|
||||
assert.equal(features.isSigninConfirmationEnabledForUser(uid, email, request), false, 'should return false when context does not match')
|
||||
|
||||
config.signinConfirmation.enabled = false
|
||||
config.signinConfirmation.forceEmailRegex = /.+@mozilla\.com$/
|
||||
request.payload.metricsContext.context = 'iframe'
|
||||
assert.equal(features.isSigninConfirmationEnabledForUser(uid, email, request), false, 'should return false when feature is disabled')
|
||||
}
|
||||
// First 27 characters are ignored, last 13 are 0.02 * 0xfffffffffffff
|
||||
hashResult = '000000000000000000000000000051eb851eb852'
|
||||
)
|
||||
|
||||
config.signinConfirmation.enabled = true
|
||||
config.signinConfirmation.sample_rate = 0.03
|
||||
config.signinConfirmation.enabledEmailAddresses = /.+@mozilla\.com$/
|
||||
config.signinConfirmation.supportedClients = [ 'wibble', 'iframe' ]
|
||||
t.equal(features.isSigninConfirmationEnabledForUser(uid, email, request), true, 'should return true when request is suspicious')
|
||||
|
||||
config.signinConfirmation.sample_rate = 0.02
|
||||
request.app.isSuspiciousRequest = false
|
||||
t.equal(features.isSigninConfirmationEnabledForUser(uid, email, request), true, 'should return true when email address matches')
|
||||
|
||||
config.signinConfirmation.enabledEmailAddresses = /.+@mozilla\.org$/
|
||||
request.payload.metricsContext.context = 'iframe'
|
||||
t.equal(features.isSigninConfirmationEnabledForUser(uid, email, request), false, 'should return false when email address and sample rate do not match')
|
||||
|
||||
config.signinConfirmation.sample_rate = 0.03
|
||||
t.equal(features.isSigninConfirmationEnabledForUser(uid, email, request), true, 'should return true when sample rate and context match')
|
||||
|
||||
request.payload.metricsContext.context = ''
|
||||
t.equal(features.isSigninConfirmationEnabledForUser(uid, email, request), false, 'should return false when context does not match')
|
||||
|
||||
config.signinConfirmation.enabled = false
|
||||
config.signinConfirmation.forceEmailRegex = /.+@mozilla\.com$/
|
||||
request.payload.metricsContext.context = 'iframe'
|
||||
t.equal(features.isSigninConfirmationEnabledForUser(uid, email, request), false, 'should return false when feature is disabled')
|
||||
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'isSigninUnblockEnabledForUser',
|
||||
t => {
|
||||
const uid = 'wibble'
|
||||
const email = 'blee@mozilla.com'
|
||||
const request = {
|
||||
payload: {
|
||||
metricsContext: {
|
||||
context: 'iframe'
|
||||
it(
|
||||
'isSigninUnblockEnabledForUser',
|
||||
() => {
|
||||
const uid = 'wibble'
|
||||
const email = 'blee@mozilla.com'
|
||||
const request = {
|
||||
payload: {
|
||||
metricsContext: {
|
||||
context: 'iframe'
|
||||
}
|
||||
}
|
||||
}
|
||||
// First 27 characters are ignored, last 13 are 0.02 * 0xfffffffffffff
|
||||
hashResult = '000000000000000000000000000051eb851eb852'
|
||||
|
||||
const unblock = config.signinUnblock
|
||||
|
||||
unblock.enabled = true
|
||||
unblock.sampleRate = 0.02
|
||||
unblock.allowedEmailAddresses = /.+@notmozilla.com$/
|
||||
unblock.supportedClients = [ 'wibble', 'iframe' ]
|
||||
assert.equal(features.isSigninUnblockEnabledForUser(uid, email, request), false, 'should return false when email is not allowed and uid is not sampled')
|
||||
|
||||
unblock.forcedEmailAddresses = /.+/
|
||||
assert.equal(features.isSigninUnblockEnabledForUser(uid, email, request), true, 'should return true when forced on')
|
||||
unblock.forcedEmailAddresses = /^$/
|
||||
|
||||
unblock.allowedEmailAddresses = /.+@mozilla.com$/
|
||||
assert.equal(features.isSigninUnblockEnabledForUser(uid, email, request), true, 'should return true when email is allowed')
|
||||
|
||||
unblock.allowedEmailAddresses = /.+@notmozilla.com$/
|
||||
unblock.sampleRate = 0.03
|
||||
assert.equal(features.isSigninUnblockEnabledForUser(uid, email, request), true, 'should return when uid is sampled')
|
||||
|
||||
|
||||
request.payload.metricsContext.context = ''
|
||||
assert.equal(features.isSigninUnblockEnabledForUser(uid, email, request), false, 'should return false when context is not supported')
|
||||
|
||||
|
||||
request.payload.metricsContext.context = 'iframe'
|
||||
unblock.enabled = false
|
||||
assert.equal(features.isSigninUnblockEnabledForUser(uid, email, request), false, 'should return false when feature is disabled')
|
||||
}
|
||||
// First 27 characters are ignored, last 13 are 0.02 * 0xfffffffffffff
|
||||
hashResult = '000000000000000000000000000051eb851eb852'
|
||||
|
||||
const unblock = config.signinUnblock
|
||||
|
||||
unblock.enabled = true
|
||||
unblock.sampleRate = 0.02
|
||||
unblock.allowedEmailAddresses = /.+@notmozilla.com$/
|
||||
unblock.supportedClients = [ 'wibble', 'iframe' ]
|
||||
t.equal(features.isSigninUnblockEnabledForUser(uid, email, request), false, 'should return false when email is not allowed and uid is not sampled')
|
||||
|
||||
unblock.forcedEmailAddresses = /.+/
|
||||
t.equal(features.isSigninUnblockEnabledForUser(uid, email, request), true, 'should return true when forced on')
|
||||
unblock.forcedEmailAddresses = /^$/
|
||||
|
||||
unblock.allowedEmailAddresses = /.+@mozilla.com$/
|
||||
t.equal(features.isSigninUnblockEnabledForUser(uid, email, request), true, 'should return true when email is allowed')
|
||||
|
||||
unblock.allowedEmailAddresses = /.+@notmozilla.com$/
|
||||
unblock.sampleRate = 0.03
|
||||
t.equal(features.isSigninUnblockEnabledForUser(uid, email, request), true, 'should return when uid is sampled')
|
||||
|
||||
|
||||
request.payload.metricsContext.context = ''
|
||||
t.equal(features.isSigninUnblockEnabledForUser(uid, email, request), false, 'should return false when context is not supported')
|
||||
|
||||
|
||||
request.payload.metricsContext.context = 'iframe'
|
||||
unblock.enabled = false
|
||||
t.equal(features.isSigninUnblockEnabledForUser(uid, email, request), false, 'should return false when feature is disabled')
|
||||
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
|
||||
)
|
||||
})
|
||||
|
|
|
@ -2,12 +2,14 @@
|
|||
* 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/. */
|
||||
|
||||
var test = require('../ptaptest')
|
||||
var log = { trace: function() {} }
|
||||
'use strict'
|
||||
|
||||
var timestamp = Date.now()
|
||||
const assert = require('insist')
|
||||
const log = { trace() {} }
|
||||
|
||||
var PasswordForgotToken = require('../../lib/tokens/password_forgot_token')(
|
||||
const timestamp = Date.now()
|
||||
|
||||
const PasswordForgotToken = require('../../lib/tokens/password_forgot_token')(
|
||||
log,
|
||||
require('util').inherits,
|
||||
require('../../lib/tokens')(log),
|
||||
|
@ -16,70 +18,72 @@ var PasswordForgotToken = require('../../lib/tokens/password_forgot_token')(
|
|||
)
|
||||
|
||||
|
||||
var ACCOUNT = {
|
||||
const ACCOUNT = {
|
||||
uid: 'xxx',
|
||||
email: Buffer('test@example.com').toString('hex')
|
||||
}
|
||||
|
||||
describe('PasswordForgotToken', () => {
|
||||
|
||||
test(
|
||||
're-creation from tokenData works',
|
||||
function (t) {
|
||||
var token = null
|
||||
return PasswordForgotToken.create(ACCOUNT)
|
||||
.then(
|
||||
function (x) {
|
||||
token = x
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
return PasswordForgotToken.fromHex(token.data, ACCOUNT)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (token2) {
|
||||
t.deepEqual(token.data, token2.data)
|
||||
t.deepEqual(token.id, token2.id)
|
||||
t.deepEqual(token.authKey, token2.authKey)
|
||||
t.deepEqual(token.bundleKey, token2.bundleKey)
|
||||
t.deepEqual(token.uid, token2.uid)
|
||||
t.deepEqual(token.email, token2.email)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
it(
|
||||
'can re-create from tokenData',
|
||||
() => {
|
||||
var token = null
|
||||
return PasswordForgotToken.create(ACCOUNT)
|
||||
.then(
|
||||
function (x) {
|
||||
token = x
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
return PasswordForgotToken.fromHex(token.data, ACCOUNT)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (token2) {
|
||||
assert.deepEqual(token.data, token2.data)
|
||||
assert.deepEqual(token.id, token2.id)
|
||||
assert.deepEqual(token.authKey, token2.authKey)
|
||||
assert.deepEqual(token.bundleKey, token2.bundleKey)
|
||||
assert.deepEqual(token.uid, token2.uid)
|
||||
assert.deepEqual(token.email, token2.email)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
test(
|
||||
'ttl "works"',
|
||||
function (t) {
|
||||
return PasswordForgotToken.create(ACCOUNT)
|
||||
.then(
|
||||
function (token) {
|
||||
token.createdAt = timestamp
|
||||
t.equal(token.ttl(timestamp), 900)
|
||||
t.equal(token.ttl(timestamp + 1000), 899)
|
||||
t.equal(token.ttl(timestamp + 2000), 898)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
it(
|
||||
'ttl "works"',
|
||||
() => {
|
||||
return PasswordForgotToken.create(ACCOUNT)
|
||||
.then(
|
||||
function (token) {
|
||||
token.createdAt = timestamp
|
||||
assert.equal(token.ttl(timestamp), 900)
|
||||
assert.equal(token.ttl(timestamp + 1000), 899)
|
||||
assert.equal(token.ttl(timestamp + 2000), 898)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
test(
|
||||
'failAttempt decrements `tries`',
|
||||
function (t) {
|
||||
return PasswordForgotToken.create(ACCOUNT)
|
||||
.then(
|
||||
function (x) {
|
||||
t.equal(x.tries, 3)
|
||||
t.equal(x.failAttempt(), false)
|
||||
t.equal(x.tries, 2)
|
||||
t.equal(x.failAttempt(), false)
|
||||
t.equal(x.tries, 1)
|
||||
t.equal(x.failAttempt(), true)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
it(
|
||||
'failAttempt decrements `tries`',
|
||||
() => {
|
||||
return PasswordForgotToken.create(ACCOUNT)
|
||||
.then(
|
||||
function (x) {
|
||||
assert.equal(x.tries, 3)
|
||||
assert.equal(x.failAttempt(), false)
|
||||
assert.equal(x.tries, 2)
|
||||
assert.equal(x.failAttempt(), false)
|
||||
assert.equal(x.tries, 1)
|
||||
assert.equal(x.failAttempt(), true)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
})
|
||||
|
|
|
@ -2,61 +2,62 @@
|
|||
* 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/. */
|
||||
|
||||
var tap = require('tap')
|
||||
var proxyquire = require('proxyquire')
|
||||
var test = tap.test
|
||||
var mockLog = require('../mocks').mockLog
|
||||
'use strict'
|
||||
|
||||
test(
|
||||
'returns location data when enabled',
|
||||
function (t) {
|
||||
var moduleMocks = {
|
||||
'../config': {
|
||||
'get': function (item) {
|
||||
if (item === 'geodb') {
|
||||
return {
|
||||
enabled: true
|
||||
const assert = require('insist')
|
||||
const proxyquire = require('proxyquire')
|
||||
const mockLog = require('../mocks').mockLog
|
||||
|
||||
describe('geodb', () => {
|
||||
it(
|
||||
'returns location data when enabled',
|
||||
() => {
|
||||
const moduleMocks = {
|
||||
'../config': {
|
||||
'get': function (item) {
|
||||
if (item === 'geodb') {
|
||||
return {
|
||||
enabled: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const thisMockLog = mockLog({})
|
||||
|
||||
const getGeoData = proxyquire('../../lib/geodb', moduleMocks)(thisMockLog)
|
||||
return getGeoData('63.245.221.32') // MTV
|
||||
.then(function (geoData) {
|
||||
assert.equal(geoData.location.city, 'Mountain View')
|
||||
assert.equal(geoData.location.country, 'United States')
|
||||
assert.equal(geoData.timeZone, 'America/Los_Angeles')
|
||||
assert.equal(geoData.location.state, 'California')
|
||||
assert.equal(geoData.location.stateCode, 'CA')
|
||||
})
|
||||
}
|
||||
var thisMockLog = mockLog({})
|
||||
)
|
||||
|
||||
var getGeoData = proxyquire('../../lib/geodb', moduleMocks)(thisMockLog)
|
||||
getGeoData('63.245.221.32') // MTV
|
||||
.then(function (geoData) {
|
||||
t.equal(geoData.location.city, 'Mountain View')
|
||||
t.equal(geoData.location.country, 'United States')
|
||||
t.equal(geoData.timeZone, 'America/Los_Angeles')
|
||||
t.equal(geoData.location.state, 'California')
|
||||
t.equal(geoData.location.stateCode, 'CA')
|
||||
t.end()
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'returns empty object data when disabled',
|
||||
function (t) {
|
||||
var moduleMocks = {
|
||||
'../config': {
|
||||
'get': function (item) {
|
||||
if (item === 'geodb') {
|
||||
return {
|
||||
enabled: false
|
||||
it(
|
||||
'returns empty object data when disabled',
|
||||
() => {
|
||||
const moduleMocks = {
|
||||
'../config': {
|
||||
'get': function (item) {
|
||||
if (item === 'geodb') {
|
||||
return {
|
||||
enabled: false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
var thisMockLog = mockLog({})
|
||||
const thisMockLog = mockLog({})
|
||||
|
||||
var getGeoData = proxyquire('../../lib/geodb', moduleMocks)(thisMockLog)
|
||||
getGeoData('8.8.8.8')
|
||||
.then(function (geoData) {
|
||||
t.deepEqual(geoData, {})
|
||||
t.end()
|
||||
})
|
||||
}
|
||||
)
|
||||
const getGeoData = proxyquire('../../lib/geodb', moduleMocks)(thisMockLog)
|
||||
return getGeoData('8.8.8.8')
|
||||
.then(function (geoData) {
|
||||
assert.deepEqual(geoData, {})
|
||||
})
|
||||
}
|
||||
)
|
||||
})
|
||||
|
|
|
@ -2,50 +2,32 @@
|
|||
* 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/. */
|
||||
|
||||
var test = require('../ptaptest')
|
||||
var hkdf = require('../../lib/crypto/hkdf')
|
||||
'use strict'
|
||||
|
||||
test(
|
||||
'hkdf basic',
|
||||
function (t) {
|
||||
var stretchedPw = 'c16d46c31bee242cb31f916e9e38d60b76431d3f5304549cc75ae4bc20c7108c'
|
||||
stretchedPw = new Buffer (stretchedPw, 'hex')
|
||||
var info = 'mainKDF'
|
||||
var salt = new Buffer ('00f000000000000000000000000000000000000000000000000000000000034d', 'hex')
|
||||
var lengthHkdf = 2 * 32
|
||||
const assert = require('insist')
|
||||
const hkdf = require('../../lib/crypto/hkdf')
|
||||
|
||||
return hkdf(stretchedPw, info, salt, lengthHkdf)
|
||||
.then(
|
||||
function (hkdfResult) {
|
||||
var hkdfStr = hkdfResult.toString('hex')
|
||||
describe('hkdf', () => {
|
||||
|
||||
t.equal(hkdfStr.substring(0, 64), '00f9b71800ab5337d51177d8fbc682a3653fa6dae5b87628eeec43a18af59a9d')
|
||||
t.equal(hkdfStr.substring(64, 128), '6ea660be9c89ec355397f89afb282ea0bf21095760c8c5009bbcc894155bbe2a')
|
||||
return hkdfResult
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
it(
|
||||
'should extract',
|
||||
() => {
|
||||
let stretchedPw = 'c16d46c31bee242cb31f916e9e38d60b76431d3f5304549cc75ae4bc20c7108c'
|
||||
stretchedPw = new Buffer (stretchedPw, 'hex')
|
||||
const info = 'mainKDF'
|
||||
const salt = new Buffer ('00f000000000000000000000000000000000000000000000000000000000034d', 'hex')
|
||||
const lengthHkdf = 2 * 32
|
||||
|
||||
test(
|
||||
'hkdf basic with salt',
|
||||
function (t) {
|
||||
var stretchedPw = 'c16d46c31bee242cb31f916e9e38d60b76431d3f5304549cc75ae4bc20c7108c'
|
||||
stretchedPw = new Buffer (stretchedPw, 'hex')
|
||||
var info = 'mainKDF'
|
||||
var salt = new Buffer ('00f000000000000000000000000000000000000000000000000000000000034d', 'hex')
|
||||
var lengthHkdf = 2 * 32
|
||||
return hkdf(stretchedPw, info, salt, lengthHkdf)
|
||||
.then(
|
||||
function (hkdfResult) {
|
||||
const hkdfStr = hkdfResult.toString('hex')
|
||||
|
||||
return hkdf(stretchedPw, info, salt, lengthHkdf)
|
||||
.then(
|
||||
function (hkdfResult) {
|
||||
var hkdfStr = hkdfResult.toString('hex')
|
||||
|
||||
t.equal(hkdfStr.substring(0, 64), '00f9b71800ab5337d51177d8fbc682a3653fa6dae5b87628eeec43a18af59a9d')
|
||||
t.equal(hkdfStr.substring(64, 128), '6ea660be9c89ec355397f89afb282ea0bf21095760c8c5009bbcc894155bbe2a')
|
||||
t.equal(salt.toString('hex'), '00f000000000000000000000000000000000000000000000000000000000034d')
|
||||
return hkdfResult
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
assert.equal(hkdfStr.substring(0, 64), '00f9b71800ab5337d51177d8fbc682a3653fa6dae5b87628eeec43a18af59a9d')
|
||||
assert.equal(hkdfStr.substring(64, 128), '6ea660be9c89ec355397f89afb282ea0bf21095760c8c5009bbcc894155bbe2a')
|
||||
assert.equal(salt.toString('hex'), '00f000000000000000000000000000000000000000000000000000000000034d')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
})
|
||||
|
|
|
@ -2,168 +2,172 @@
|
|||
* 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/. */
|
||||
|
||||
var test = require('../ptaptest')
|
||||
var crypto = require('crypto')
|
||||
var log = { trace: function() {} }
|
||||
'use strict'
|
||||
|
||||
var tokens = require('../../lib/tokens')(log)
|
||||
var KeyFetchToken = tokens.KeyFetchToken
|
||||
const assert = require('insist')
|
||||
const crypto = require('crypto')
|
||||
const log = { trace() {} }
|
||||
|
||||
var ACCOUNT = {
|
||||
const tokens = require('../../lib/tokens')(log)
|
||||
const KeyFetchToken = tokens.KeyFetchToken
|
||||
|
||||
const ACCOUNT = {
|
||||
uid: 'xxx',
|
||||
kA: Buffer('0000000000000000000000000000000000000000000000000000000000000000', 'hex'),
|
||||
wrapKb: Buffer('0000000000000000000000000000000000000000000000000000000000000000', 'hex'),
|
||||
emailVerified: true
|
||||
}
|
||||
|
||||
describe('KeyFetchToken', () => {
|
||||
|
||||
test(
|
||||
're-creation from tokenData works',
|
||||
function (t) {
|
||||
var token = null
|
||||
return KeyFetchToken.create(ACCOUNT)
|
||||
.then(
|
||||
function (x) {
|
||||
token = x
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
return KeyFetchToken.fromHex(token.data, ACCOUNT)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (token2) {
|
||||
t.deepEqual(token.data, token2.data)
|
||||
t.deepEqual(token.id, token2.id)
|
||||
t.deepEqual(token.authKey, token2.authKey)
|
||||
t.deepEqual(token.bundleKey, token2.bundleKey)
|
||||
t.deepEqual(token.uid, token2.uid)
|
||||
t.deepEqual(token.kA, token2.kA)
|
||||
t.deepEqual(token.wrapKb, token2.wrapKb)
|
||||
t.equal(token.emailVerified, token2.emailVerified)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
it(
|
||||
'should re-create from tokenData',
|
||||
() => {
|
||||
var token = null
|
||||
return KeyFetchToken.create(ACCOUNT)
|
||||
.then(
|
||||
function (x) {
|
||||
token = x
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
return KeyFetchToken.fromHex(token.data, ACCOUNT)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (token2) {
|
||||
assert.deepEqual(token.data, token2.data)
|
||||
assert.deepEqual(token.id, token2.id)
|
||||
assert.deepEqual(token.authKey, token2.authKey)
|
||||
assert.deepEqual(token.bundleKey, token2.bundleKey)
|
||||
assert.deepEqual(token.uid, token2.uid)
|
||||
assert.deepEqual(token.kA, token2.kA)
|
||||
assert.deepEqual(token.wrapKb, token2.wrapKb)
|
||||
assert.equal(token.emailVerified, token2.emailVerified)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
test(
|
||||
're-creation from id works',
|
||||
function (t) {
|
||||
var token = null
|
||||
return KeyFetchToken.create(ACCOUNT)
|
||||
.then(
|
||||
function (x) {
|
||||
token = x
|
||||
return KeyFetchToken.fromId(token.tokenId, token)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (x) {
|
||||
t.equal(x.tokenId, token.tokenId, 'should have same id')
|
||||
t.equal(x.authKey, token.authKey, 'should have same authKey')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
it(
|
||||
'should re-create from id',
|
||||
() => {
|
||||
let token = null
|
||||
return KeyFetchToken.create(ACCOUNT)
|
||||
.then(
|
||||
function (x) {
|
||||
token = x
|
||||
return KeyFetchToken.fromId(token.tokenId, token)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (x) {
|
||||
assert.equal(x.tokenId, token.tokenId, 'should have same id')
|
||||
assert.equal(x.authKey, token.authKey, 'should have same authKey')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
test(
|
||||
'bundle / unbundle of keys works',
|
||||
function (t) {
|
||||
var token = null
|
||||
var kA = crypto.randomBytes(32)
|
||||
var wrapKb = crypto.randomBytes(32)
|
||||
return KeyFetchToken.create(ACCOUNT)
|
||||
.then(
|
||||
function (x) {
|
||||
token = x
|
||||
return x.bundleKeys(kA, wrapKb)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (b) {
|
||||
return token.unbundleKeys(b)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (ub) {
|
||||
t.deepEqual(ub.kA, kA)
|
||||
t.deepEqual(ub.wrapKb, wrapKb)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
it(
|
||||
'should bundle / unbundle of keys',
|
||||
() => {
|
||||
let token = null
|
||||
const kA = crypto.randomBytes(32)
|
||||
const wrapKb = crypto.randomBytes(32)
|
||||
return KeyFetchToken.create(ACCOUNT)
|
||||
.then(
|
||||
function (x) {
|
||||
token = x
|
||||
return x.bundleKeys(kA, wrapKb)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (b) {
|
||||
return token.unbundleKeys(b)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (ub) {
|
||||
assert.deepEqual(ub.kA, kA)
|
||||
assert.deepEqual(ub.wrapKb, wrapKb)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
test(
|
||||
'bundle / unbundle of keys only works with correct token',
|
||||
function (t) {
|
||||
var token1 = null
|
||||
var token2 = null
|
||||
var kA = crypto.randomBytes(32)
|
||||
var wrapKb = crypto.randomBytes(32)
|
||||
return KeyFetchToken.create(ACCOUNT)
|
||||
.then(
|
||||
function (x) {
|
||||
token1 = x
|
||||
return KeyFetchToken.create(ACCOUNT)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (x) {
|
||||
token2 = x
|
||||
return token1.bundleKeys(kA, wrapKb)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (b) {
|
||||
return token2.unbundleKeys(b)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (ub) {
|
||||
t.fail('was able to unbundle using wrong token')
|
||||
},
|
||||
function (err) {
|
||||
t.equal(err.errno, 109, 'expected an invalidSignature error')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
it(
|
||||
'should only bundle / unbundle of keys with correct token',
|
||||
() => {
|
||||
let token1 = null
|
||||
let token2 = null
|
||||
const kA = crypto.randomBytes(32)
|
||||
const wrapKb = crypto.randomBytes(32)
|
||||
return KeyFetchToken.create(ACCOUNT)
|
||||
.then(
|
||||
function (x) {
|
||||
token1 = x
|
||||
return KeyFetchToken.create(ACCOUNT)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (x) {
|
||||
token2 = x
|
||||
return token1.bundleKeys(kA, wrapKb)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (b) {
|
||||
return token2.unbundleKeys(b)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (ub) {
|
||||
assert(false, 'was able to unbundle using wrong token')
|
||||
},
|
||||
function (err) {
|
||||
assert.equal(err.errno, 109, 'expected an invalidSignature error')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
test(
|
||||
'keyFetchToken key derivations are test-vector compliant',
|
||||
function (t) {
|
||||
var token = null
|
||||
var tokenData = '808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f'
|
||||
return KeyFetchToken.fromHex(tokenData, ACCOUNT)
|
||||
.then(
|
||||
function (x) {
|
||||
token = x
|
||||
t.equal(token.data.toString('hex'), tokenData)
|
||||
t.equal(token.id.toString('hex'), '3d0a7c02a15a62a2882f76e39b6494b500c022a8816e048625a495718998ba60')
|
||||
t.equal(token.authKey.toString('hex'), '87b8937f61d38d0e29cd2d5600b3f4da0aa48ac41de36a0efe84bb4a9872ceb7')
|
||||
t.equal(token.bundleKey.toString('hex'), '14f338a9e8c6324d9e102d4e6ee83b209796d5c74bb734a410e729e014a4a546')
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
var kA = Buffer('202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f', 'hex')
|
||||
var wrapKb = Buffer('404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f', 'hex')
|
||||
return token.bundleKeys(kA, wrapKb)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (bundle) {
|
||||
t.equal(bundle,
|
||||
'ee5c58845c7c9412b11bbd20920c2fddd83c33c9cd2c2de2' +
|
||||
'd66b222613364636c2c0f8cfbb7c630472c0bd88451342c6' +
|
||||
'c05b14ce342c5ad46ad89e84464c993c3927d30230157d08' +
|
||||
'17a077eef4b20d976f7a97363faf3f064c003ada7d01aa70')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
it(
|
||||
'should have key derivations that are test-vector compliant',
|
||||
() => {
|
||||
let token = null
|
||||
const tokenData = '808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f'
|
||||
return KeyFetchToken.fromHex(tokenData, ACCOUNT)
|
||||
.then(
|
||||
function (x) {
|
||||
token = x
|
||||
assert.equal(token.data.toString('hex'), tokenData)
|
||||
assert.equal(token.id.toString('hex'), '3d0a7c02a15a62a2882f76e39b6494b500c022a8816e048625a495718998ba60')
|
||||
assert.equal(token.authKey.toString('hex'), '87b8937f61d38d0e29cd2d5600b3f4da0aa48ac41de36a0efe84bb4a9872ceb7')
|
||||
assert.equal(token.bundleKey.toString('hex'), '14f338a9e8c6324d9e102d4e6ee83b209796d5c74bb734a410e729e014a4a546')
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
const kA = Buffer('202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f', 'hex')
|
||||
const wrapKb = Buffer('404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f', 'hex')
|
||||
return token.bundleKeys(kA, wrapKb)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (bundle) {
|
||||
assert.equal(bundle,
|
||||
'ee5c58845c7c9412b11bbd20920c2fddd83c33c9cd2c2de2' +
|
||||
'd66b222613364636c2c0f8cfbb7c630472c0bd88451342c6' +
|
||||
'c05b14ce342c5ad46ad89e84464c993c3927d30230157d08' +
|
||||
'17a077eef4b20d976f7a97363faf3f064c003ada7d01aa70')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
})
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -2,82 +2,79 @@
|
|||
* 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/. */
|
||||
|
||||
var test = require('tap').test
|
||||
'use strict'
|
||||
|
||||
const assert = require('insist')
|
||||
var config = require('../../config').getProperties()
|
||||
var log = {}
|
||||
|
||||
require('../../lib/mailer')(config, log)
|
||||
.done(
|
||||
function(mailer) {
|
||||
describe('mailer locales', () => {
|
||||
|
||||
test(
|
||||
'All configured supportedLanguages are available',
|
||||
function (t) {
|
||||
var locales = config.i18n.supportedLanguages
|
||||
locales.forEach(function(lang) {
|
||||
// sr-LATN is sr, but in Latin characters, not Cyrillic
|
||||
if (lang === 'sr-LATN') {
|
||||
t.equal('sr-Latn', mailer.translator(lang).language)
|
||||
} else {
|
||||
t.equal(lang, mailer.translator(lang).language)
|
||||
}
|
||||
})
|
||||
t.end()
|
||||
let mailer
|
||||
before(() => {
|
||||
return require('../../lib/mailer')(config, log)
|
||||
.then(m => {
|
||||
mailer = m
|
||||
})
|
||||
})
|
||||
|
||||
it(
|
||||
'All configured supportedLanguages are available',
|
||||
() => {
|
||||
var locales = config.i18n.supportedLanguages
|
||||
locales.forEach(function(lang) {
|
||||
// sr-LATN is sr, but in Latin characters, not Cyrillic
|
||||
if (lang === 'sr-LATN') {
|
||||
assert.equal('sr-Latn', mailer.translator(lang).language)
|
||||
} else {
|
||||
assert.equal(lang, mailer.translator(lang).language)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'unsupported languages get default/fallback content',
|
||||
function (t) {
|
||||
// These are locales for which we do not have explicit translations
|
||||
var locales = [
|
||||
// [ locale, expected result ]
|
||||
[ '', 'en' ],
|
||||
[ 'en-US', 'en' ],
|
||||
[ 'en-CA', 'en' ],
|
||||
[ 'db-LB', 'en' ],
|
||||
[ 'el-GR', 'en' ],
|
||||
[ 'es-BO', 'es' ],
|
||||
[ 'fr-FR', 'fr' ],
|
||||
[ 'fr-CA', 'fr' ],
|
||||
]
|
||||
|
||||
locales.forEach(function(lang) {
|
||||
t.equal(lang[1], mailer.translator(lang[0]).language)
|
||||
})
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'accept-language handled correctly',
|
||||
function (t) {
|
||||
// These are the Accept-Language headers from Firefox 37 L10N builds
|
||||
var locales = [
|
||||
// [ accept-language, expected result ]
|
||||
[ 'bogus-value', 'en' ],
|
||||
[ 'en-US,en;q=0.5', 'en' ],
|
||||
[ 'es-AR,es;q=0.8,en-US;q=0.5,en;q=0.3', 'es-AR' ],
|
||||
[ 'es-ES,es;q=0.8,en-US;q=0.5,en;q=0.3', 'es-ES' ],
|
||||
[ 'sv-SE,sv;q=0.8,en-US;q=0.5,en;q=0.3', 'sv-SE' ],
|
||||
[ 'zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3', 'zh-CN' ]
|
||||
]
|
||||
|
||||
locales.forEach(function(lang) {
|
||||
t.equal(lang[1], mailer.translator(lang[0]).language)
|
||||
})
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'teardown',
|
||||
function (t) {
|
||||
mailer.stop()
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
it(
|
||||
'unsupported languages get default/fallback content',
|
||||
() => {
|
||||
// These are locales for which we do not have explicit translations
|
||||
var locales = [
|
||||
// [ locale, expected result ]
|
||||
[ '', 'en' ],
|
||||
[ 'en-US', 'en' ],
|
||||
[ 'en-CA', 'en' ],
|
||||
[ 'db-LB', 'en' ],
|
||||
[ 'el-GR', 'en' ],
|
||||
[ 'es-BO', 'es' ],
|
||||
[ 'fr-FR', 'fr' ],
|
||||
[ 'fr-CA', 'fr' ],
|
||||
]
|
||||
|
||||
locales.forEach(function(lang) {
|
||||
assert.equal(lang[1], mailer.translator(lang[0]).language)
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
it(
|
||||
'accept-language handled correctly',
|
||||
() => {
|
||||
// These are the Accept-Language headers from Firefox 37 L10N builds
|
||||
var locales = [
|
||||
// [ accept-language, expected result ]
|
||||
[ 'bogus-value', 'en' ],
|
||||
[ 'en-US,en;q=0.5', 'en' ],
|
||||
[ 'es-AR,es;q=0.8,en-US;q=0.5,en;q=0.3', 'es-AR' ],
|
||||
[ 'es-ES,es;q=0.8,en-US;q=0.5,en;q=0.3', 'es-ES' ],
|
||||
[ 'sv-SE,sv;q=0.8,en-US;q=0.5,en;q=0.3', 'sv-SE' ],
|
||||
[ 'zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3', 'zh-CN' ]
|
||||
]
|
||||
|
||||
locales.forEach(function(lang) {
|
||||
assert.equal(lang[1], mailer.translator(lang[0]).language)
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
after(() => mailer.stop())
|
||||
|
||||
})
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -4,8 +4,8 @@
|
|||
|
||||
'use strict'
|
||||
|
||||
const assert = require('insist')
|
||||
const sinon = require('sinon')
|
||||
const test = require('../ptaptest')
|
||||
const P = require('../../lib/promise')
|
||||
const log = {
|
||||
activityEvent: sinon.spy(() => {
|
||||
|
@ -17,108 +17,108 @@ const log = {
|
|||
}
|
||||
const events = require('../../lib/metrics/events')(log)
|
||||
|
||||
test('events interface is correct', t => {
|
||||
t.equal(typeof events, 'object', 'events is object')
|
||||
t.notEqual(events, null, 'events is not null')
|
||||
t.equal(Object.keys(events).length, 1, 'events has 1 property')
|
||||
describe('metrics/events', () => {
|
||||
|
||||
t.equal(typeof events.emit, 'function', 'events.emit is function')
|
||||
t.equal(events.emit.length, 2, 'events.emit expects 2 arguments')
|
||||
it('interface is correct', () => {
|
||||
assert.equal(typeof events, 'object', 'events is object')
|
||||
assert.notEqual(events, null, 'events is not null')
|
||||
assert.equal(Object.keys(events).length, 1, 'events has 1 property')
|
||||
|
||||
t.equal(log.activityEvent.callCount, 0, 'log.activityEvent was not called')
|
||||
t.equal(log.flowEvent.callCount, 0, 'log.flowEvent was not called')
|
||||
assert.equal(typeof events.emit, 'function', 'events.emit is function')
|
||||
assert.equal(events.emit.length, 2, 'events.emit expects 2 arguments')
|
||||
|
||||
t.end()
|
||||
})
|
||||
assert.equal(log.activityEvent.callCount, 0, 'log.activityEvent was not called')
|
||||
assert.equal(log.flowEvent.callCount, 0, 'log.flowEvent was not called')
|
||||
})
|
||||
|
||||
test('events.emit with activity event', t => {
|
||||
const request = {}
|
||||
const data = {}
|
||||
return events.emit.call(request, 'device.created', data)
|
||||
.then(() => {
|
||||
t.equal(log.activityEvent.callCount, 1, 'log.activityEvent was called once')
|
||||
const args = log.activityEvent.args[0]
|
||||
t.equal(args.length, 3, 'log.activityEvent was passed three arguments')
|
||||
t.equal(args[0], 'device.created', 'first argument was event name')
|
||||
t.equal(args[1], request, 'second argument was request object')
|
||||
t.equal(args[2], data, 'third argument was event data')
|
||||
it('.emit with activity event', () => {
|
||||
const request = {}
|
||||
const data = {}
|
||||
return events.emit.call(request, 'device.created', data)
|
||||
.then(() => {
|
||||
assert.equal(log.activityEvent.callCount, 1, 'log.activityEvent was called once')
|
||||
const args = log.activityEvent.args[0]
|
||||
assert.equal(args.length, 3, 'log.activityEvent was passed three arguments')
|
||||
assert.equal(args[0], 'device.created', 'first argument was event name')
|
||||
assert.equal(args[1], request, 'second argument was request object')
|
||||
assert.equal(args[2], data, 'third argument was event data')
|
||||
|
||||
t.equal(log.flowEvent.callCount, 0, 'log.flowEvent was not called')
|
||||
assert.equal(log.flowEvent.callCount, 0, 'log.flowEvent was not called')
|
||||
|
||||
log.activityEvent.reset()
|
||||
})
|
||||
})
|
||||
log.activityEvent.reset()
|
||||
})
|
||||
})
|
||||
|
||||
test('events.emit with flow event', t => {
|
||||
const request = {}
|
||||
const data = {}
|
||||
return events.emit.call(request, 'account.reminder', data)
|
||||
.then(() => {
|
||||
t.equal(log.flowEvent.callCount, 1, 'log.flowEvent was called once')
|
||||
const args = log.flowEvent.args[0]
|
||||
t.equal(args.length, 2, 'log.flowEvent was passed two arguments')
|
||||
t.equal(args[0], 'account.reminder', 'first argument was event name')
|
||||
t.equal(args[1], request, 'second argument was request object')
|
||||
it('.emit with flow event', () => {
|
||||
const request = {}
|
||||
const data = {}
|
||||
return events.emit.call(request, 'account.reminder', data)
|
||||
.then(() => {
|
||||
assert.equal(log.flowEvent.callCount, 1, 'log.flowEvent was called once')
|
||||
const args = log.flowEvent.args[0]
|
||||
assert.equal(args.length, 2, 'log.flowEvent was passed two arguments')
|
||||
assert.equal(args[0], 'account.reminder', 'first argument was event name')
|
||||
assert.equal(args[1], request, 'second argument was request object')
|
||||
|
||||
t.equal(log.activityEvent.callCount, 0, 'log.activityEvent was not called')
|
||||
assert.equal(log.activityEvent.callCount, 0, 'log.activityEvent was not called')
|
||||
|
||||
log.flowEvent.reset()
|
||||
})
|
||||
})
|
||||
log.flowEvent.reset()
|
||||
})
|
||||
})
|
||||
|
||||
test('events.emit with hybrid activity/flow event', t => {
|
||||
const request = {}
|
||||
const data = {}
|
||||
return events.emit.call(request, 'account.created', data)
|
||||
.then(() => {
|
||||
t.equal(log.activityEvent.callCount, 1, 'log.activityEvent was called once')
|
||||
let args = log.activityEvent.args[0]
|
||||
t.equal(args.length, 3, 'log.activityEvent was passed three arguments')
|
||||
t.equal(args[0], 'account.created', 'first argument was event name')
|
||||
t.equal(args[1], request, 'second argument was request object')
|
||||
t.equal(args[2], data, 'third argument was event data')
|
||||
it('.emit with hybrid activity/flow event', () => {
|
||||
const request = {}
|
||||
const data = {}
|
||||
return events.emit.call(request, 'account.created', data)
|
||||
.then(() => {
|
||||
assert.equal(log.activityEvent.callCount, 1, 'log.activityEvent was called once')
|
||||
let args = log.activityEvent.args[0]
|
||||
assert.equal(args.length, 3, 'log.activityEvent was passed three arguments')
|
||||
assert.equal(args[0], 'account.created', 'first argument was event name')
|
||||
assert.equal(args[1], request, 'second argument was request object')
|
||||
assert.equal(args[2], data, 'third argument was event data')
|
||||
|
||||
t.equal(log.flowEvent.callCount, 1, 'log.flowEvent was called once')
|
||||
args = log.flowEvent.args[0]
|
||||
t.equal(args.length, 2, 'log.flowEvent was passed two arguments')
|
||||
t.equal(args[0], 'account.created', 'first argument was event name')
|
||||
t.equal(args[1], request, 'second argument was request object')
|
||||
assert.equal(log.flowEvent.callCount, 1, 'log.flowEvent was called once')
|
||||
args = log.flowEvent.args[0]
|
||||
assert.equal(args.length, 2, 'log.flowEvent was passed two arguments')
|
||||
assert.equal(args[0], 'account.created', 'first argument was event name')
|
||||
assert.equal(args[1], request, 'second argument was request object')
|
||||
|
||||
log.activityEvent.reset()
|
||||
log.flowEvent.reset()
|
||||
})
|
||||
})
|
||||
log.activityEvent.reset()
|
||||
log.flowEvent.reset()
|
||||
})
|
||||
})
|
||||
|
||||
test('events.emit with content server account.signed event', t => {
|
||||
const request = {
|
||||
query: {
|
||||
service: 'content-server'
|
||||
it('.emit with content server account.signed event', () => {
|
||||
const request = {
|
||||
query: {
|
||||
service: 'content-server'
|
||||
}
|
||||
}
|
||||
}
|
||||
const data = {}
|
||||
return events.emit.call(request, 'account.signed', data)
|
||||
.then(() => {
|
||||
t.equal(log.activityEvent.callCount, 1, 'log.activityEvent was called once')
|
||||
t.equal(log.flowEvent.callCount, 0, 'log.flowEvent was not called')
|
||||
const data = {}
|
||||
return events.emit.call(request, 'account.signed', data)
|
||||
.then(() => {
|
||||
assert.equal(log.activityEvent.callCount, 1, 'log.activityEvent was called once')
|
||||
assert.equal(log.flowEvent.callCount, 0, 'log.flowEvent was not called')
|
||||
|
||||
log.activityEvent.reset()
|
||||
})
|
||||
})
|
||||
log.activityEvent.reset()
|
||||
})
|
||||
})
|
||||
|
||||
test('events.emit with sync account.signed event', t => {
|
||||
const request = {
|
||||
query: {
|
||||
service: 'sync'
|
||||
it('.emit with sync account.signed event', () => {
|
||||
const request = {
|
||||
query: {
|
||||
service: 'sync'
|
||||
}
|
||||
}
|
||||
}
|
||||
const data = {}
|
||||
return events.emit.call(request, 'account.signed', data)
|
||||
.then(() => {
|
||||
t.equal(log.activityEvent.callCount, 1, 'log.activityEvent was called once')
|
||||
t.equal(log.flowEvent.callCount, 1, 'log.flowEvent was called once')
|
||||
const data = {}
|
||||
return events.emit.call(request, 'account.signed', data)
|
||||
.then(() => {
|
||||
assert.equal(log.activityEvent.callCount, 1, 'log.activityEvent was called once')
|
||||
assert.equal(log.flowEvent.callCount, 1, 'log.flowEvent was called once')
|
||||
|
||||
log.activityEvent.reset()
|
||||
log.flowEvent.reset()
|
||||
})
|
||||
log.activityEvent.reset()
|
||||
log.flowEvent.reset()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
|
|
|
@ -2,10 +2,10 @@
|
|||
* 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/. */
|
||||
|
||||
const assert = require('insist')
|
||||
var sinon = require('sinon')
|
||||
|
||||
var P = require('../../lib/promise')
|
||||
var test = require('../ptaptest')
|
||||
var mockLog = require('../mocks').mockLog()
|
||||
var config = {}
|
||||
var Password = require('../../lib/crypto/password')(mockLog, config)
|
||||
|
@ -28,106 +28,108 @@ var CLIENT_ADDRESS = '10.0.0.1'
|
|||
|
||||
var checkPassword = require('../../lib/routes/utils/password_check')(mockLog, config, Password, MockCustoms, MockDB)
|
||||
|
||||
test(
|
||||
'password check with correct password',
|
||||
function (t) {
|
||||
var authPW = new Buffer('aaaaaaaaaaaaaaaa')
|
||||
var emailRecord = {
|
||||
uid: 'correct_password',
|
||||
verifyHash: null,
|
||||
verifierVersion: 0,
|
||||
authSalt: new Buffer('bbbbbbbbbbbbbbbb')
|
||||
describe('password_check', () => {
|
||||
it(
|
||||
'should check with correct password',
|
||||
() => {
|
||||
var authPW = new Buffer('aaaaaaaaaaaaaaaa')
|
||||
var emailRecord = {
|
||||
uid: 'correct_password',
|
||||
verifyHash: null,
|
||||
verifierVersion: 0,
|
||||
authSalt: new Buffer('bbbbbbbbbbbbbbbb')
|
||||
}
|
||||
MockCustoms.flag.reset()
|
||||
|
||||
var password = new Password(
|
||||
authPW, emailRecord.authSalt, emailRecord.verifierVersion)
|
||||
|
||||
return password.verifyHash()
|
||||
.then(
|
||||
function (hash) {
|
||||
emailRecord.verifyHash = hash
|
||||
|
||||
return checkPassword(emailRecord, authPW, CLIENT_ADDRESS)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (matches) {
|
||||
assert.ok(matches, 'password matches, checkPassword returns true')
|
||||
assert.equal(MockCustoms.flag.callCount, 0, 'customs.flag was not called')
|
||||
}
|
||||
)
|
||||
}
|
||||
MockCustoms.flag.reset()
|
||||
)
|
||||
|
||||
var password = new Password(
|
||||
authPW, emailRecord.authSalt, emailRecord.verifierVersion)
|
||||
it(
|
||||
'should return false when check with incorrect password',
|
||||
() => {
|
||||
var authPW = new Buffer('aaaaaaaaaaaaaaaa')
|
||||
var emailRecord = {
|
||||
uid: 'uid',
|
||||
email: 'test@example.com',
|
||||
verifyHash: null,
|
||||
verifierVersion: 0,
|
||||
authSalt: new Buffer('bbbbbbbbbbbbbbbb')
|
||||
}
|
||||
MockCustoms.flag.reset()
|
||||
|
||||
return password.verifyHash()
|
||||
.then(
|
||||
function (hash) {
|
||||
emailRecord.verifyHash = hash
|
||||
var password = new Password(
|
||||
authPW, emailRecord.authSalt, emailRecord.verifierVersion)
|
||||
|
||||
return checkPassword(emailRecord, authPW, CLIENT_ADDRESS)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (matches) {
|
||||
t.ok(matches, 'password matches, checkPassword returns true')
|
||||
t.equal(MockCustoms.flag.callCount, 0, 'customs.flag was not called')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
return password.verifyHash()
|
||||
.then(
|
||||
function (hash) {
|
||||
emailRecord.verifyHash = hash
|
||||
|
||||
test(
|
||||
'password check with incorrect password',
|
||||
function (t) {
|
||||
var authPW = new Buffer('aaaaaaaaaaaaaaaa')
|
||||
var emailRecord = {
|
||||
uid: 'uid',
|
||||
email: 'test@example.com',
|
||||
verifyHash: null,
|
||||
verifierVersion: 0,
|
||||
authSalt: new Buffer('bbbbbbbbbbbbbbbb')
|
||||
var incorrectAuthPW = new Buffer('cccccccccccccccc')
|
||||
|
||||
return checkPassword(emailRecord, incorrectAuthPW, CLIENT_ADDRESS)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (match) {
|
||||
assert.equal(!!match, false, 'password does not match, checkPassword returns false')
|
||||
assert.equal(MockCustoms.flag.callCount, 1, 'customs.flag was called')
|
||||
assert.equal(MockCustoms.flag.getCall(0).args[0], CLIENT_ADDRESS, 'customs.flag was called with client ip')
|
||||
assert.deepEqual(MockCustoms.flag.getCall(0).args[1], {
|
||||
email: emailRecord.email,
|
||||
errno: error.ERRNO.INCORRECT_PASSWORD
|
||||
}, 'customs.flag was called with correct event details')
|
||||
}
|
||||
)
|
||||
}
|
||||
MockCustoms.flag.reset()
|
||||
)
|
||||
|
||||
var password = new Password(
|
||||
authPW, emailRecord.authSalt, emailRecord.verifierVersion)
|
||||
it(
|
||||
'should error when check with account whose password must be reset',
|
||||
() => {
|
||||
var emailRecord = {
|
||||
uid: 'must_reset',
|
||||
email: 'test@example.com',
|
||||
verifyHash: null,
|
||||
verifierVersion: 0,
|
||||
authSalt: butil.ONES
|
||||
}
|
||||
MockCustoms.flag.reset()
|
||||
|
||||
return password.verifyHash()
|
||||
.then(
|
||||
function (hash) {
|
||||
emailRecord.verifyHash = hash
|
||||
var incorrectAuthPW = new Buffer('cccccccccccccccc')
|
||||
|
||||
var incorrectAuthPW = new Buffer('cccccccccccccccc')
|
||||
|
||||
return checkPassword(emailRecord, incorrectAuthPW, CLIENT_ADDRESS)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (match) {
|
||||
t.equal(!!match, false, 'password does not match, checkPassword returns false')
|
||||
t.equal(MockCustoms.flag.callCount, 1, 'customs.flag was called')
|
||||
t.equal(MockCustoms.flag.getCall(0).args[0], CLIENT_ADDRESS, 'customs.flag was called with client ip')
|
||||
t.deepEqual(MockCustoms.flag.getCall(0).args[1], {
|
||||
email: emailRecord.email,
|
||||
errno: error.ERRNO.INCORRECT_PASSWORD
|
||||
}, 'customs.flag was called with correct event details')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'password check with account whose password must be reset',
|
||||
function (t) {
|
||||
var emailRecord = {
|
||||
uid: 'must_reset',
|
||||
email: 'test@example.com',
|
||||
verifyHash: null,
|
||||
verifierVersion: 0,
|
||||
authSalt: butil.ONES
|
||||
return checkPassword(emailRecord, incorrectAuthPW, CLIENT_ADDRESS)
|
||||
.then(
|
||||
function (match) {
|
||||
assert(false, 'password check should not have succeeded')
|
||||
},
|
||||
function (err) {
|
||||
assert.equal(err.errno, error.ERRNO.ACCOUNT_RESET, 'an ACCOUNT_RESET error was thrown')
|
||||
assert.equal(MockCustoms.flag.callCount, 1, 'customs.flag was called')
|
||||
assert.equal(MockCustoms.flag.getCall(0).args[0], CLIENT_ADDRESS, 'customs.flag was called with client ip')
|
||||
assert.deepEqual(MockCustoms.flag.getCall(0).args[1], {
|
||||
email: emailRecord.email,
|
||||
errno: error.ERRNO.ACCOUNT_RESET
|
||||
}, 'customs.flag was called with correct event details')
|
||||
}
|
||||
)
|
||||
}
|
||||
MockCustoms.flag.reset()
|
||||
|
||||
var incorrectAuthPW = new Buffer('cccccccccccccccc')
|
||||
|
||||
return checkPassword(emailRecord, incorrectAuthPW, CLIENT_ADDRESS)
|
||||
.then(
|
||||
function (match) {
|
||||
t.fail('password check should not have succeeded')
|
||||
},
|
||||
function (err) {
|
||||
t.equal(err.errno, error.ERRNO.ACCOUNT_RESET, 'an ACCOUNT_RESET error was thrown')
|
||||
t.equal(MockCustoms.flag.callCount, 1, 'customs.flag was called')
|
||||
t.equal(MockCustoms.flag.getCall(0).args[0], CLIENT_ADDRESS, 'customs.flag was called with client ip')
|
||||
t.deepEqual(MockCustoms.flag.getCall(0).args[1], {
|
||||
email: emailRecord.email,
|
||||
errno: error.ERRNO.ACCOUNT_RESET
|
||||
}, 'customs.flag was called with correct event details')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
)
|
||||
})
|
||||
|
|
|
@ -2,7 +2,9 @@
|
|||
* 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/. */
|
||||
|
||||
var test = require('../ptaptest')
|
||||
'use strict'
|
||||
|
||||
const assert = require('insist')
|
||||
var mocks = require('../mocks')
|
||||
var getRoute = require('../routes_helpers').getRoute
|
||||
|
||||
|
@ -16,7 +18,7 @@ const log = require('../../lib/log')
|
|||
|
||||
var TEST_EMAIL = 'foo@gmail.com'
|
||||
|
||||
var makeRoutes = function (options) {
|
||||
function makeRoutes(options) {
|
||||
options = options || {}
|
||||
|
||||
var config = options.config || {
|
||||
|
@ -43,246 +45,248 @@ var makeRoutes = function (options) {
|
|||
)
|
||||
}
|
||||
|
||||
test(
|
||||
'/password/forgot/send_code',
|
||||
function (t) {
|
||||
var mockCustoms = mocks.mockCustoms()
|
||||
var uid = uuid.v4('binary')
|
||||
var mockDB = mocks.mockDB({
|
||||
email: TEST_EMAIL,
|
||||
passCode: 'foo',
|
||||
passwordForgotTokenId: crypto.randomBytes(16),
|
||||
uid: uid
|
||||
})
|
||||
var mockMailer = mocks.mockMailer()
|
||||
var mockMetricsContext = mocks.mockMetricsContext()
|
||||
var mockLog = log('ERROR', 'test', {
|
||||
stdout: {
|
||||
on: sinon.spy(),
|
||||
write: sinon.spy()
|
||||
},
|
||||
stderr: {
|
||||
on: sinon.spy(),
|
||||
write: sinon.spy()
|
||||
}
|
||||
})
|
||||
mockLog.flowEvent = sinon.spy(() => {
|
||||
return P.resolve()
|
||||
})
|
||||
var passwordRoutes = makeRoutes({
|
||||
customs: mockCustoms,
|
||||
db: mockDB,
|
||||
mailer : mockMailer,
|
||||
metricsContext: mockMetricsContext,
|
||||
log: mockLog
|
||||
})
|
||||
|
||||
var mockRequest = mocks.mockRequest({
|
||||
log: mockLog,
|
||||
payload: {
|
||||
email: TEST_EMAIL
|
||||
},
|
||||
query: {},
|
||||
metricsContext: mockMetricsContext
|
||||
})
|
||||
return new P(function(resolve) {
|
||||
getRoute(passwordRoutes, '/password/forgot/send_code')
|
||||
.handler(mockRequest, resolve)
|
||||
})
|
||||
.then(function(response) {
|
||||
t.equal(mockDB.emailRecord.callCount, 1, 'db.emailRecord was called once')
|
||||
|
||||
t.equal(mockDB.createPasswordForgotToken.callCount, 1, 'db.createPasswordForgotToken was called once')
|
||||
var args = mockDB.createPasswordForgotToken.args[0]
|
||||
t.equal(args.length, 1, 'db.createPasswordForgotToken was passed one argument')
|
||||
t.deepEqual(args[0].uid, uid, 'db.createPasswordForgotToken was passed the correct uid')
|
||||
t.equal(args[0].createdAt, undefined, 'db.createPasswordForgotToken was not passed a createdAt timestamp')
|
||||
|
||||
t.equal(mockRequest.validateMetricsContext.callCount, 1, 'validateMetricsContext was called')
|
||||
t.equal(mockLog.flowEvent.callCount, 2, 'log.flowEvent was called twice')
|
||||
t.equal(mockLog.flowEvent.args[0][0], 'password.forgot.send_code.start', 'password.forgot.send_code.start event was logged')
|
||||
t.equal(mockLog.flowEvent.args[1][0], 'password.forgot.send_code.completed', 'password.forgot.send_code.completed event was logged')
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'/password/forgot/resend_code',
|
||||
function (t) {
|
||||
var mockCustoms = mocks.mockCustoms()
|
||||
var uid = uuid.v4('binary')
|
||||
var mockDB = mocks.mockDB()
|
||||
var mockMailer = mocks.mockMailer()
|
||||
var mockMetricsContext = mocks.mockMetricsContext()
|
||||
var mockLog = log('ERROR', 'test', {
|
||||
stdout: {
|
||||
on: sinon.spy(),
|
||||
write: sinon.spy()
|
||||
},
|
||||
stderr: {
|
||||
on: sinon.spy(),
|
||||
write: sinon.spy()
|
||||
}
|
||||
})
|
||||
mockLog.flowEvent = sinon.spy(() => {
|
||||
return P.resolve()
|
||||
})
|
||||
var passwordRoutes = makeRoutes({
|
||||
customs: mockCustoms,
|
||||
db: mockDB,
|
||||
mailer : mockMailer,
|
||||
metricsContext: mockMetricsContext,
|
||||
log: mockLog
|
||||
})
|
||||
|
||||
var mockRequest = mocks.mockRequest({
|
||||
credentials: {
|
||||
data: crypto.randomBytes(16),
|
||||
describe('/password', () => {
|
||||
it(
|
||||
'/forgot/send_code',
|
||||
() => {
|
||||
var mockCustoms = mocks.mockCustoms()
|
||||
var uid = uuid.v4('binary')
|
||||
var mockDB = mocks.mockDB({
|
||||
email: TEST_EMAIL,
|
||||
passCode: Buffer('abcdef', 'hex'),
|
||||
ttl: function () { return 17 },
|
||||
passCode: 'foo',
|
||||
passwordForgotTokenId: crypto.randomBytes(16),
|
||||
uid: uid
|
||||
},
|
||||
log: mockLog,
|
||||
payload: {
|
||||
email: TEST_EMAIL
|
||||
},
|
||||
query: {},
|
||||
metricsContext: mockMetricsContext
|
||||
})
|
||||
return new P(function(resolve) {
|
||||
getRoute(passwordRoutes, '/password/forgot/resend_code')
|
||||
.handler(mockRequest, resolve)
|
||||
})
|
||||
.then(function(response) {
|
||||
t.equal(mockMailer.sendRecoveryCode.callCount, 1, 'mailer.sendRecoveryCode was called once')
|
||||
|
||||
t.equal(mockRequest.validateMetricsContext.callCount, 1, 'validateMetricsContext was called')
|
||||
t.equal(mockLog.flowEvent.callCount, 2, 'log.flowEvent was called twice')
|
||||
t.equal(mockLog.flowEvent.args[0][0], 'password.forgot.resend_code.start', 'password.forgot.resend_code.start event was logged')
|
||||
t.equal(mockLog.flowEvent.args[1][0], 'password.forgot.resend_code.completed', 'password.forgot.resend_code.completed event was logged')
|
||||
})
|
||||
}
|
||||
)
|
||||
var mockMailer = mocks.mockMailer()
|
||||
var mockMetricsContext = mocks.mockMetricsContext()
|
||||
var mockLog = log('ERROR', 'test', {
|
||||
stdout: {
|
||||
on: sinon.spy(),
|
||||
write: sinon.spy()
|
||||
},
|
||||
stderr: {
|
||||
on: sinon.spy(),
|
||||
write: sinon.spy()
|
||||
}
|
||||
})
|
||||
mockLog.flowEvent = sinon.spy(() => {
|
||||
return P.resolve()
|
||||
})
|
||||
var passwordRoutes = makeRoutes({
|
||||
customs: mockCustoms,
|
||||
db: mockDB,
|
||||
mailer : mockMailer,
|
||||
metricsContext: mockMetricsContext,
|
||||
log: mockLog
|
||||
})
|
||||
|
||||
test(
|
||||
'/password/forgot/verify_code',
|
||||
function (t) {
|
||||
var mockCustoms = mocks.mockCustoms()
|
||||
var uid = uuid.v4('binary')
|
||||
var accountResetToken = {
|
||||
data: crypto.randomBytes(16)
|
||||
var mockRequest = mocks.mockRequest({
|
||||
log: mockLog,
|
||||
payload: {
|
||||
email: TEST_EMAIL
|
||||
},
|
||||
query: {},
|
||||
metricsContext: mockMetricsContext
|
||||
})
|
||||
return new P(function(resolve) {
|
||||
getRoute(passwordRoutes, '/password/forgot/send_code')
|
||||
.handler(mockRequest, resolve)
|
||||
})
|
||||
.then(function(response) {
|
||||
assert.equal(mockDB.emailRecord.callCount, 1, 'db.emailRecord was called once')
|
||||
|
||||
assert.equal(mockDB.createPasswordForgotToken.callCount, 1, 'db.createPasswordForgotToken was called once')
|
||||
var args = mockDB.createPasswordForgotToken.args[0]
|
||||
assert.equal(args.length, 1, 'db.createPasswordForgotToken was passed one argument')
|
||||
assert.deepEqual(args[0].uid, uid, 'db.createPasswordForgotToken was passed the correct uid')
|
||||
assert.equal(args[0].createdAt, undefined, 'db.createPasswordForgotToken was not passed a createdAt timestamp')
|
||||
|
||||
assert.equal(mockRequest.validateMetricsContext.callCount, 1, 'validateMetricsContext was called')
|
||||
assert.equal(mockLog.flowEvent.callCount, 2, 'log.flowEvent was called twice')
|
||||
assert.equal(mockLog.flowEvent.args[0][0], 'password.forgot.send_code.start', 'password.forgot.send_code.start event was logged')
|
||||
assert.equal(mockLog.flowEvent.args[1][0], 'password.forgot.send_code.completed', 'password.forgot.send_code.completed event was logged')
|
||||
})
|
||||
}
|
||||
var mockDB = mocks.mockDB({
|
||||
accountResetToken: accountResetToken,
|
||||
email: TEST_EMAIL,
|
||||
passCode: 'abcdef',
|
||||
passwordForgotTokenId: crypto.randomBytes(16),
|
||||
uid: uid
|
||||
})
|
||||
var mockMailer = mocks.mockMailer()
|
||||
var mockMetricsContext = mocks.mockMetricsContext()
|
||||
var mockLog = log('ERROR', 'test', {
|
||||
stdout: {
|
||||
on: sinon.spy(),
|
||||
write: sinon.spy()
|
||||
},
|
||||
stderr: {
|
||||
on: sinon.spy(),
|
||||
write: sinon.spy()
|
||||
}
|
||||
})
|
||||
mockLog.flowEvent = sinon.spy(() => {
|
||||
return P.resolve()
|
||||
})
|
||||
var passwordRoutes = makeRoutes({
|
||||
customs: mockCustoms,
|
||||
db: mockDB,
|
||||
mailer: mockMailer,
|
||||
metricsContext: mockMetricsContext
|
||||
})
|
||||
)
|
||||
|
||||
var mockRequest = mocks.mockRequest({
|
||||
log: mockLog,
|
||||
credentials: {
|
||||
email: TEST_EMAIL,
|
||||
passCode: Buffer('abcdef', 'hex'),
|
||||
ttl: function () { return 17 },
|
||||
uid: uid
|
||||
},
|
||||
payload: {
|
||||
code: 'abcdef'
|
||||
},
|
||||
query: {}
|
||||
})
|
||||
return new P(function(resolve) {
|
||||
getRoute(passwordRoutes, '/password/forgot/verify_code')
|
||||
.handler(mockRequest, resolve)
|
||||
})
|
||||
.then(function(response) {
|
||||
t.deepEqual(Object.keys(response), ['accountResetToken'], 'an accountResetToken was returned')
|
||||
t.equal(response.accountResetToken, accountResetToken.data.toString('hex'), 'correct accountResetToken was returned')
|
||||
it(
|
||||
'/forgot/resend_code',
|
||||
() => {
|
||||
var mockCustoms = mocks.mockCustoms()
|
||||
var uid = uuid.v4('binary')
|
||||
var mockDB = mocks.mockDB()
|
||||
var mockMailer = mocks.mockMailer()
|
||||
var mockMetricsContext = mocks.mockMetricsContext()
|
||||
var mockLog = log('ERROR', 'test', {
|
||||
stdout: {
|
||||
on: sinon.spy(),
|
||||
write: sinon.spy()
|
||||
},
|
||||
stderr: {
|
||||
on: sinon.spy(),
|
||||
write: sinon.spy()
|
||||
}
|
||||
})
|
||||
mockLog.flowEvent = sinon.spy(() => {
|
||||
return P.resolve()
|
||||
})
|
||||
var passwordRoutes = makeRoutes({
|
||||
customs: mockCustoms,
|
||||
db: mockDB,
|
||||
mailer : mockMailer,
|
||||
metricsContext: mockMetricsContext,
|
||||
log: mockLog
|
||||
})
|
||||
|
||||
t.equal(mockCustoms.check.callCount, 1, 'customs.check was called once')
|
||||
var mockRequest = mocks.mockRequest({
|
||||
credentials: {
|
||||
data: crypto.randomBytes(16),
|
||||
email: TEST_EMAIL,
|
||||
passCode: Buffer('abcdef', 'hex'),
|
||||
ttl: function () { return 17 },
|
||||
uid: uid
|
||||
},
|
||||
log: mockLog,
|
||||
payload: {
|
||||
email: TEST_EMAIL
|
||||
},
|
||||
query: {},
|
||||
metricsContext: mockMetricsContext
|
||||
})
|
||||
return new P(function(resolve) {
|
||||
getRoute(passwordRoutes, '/password/forgot/resend_code')
|
||||
.handler(mockRequest, resolve)
|
||||
})
|
||||
.then(function(response) {
|
||||
assert.equal(mockMailer.sendRecoveryCode.callCount, 1, 'mailer.sendRecoveryCode was called once')
|
||||
|
||||
t.equal(mockDB.forgotPasswordVerified.callCount, 1, 'db.passwordForgotVerified was called once')
|
||||
var args = mockDB.forgotPasswordVerified.args[0]
|
||||
t.equal(args.length, 1, 'db.passwordForgotVerified was passed one argument')
|
||||
t.deepEqual(args[0].uid, uid, 'db.forgotPasswordVerified was passed the correct token')
|
||||
|
||||
t.equal(mockRequest.validateMetricsContext.callCount, 1, 'validateMetricsContext was called')
|
||||
t.equal(mockLog.flowEvent.callCount, 2, 'log.flowEvent was called twice')
|
||||
t.equal(mockLog.flowEvent.args[0][0], 'password.forgot.verify_code.start', 'password.forgot.verify_code.start event was logged')
|
||||
t.equal(mockLog.flowEvent.args[1][0], 'password.forgot.verify_code.completed', 'password.forgot.verify_code.completed event was logged')
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'/password/change/finish',
|
||||
function (t) {
|
||||
var uid = uuid.v4('binary')
|
||||
var mockRequest = mocks.mockRequest({
|
||||
credentials: {
|
||||
uid: uid.toString('hex')
|
||||
},
|
||||
payload: {
|
||||
authPW: crypto.randomBytes(32).toString('hex'),
|
||||
wrapKb: crypto.randomBytes(32).toString('hex'),
|
||||
sessionToken: crypto.randomBytes(32).toString('hex')
|
||||
},
|
||||
query: {
|
||||
keys: 'true'
|
||||
}
|
||||
})
|
||||
var mockDB = mocks.mockDB({
|
||||
email: TEST_EMAIL,
|
||||
uid: uid
|
||||
})
|
||||
var mockPush = mocks.mockPush()
|
||||
var mockMailer = mocks.mockMailer()
|
||||
var passwordRoutes = makeRoutes({
|
||||
db: mockDB,
|
||||
push: mockPush,
|
||||
mailer: mockMailer
|
||||
})
|
||||
|
||||
return new P(function(resolve) {
|
||||
getRoute(passwordRoutes, '/password/change/finish')
|
||||
.handler(mockRequest, function(response) {
|
||||
resolve(response)
|
||||
assert.equal(mockRequest.validateMetricsContext.callCount, 1, 'validateMetricsContext was called')
|
||||
assert.equal(mockLog.flowEvent.callCount, 2, 'log.flowEvent was called twice')
|
||||
assert.equal(mockLog.flowEvent.args[0][0], 'password.forgot.resend_code.start', 'password.forgot.resend_code.start event was logged')
|
||||
assert.equal(mockLog.flowEvent.args[1][0], 'password.forgot.resend_code.completed', 'password.forgot.resend_code.completed event was logged')
|
||||
})
|
||||
})
|
||||
.then(function(response) {
|
||||
t.equal(mockDB.deletePasswordChangeToken.callCount, 1)
|
||||
t.equal(mockDB.resetAccount.callCount, 1)
|
||||
}
|
||||
)
|
||||
|
||||
t.equal(mockPush.notifyPasswordChanged.callCount, 1)
|
||||
t.equal(mockPush.notifyPasswordChanged.firstCall.args[0], uid.toString('hex'))
|
||||
it(
|
||||
'/forgot/verify_code',
|
||||
() => {
|
||||
var mockCustoms = mocks.mockCustoms()
|
||||
var uid = uuid.v4('binary')
|
||||
var accountResetToken = {
|
||||
data: crypto.randomBytes(16)
|
||||
}
|
||||
var mockDB = mocks.mockDB({
|
||||
accountResetToken: accountResetToken,
|
||||
email: TEST_EMAIL,
|
||||
passCode: 'abcdef',
|
||||
passwordForgotTokenId: crypto.randomBytes(16),
|
||||
uid: uid
|
||||
})
|
||||
var mockMailer = mocks.mockMailer()
|
||||
var mockMetricsContext = mocks.mockMetricsContext()
|
||||
var mockLog = log('ERROR', 'test', {
|
||||
stdout: {
|
||||
on: sinon.spy(),
|
||||
write: sinon.spy()
|
||||
},
|
||||
stderr: {
|
||||
on: sinon.spy(),
|
||||
write: sinon.spy()
|
||||
}
|
||||
})
|
||||
mockLog.flowEvent = sinon.spy(() => {
|
||||
return P.resolve()
|
||||
})
|
||||
var passwordRoutes = makeRoutes({
|
||||
customs: mockCustoms,
|
||||
db: mockDB,
|
||||
mailer: mockMailer,
|
||||
metricsContext: mockMetricsContext
|
||||
})
|
||||
|
||||
t.equal(mockDB.account.callCount, 1)
|
||||
t.equal(mockMailer.sendPasswordChangedNotification.callCount, 1)
|
||||
t.equal(mockMailer.sendPasswordChangedNotification.firstCall.args[0], TEST_EMAIL)
|
||||
})
|
||||
}
|
||||
)
|
||||
var mockRequest = mocks.mockRequest({
|
||||
log: mockLog,
|
||||
credentials: {
|
||||
email: TEST_EMAIL,
|
||||
passCode: Buffer('abcdef', 'hex'),
|
||||
ttl: function () { return 17 },
|
||||
uid: uid
|
||||
},
|
||||
payload: {
|
||||
code: 'abcdef'
|
||||
},
|
||||
query: {}
|
||||
})
|
||||
return new P(function(resolve) {
|
||||
getRoute(passwordRoutes, '/password/forgot/verify_code')
|
||||
.handler(mockRequest, resolve)
|
||||
})
|
||||
.then(function(response) {
|
||||
assert.deepEqual(Object.keys(response), ['accountResetToken'], 'an accountResetToken was returned')
|
||||
assert.equal(response.accountResetToken, accountResetToken.data.toString('hex'), 'correct accountResetToken was returned')
|
||||
|
||||
assert.equal(mockCustoms.check.callCount, 1, 'customs.check was called once')
|
||||
|
||||
assert.equal(mockDB.forgotPasswordVerified.callCount, 1, 'db.passwordForgotVerified was called once')
|
||||
var args = mockDB.forgotPasswordVerified.args[0]
|
||||
assert.equal(args.length, 1, 'db.passwordForgotVerified was passed one argument')
|
||||
assert.deepEqual(args[0].uid, uid, 'db.forgotPasswordVerified was passed the correct token')
|
||||
|
||||
assert.equal(mockRequest.validateMetricsContext.callCount, 1, 'validateMetricsContext was called')
|
||||
assert.equal(mockLog.flowEvent.callCount, 2, 'log.flowEvent was called twice')
|
||||
assert.equal(mockLog.flowEvent.args[0][0], 'password.forgot.verify_code.start', 'password.forgot.verify_code.start event was logged')
|
||||
assert.equal(mockLog.flowEvent.args[1][0], 'password.forgot.verify_code.completed', 'password.forgot.verify_code.completed event was logged')
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
it(
|
||||
'/change/finish',
|
||||
() => {
|
||||
var uid = uuid.v4('binary')
|
||||
var mockRequest = mocks.mockRequest({
|
||||
credentials: {
|
||||
uid: uid.toString('hex')
|
||||
},
|
||||
payload: {
|
||||
authPW: crypto.randomBytes(32).toString('hex'),
|
||||
wrapKb: crypto.randomBytes(32).toString('hex'),
|
||||
sessionToken: crypto.randomBytes(32).toString('hex')
|
||||
},
|
||||
query: {
|
||||
keys: 'true'
|
||||
}
|
||||
})
|
||||
var mockDB = mocks.mockDB({
|
||||
email: TEST_EMAIL,
|
||||
uid: uid
|
||||
})
|
||||
var mockPush = mocks.mockPush()
|
||||
var mockMailer = mocks.mockMailer()
|
||||
var passwordRoutes = makeRoutes({
|
||||
db: mockDB,
|
||||
push: mockPush,
|
||||
mailer: mockMailer
|
||||
})
|
||||
|
||||
return new P(function(resolve) {
|
||||
getRoute(passwordRoutes, '/password/change/finish')
|
||||
.handler(mockRequest, function(response) {
|
||||
resolve(response)
|
||||
})
|
||||
})
|
||||
.then(function(response) {
|
||||
assert.equal(mockDB.deletePasswordChangeToken.callCount, 1)
|
||||
assert.equal(mockDB.resetAccount.callCount, 1)
|
||||
|
||||
assert.equal(mockPush.notifyPasswordChanged.callCount, 1)
|
||||
assert.equal(mockPush.notifyPasswordChanged.firstCall.args[0], uid.toString('hex'))
|
||||
|
||||
assert.equal(mockDB.account.callCount, 1)
|
||||
assert.equal(mockMailer.sendPasswordChangedNotification.callCount, 1)
|
||||
assert.equal(mockMailer.sendPasswordChangedNotification.firstCall.args[0], TEST_EMAIL)
|
||||
})
|
||||
}
|
||||
)
|
||||
})
|
||||
|
|
|
@ -2,85 +2,88 @@
|
|||
* 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/. */
|
||||
|
||||
var test = require('../ptaptest')
|
||||
var log = {}
|
||||
var config = {}
|
||||
var Password = require('../../lib/crypto/password')(log, config)
|
||||
'use strict'
|
||||
|
||||
test(
|
||||
'password version zero',
|
||||
function (t) {
|
||||
var pwd = Buffer('aaaaaaaaaaaaaaaa')
|
||||
var salt = Buffer('bbbbbbbbbbbbbbbb')
|
||||
var p1 = new Password(pwd, salt, 0)
|
||||
t.equal(p1.version, 0, 'should be using version zero')
|
||||
var p2 = new Password(pwd, salt, 0)
|
||||
t.equal(p2.version, 0, 'should be using version zero')
|
||||
return p1.verifyHash()
|
||||
.then(
|
||||
function (hash) {
|
||||
return p2.matches(hash)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (matched) {
|
||||
t.ok(matched, 'identical passwords should match')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
const assert = require('insist')
|
||||
const log = {}
|
||||
const config = {}
|
||||
const Password = require('../../lib/crypto/password')(log, config)
|
||||
|
||||
test(
|
||||
'password version one',
|
||||
function (t) {
|
||||
var pwd = Buffer('aaaaaaaaaaaaaaaa')
|
||||
var salt = Buffer('bbbbbbbbbbbbbbbb')
|
||||
var p1 = new Password(pwd, salt, 1)
|
||||
t.equal(p1.version, 1, 'should be using version one')
|
||||
var p2 = new Password(pwd, salt, 1)
|
||||
t.equal(p2.version, 1, 'should be using version one')
|
||||
return p1.verifyHash()
|
||||
.then(
|
||||
function (hash) {
|
||||
return p2.matches(hash)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (matched) {
|
||||
t.ok(matched, 'identical passwords should match')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
describe('Password', () => {
|
||||
it(
|
||||
'password version zero',
|
||||
() => {
|
||||
var pwd = Buffer('aaaaaaaaaaaaaaaa')
|
||||
var salt = Buffer('bbbbbbbbbbbbbbbb')
|
||||
var p1 = new Password(pwd, salt, 0)
|
||||
assert.equal(p1.version, 0, 'should be using version zero')
|
||||
var p2 = new Password(pwd, salt, 0)
|
||||
assert.equal(p2.version, 0, 'should be using version zero')
|
||||
return p1.verifyHash()
|
||||
.then(
|
||||
function (hash) {
|
||||
return p2.matches(hash)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (matched) {
|
||||
assert.ok(matched, 'identical passwords should match')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'passwords of different versions should not match',
|
||||
function (t) {
|
||||
var pwd = Buffer('aaaaaaaaaaaaaaaa')
|
||||
var salt = Buffer('bbbbbbbbbbbbbbbb')
|
||||
var p1 = new Password(pwd, salt, 0)
|
||||
var p2 = new Password(pwd, salt, 1)
|
||||
return p1.verifyHash()
|
||||
.then(
|
||||
function (hash) {
|
||||
return p2.matches(hash)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (matched) {
|
||||
t.ok(!matched, 'passwords should not match')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
it(
|
||||
'password version one',
|
||||
() => {
|
||||
var pwd = Buffer('aaaaaaaaaaaaaaaa')
|
||||
var salt = Buffer('bbbbbbbbbbbbbbbb')
|
||||
var p1 = new Password(pwd, salt, 1)
|
||||
assert.equal(p1.version, 1, 'should be using version one')
|
||||
var p2 = new Password(pwd, salt, 1)
|
||||
assert.equal(p2.version, 1, 'should be using version one')
|
||||
return p1.verifyHash()
|
||||
.then(
|
||||
function (hash) {
|
||||
return p2.matches(hash)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (matched) {
|
||||
assert.ok(matched, 'identical passwords should match')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'scrypt queue stats can be reported',
|
||||
function (t) {
|
||||
var stat = Password.stat()
|
||||
t.equal(stat.stat, 'scrypt')
|
||||
t.ok(stat.hasOwnProperty('numPending'))
|
||||
t.ok(stat.hasOwnProperty('numPendingHWM'))
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
it(
|
||||
'passwords of different versions should not match',
|
||||
() => {
|
||||
var pwd = Buffer('aaaaaaaaaaaaaaaa')
|
||||
var salt = Buffer('bbbbbbbbbbbbbbbb')
|
||||
var p1 = new Password(pwd, salt, 0)
|
||||
var p2 = new Password(pwd, salt, 1)
|
||||
return p1.verifyHash()
|
||||
.then(
|
||||
function (hash) {
|
||||
return p2.matches(hash)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (matched) {
|
||||
assert.ok(!matched, 'passwords should not match')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
it(
|
||||
'scrypt queue stats can be reported',
|
||||
() => {
|
||||
var stat = Password.stat()
|
||||
assert.equal(stat.stat, 'scrypt')
|
||||
assert.ok(stat.hasOwnProperty('numPending'))
|
||||
assert.ok(stat.hasOwnProperty('numPendingHWM'))
|
||||
}
|
||||
)
|
||||
})
|
||||
|
|
|
@ -2,56 +2,61 @@
|
|||
* 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/. */
|
||||
|
||||
var test = require('../ptaptest')
|
||||
var pbkdf2 = require('../../lib/crypto/pbkdf2')
|
||||
var ITERATIONS = 20000
|
||||
var LENGTH = 32
|
||||
'use strict'
|
||||
|
||||
test(
|
||||
'pbkdf2 derive',
|
||||
function (t) {
|
||||
var salt = Buffer('identity.mozilla.com/picl/v1/first-PBKDF:andré@example.org')
|
||||
var password = Buffer('pässwörd')
|
||||
return pbkdf2.derive(password, salt, ITERATIONS, LENGTH)
|
||||
.then(
|
||||
function (K1) {
|
||||
t.equal(K1.toString('hex'), 'f84913e3d8e6d624689d0a3e9678ac8dcc79d2c2f3d9641488cd9d6ef6cd83dd')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
const assert = require('insist')
|
||||
const pbkdf2 = require('../../lib/crypto/pbkdf2')
|
||||
const ITERATIONS = 20000
|
||||
const LENGTH = 32
|
||||
|
||||
test(
|
||||
'pbkdf2 derive long input',
|
||||
function (t) {
|
||||
var email = Buffer('ijqmkkafer3xsj5rzoq+msnxsacvkmqxabtsvxvj@some-test-domain-with-a-long-name-example.org')
|
||||
var password = Buffer('mSnxsacVkMQxAbtSVxVjCCoWArNUsFhiJqmkkafER3XSJ5rzoQ')
|
||||
var salt = Buffer('identity.mozilla.com/picl/v1/first-PBKDF:' + email)
|
||||
return pbkdf2.derive(password, salt, ITERATIONS, LENGTH)
|
||||
.then(
|
||||
function (K1) {
|
||||
t.equal(K1.toString('hex'), '5f99c22dfac713b6d73094604a05082e6d345f8a00d4947e57105733f51216eb')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
describe('pbkdf2', () => {
|
||||
it(
|
||||
'pbkdf2 derive',
|
||||
() => {
|
||||
var salt = Buffer('identity.mozilla.com/picl/v1/first-PBKDF:andré@example.org')
|
||||
var password = Buffer('pässwörd')
|
||||
return pbkdf2.derive(password, salt, ITERATIONS, LENGTH)
|
||||
.then(
|
||||
function (K1) {
|
||||
assert.equal(K1.toString('hex'), 'f84913e3d8e6d624689d0a3e9678ac8dcc79d2c2f3d9641488cd9d6ef6cd83dd')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'pbkdf2 derive bit array',
|
||||
function (t) {
|
||||
var salt = Buffer('identity.mozilla.com/picl/v1/second-PBKDF:andré@example.org')
|
||||
var K2 = '5b82f146a64126923e4167a0350bb181feba61f63cb1714012b19cb0be0119c5'
|
||||
var passwordString = 'pässwörd'
|
||||
var password = Buffer.concat([
|
||||
Buffer(K2, 'hex'),
|
||||
Buffer(passwordString)
|
||||
])
|
||||
it(
|
||||
'pbkdf2 derive long input',
|
||||
() => {
|
||||
var email = Buffer('ijqmkkafer3xsj5rzoq+msnxsacvkmqxabtsvxvj@some-test-domain-with-a-long-name-example.org')
|
||||
var password = Buffer('mSnxsacVkMQxAbtSVxVjCCoWArNUsFhiJqmkkafER3XSJ5rzoQ')
|
||||
var salt = Buffer('identity.mozilla.com/picl/v1/first-PBKDF:' + email)
|
||||
return pbkdf2.derive(password, salt, ITERATIONS, LENGTH)
|
||||
.then(
|
||||
function (K1) {
|
||||
assert.equal(K1.toString('hex'), '5f99c22dfac713b6d73094604a05082e6d345f8a00d4947e57105733f51216eb')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
return pbkdf2.derive(password, salt, ITERATIONS, LENGTH)
|
||||
.then(
|
||||
function (K1) {
|
||||
t.equal(K1.toString('hex'), 'c16d46c31bee242cb31f916e9e38d60b76431d3f5304549cc75ae4bc20c7108c')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
it(
|
||||
'pbkdf2 derive bit array',
|
||||
() => {
|
||||
var salt = Buffer('identity.mozilla.com/picl/v1/second-PBKDF:andré@example.org')
|
||||
var K2 = '5b82f146a64126923e4167a0350bb181feba61f63cb1714012b19cb0be0119c5'
|
||||
var passwordString = 'pässwörd'
|
||||
var password = Buffer.concat([
|
||||
Buffer(K2, 'hex'),
|
||||
Buffer(passwordString)
|
||||
])
|
||||
|
||||
return pbkdf2.derive(password, salt, ITERATIONS, LENGTH)
|
||||
.then(
|
||||
function (K1) {
|
||||
assert.equal(K1.toString('hex'), 'c16d46c31bee242cb31f916e9e38d60b76431d3f5304549cc75ae4bc20c7108c')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
})
|
||||
|
|
|
@ -2,297 +2,258 @@
|
|||
* 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/. */
|
||||
|
||||
var test = require('../ptaptest')
|
||||
var sinon = require('sinon')
|
||||
var proxyquire = require('proxyquire')
|
||||
var Pool, poolee
|
||||
'use strict'
|
||||
|
||||
test(
|
||||
'pool.request with default options',
|
||||
function (t) {
|
||||
setup()
|
||||
const assert = require('insist')
|
||||
const sinon = require('sinon')
|
||||
const proxyquire = require('proxyquire')
|
||||
|
||||
var pool = new Pool('http://example.com/ignore/me')
|
||||
pool.request()
|
||||
describe('Pool', () => {
|
||||
|
||||
t.equal(poolee.request.callCount, 1, 'poolee.request was called once')
|
||||
let Pool, poolee
|
||||
|
||||
var args = poolee.request.getCall(0).args
|
||||
t.equal(args.length, 2, 'poolee.request was passed two arguments')
|
||||
|
||||
var options = args[0]
|
||||
t.equal(typeof options, 'object', 'options is object')
|
||||
t.equal(Object.keys(options).length, 4, 'options has 4 properties')
|
||||
t.equal(options.method, 'GET', 'options.method is GET')
|
||||
t.equal(options.path, undefined, 'options.path is undefined')
|
||||
t.equal(typeof options.headers, 'object', 'options.headers is object')
|
||||
t.equal(Object.keys(options.headers).length, 1, 'options.headers has 1 property')
|
||||
t.equal(options.headers['Content-Type'], 'application/json', 'Content-Type header is application/json')
|
||||
t.equal(options.data, undefined, 'options.data is undefined')
|
||||
|
||||
var callback = args[1]
|
||||
t.equal(typeof callback, 'function', 'callback is function')
|
||||
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'pool.request with alternative options',
|
||||
function (t) {
|
||||
setup()
|
||||
|
||||
var pool = new Pool('http://example.com/')
|
||||
pool.request('POST', '/foo', { bar: 'baz' })
|
||||
|
||||
t.equal(poolee.request.callCount, 1, 'poolee.request was called once')
|
||||
|
||||
var args = poolee.request.getCall(0).args
|
||||
t.equal(args.length, 2, 'poolee.request was passed two arguments')
|
||||
|
||||
var options = args[0]
|
||||
t.equal(typeof options, 'object', 'options is object')
|
||||
t.equal(Object.keys(options).length, 4, 'options has 4 properties')
|
||||
t.equal(options.method, 'POST', 'options.method is POST')
|
||||
t.equal(options.path, '/foo', 'options.path is /foo')
|
||||
t.equal(typeof options.headers, 'object', 'options.headers is object')
|
||||
t.equal(Object.keys(options.headers).length, 1, 'options.headers has 1 property')
|
||||
t.equal(options.headers['Content-Type'], 'application/json', 'Content-Type header is application/json')
|
||||
t.equal(options.data, '{"bar":"baz"}', 'options.data is correct')
|
||||
|
||||
var callback = args[1]
|
||||
t.equal(typeof callback, 'function', 'callback is function')
|
||||
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'pool.request callback with error',
|
||||
function (t) {
|
||||
setup()
|
||||
|
||||
var pool = new Pool('http://example.com/')
|
||||
pool.request()
|
||||
.then(function () {
|
||||
t.fail('request should have failed')
|
||||
t.end()
|
||||
}, function (error) {
|
||||
t.equal(typeof error, 'string', 'error is string')
|
||||
t.equal(error, 'foo', 'error is correct')
|
||||
t.end()
|
||||
})
|
||||
|
||||
var args = poolee.request.getCall(0).args
|
||||
var callback = args[1]
|
||||
callback('foo')
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'pool.request callback with HTTP error response',
|
||||
function (t) {
|
||||
setup()
|
||||
|
||||
var pool = new Pool('http://example.com/')
|
||||
pool.request()
|
||||
.then(function () {
|
||||
t.fail('request should have failed')
|
||||
t.end()
|
||||
}, function (error) {
|
||||
t.ok(error instanceof Error, 'error is Error instance')
|
||||
t.equal(error.statusCode, 404, 'error.statusCode is 404')
|
||||
t.equal(error.message, 'wibble', 'error.message is correct')
|
||||
t.end()
|
||||
})
|
||||
|
||||
var args = poolee.request.getCall(0).args
|
||||
var callback = args[1]
|
||||
callback(null, { statusCode: 404 }, 'wibble')
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'pool.request callback with HTTP error response and JSON body',
|
||||
function (t) {
|
||||
setup()
|
||||
|
||||
var pool = new Pool('http://example.com/')
|
||||
pool.request()
|
||||
.then(function () {
|
||||
t.fail('request should have failed')
|
||||
t.end()
|
||||
}, function (error) {
|
||||
t.equal(error instanceof Error, false, 'error is not Error instance')
|
||||
t.equal(typeof error, 'object', 'error is object')
|
||||
t.equal(Object.keys(error).length, 2, 'error has two properties')
|
||||
t.equal(error.statusCode, 418, 'error.statusCode is 418')
|
||||
t.equal(error.foo, 'bar', 'other error data is correct')
|
||||
t.end()
|
||||
})
|
||||
|
||||
var args = poolee.request.getCall(0).args
|
||||
var callback = args[1]
|
||||
callback(null, { statusCode: 418 }, '{"foo":"bar"}')
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'pool.request callback with HTTP success response and empty body',
|
||||
function (t) {
|
||||
setup()
|
||||
|
||||
var pool = new Pool('http://example.com/')
|
||||
pool.request()
|
||||
.then(function (result) {
|
||||
t.equal(result, undefined, 'result is undefined')
|
||||
t.end()
|
||||
}, function () {
|
||||
t.fail('request should have succeeded')
|
||||
t.end()
|
||||
})
|
||||
|
||||
var args = poolee.request.getCall(0).args
|
||||
var callback = args[1]
|
||||
callback(null, { statusCode: 200 }, '')
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'pool.request callback with HTTP success response and valid JSON body',
|
||||
function (t) {
|
||||
setup()
|
||||
|
||||
var pool = new Pool('http://example.com/')
|
||||
pool.request()
|
||||
.then(function (result) {
|
||||
t.equal(typeof result, 'object', 'result is object')
|
||||
t.equal(Object.keys(result).length, 1, 'result has 1 property')
|
||||
t.equal(result.foo, 'bar', 'result data is correct')
|
||||
t.end()
|
||||
}, function () {
|
||||
t.fail('request should have succeeded')
|
||||
t.end()
|
||||
})
|
||||
|
||||
var args = poolee.request.getCall(0).args
|
||||
var callback = args[1]
|
||||
callback(null, { statusCode: 200 }, '{"foo":"bar"}')
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'pool.request callback with HTTP success response and invalid JSON body',
|
||||
function (t) {
|
||||
setup()
|
||||
|
||||
var pool = new Pool('http://example.com/')
|
||||
pool.request()
|
||||
.then(function () {
|
||||
t.fail('request should have failed')
|
||||
t.end()
|
||||
}, function (error) {
|
||||
t.ok(error instanceof Error, 'error is Error instance')
|
||||
t.equal(error.statusCode, undefined, 'error.statusCode is undefined')
|
||||
t.equal(error.message, 'Invalid JSON', 'error.message is correct')
|
||||
t.end()
|
||||
})
|
||||
|
||||
var args = poolee.request.getCall(0).args
|
||||
var callback = args[1]
|
||||
callback(null, { statusCode: 200 }, 'foo')
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'pool.get',
|
||||
function (t) {
|
||||
setup()
|
||||
|
||||
var pool = new Pool('http://example.com/')
|
||||
sinon.stub(pool, 'request', function () {})
|
||||
pool.get('foo')
|
||||
|
||||
t.equal(pool.request.callCount, 1, 'pool.request was called once')
|
||||
|
||||
var args = pool.request.getCall(0).args
|
||||
t.equal(args.length, 2, 'pool.request was passed three arguments')
|
||||
t.equal(args[0], 'GET', 'first argument to pool.request was POST')
|
||||
t.equal(args[1], 'foo', 'second argument to pool.request was correct')
|
||||
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'pool.put',
|
||||
function (t) {
|
||||
setup()
|
||||
|
||||
var pool = new Pool('http://example.com/')
|
||||
sinon.stub(pool, 'request', function () {})
|
||||
pool.put('baz', 'qux')
|
||||
|
||||
t.equal(pool.request.callCount, 1, 'pool.request was called once')
|
||||
|
||||
var args = pool.request.getCall(0).args
|
||||
t.equal(args.length, 3, 'pool.request was passed three arguments')
|
||||
t.equal(args[0], 'PUT', 'first argument to pool.request was POST')
|
||||
t.equal(args[1], 'baz', 'second argument to pool.request was correct')
|
||||
t.equal(args[2], 'qux', 'third argument to pool.request was correct')
|
||||
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'pool.post',
|
||||
function (t) {
|
||||
setup()
|
||||
|
||||
var pool = new Pool('http://example.com/')
|
||||
sinon.stub(pool, 'request', function () {})
|
||||
pool.post('foo', 'bar')
|
||||
|
||||
t.equal(pool.request.callCount, 1, 'pool.request was called once')
|
||||
|
||||
var args = pool.request.getCall(0).args
|
||||
t.equal(args.length, 3, 'pool.request was passed three arguments')
|
||||
t.equal(args[0], 'POST', 'first argument to pool.request was POST')
|
||||
t.equal(args[1], 'foo', 'second argument to pool.request was correct')
|
||||
t.equal(args[2], 'bar', 'third argument to pool.request was correct')
|
||||
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'pool.del',
|
||||
function (t) {
|
||||
setup()
|
||||
|
||||
var pool = new Pool('http://example.com/')
|
||||
sinon.stub(pool, 'request', function () {})
|
||||
pool.del('foo', 'bar')
|
||||
|
||||
t.equal(pool.request.callCount, 1, 'pool.request was called once')
|
||||
|
||||
var args = pool.request.getCall(0).args
|
||||
t.equal(args.length, 3, 'pool.request was passed three arguments')
|
||||
t.equal(args[0], 'DELETE', 'first argument to pool.request was POST')
|
||||
t.equal(args[1], 'foo', 'second argument to pool.request was correct')
|
||||
t.equal(args[2], 'bar', 'second argument can be data')
|
||||
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
|
||||
function setup () {
|
||||
poolee = sinon.createStubInstance(require('poolee'))
|
||||
Pool = proxyquire('../../lib/pool', {
|
||||
poolee: function () {
|
||||
return poolee
|
||||
}
|
||||
beforeEach(() => {
|
||||
poolee = sinon.createStubInstance(require('poolee'))
|
||||
Pool = proxyquire('../../lib/pool', {
|
||||
poolee: function () {
|
||||
return poolee
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
it(
|
||||
'pool.request with default options',
|
||||
() => {
|
||||
var pool = new Pool('http://example.com/ignore/me')
|
||||
pool.request()
|
||||
|
||||
assert.equal(poolee.request.callCount, 1, 'poolee.request was called once')
|
||||
|
||||
var args = poolee.request.getCall(0).args
|
||||
assert.equal(args.length, 2, 'poolee.request was passed two arguments')
|
||||
|
||||
var options = args[0]
|
||||
assert.equal(typeof options, 'object', 'options is object')
|
||||
assert.equal(Object.keys(options).length, 4, 'options has 4 properties')
|
||||
assert.equal(options.method, 'GET', 'options.method is GET')
|
||||
assert.equal(options.path, undefined, 'options.path is undefined')
|
||||
assert.equal(typeof options.headers, 'object', 'options.headers is object')
|
||||
assert.equal(Object.keys(options.headers).length, 1, 'options.headers has 1 property')
|
||||
assert.equal(options.headers['Content-Type'], 'application/json', 'Content-Type header is application/json')
|
||||
assert.equal(options.data, undefined, 'options.data is undefined')
|
||||
|
||||
var callback = args[1]
|
||||
assert.equal(typeof callback, 'function', 'callback is function')
|
||||
}
|
||||
)
|
||||
|
||||
it(
|
||||
'pool.request with alternative options',
|
||||
() => {
|
||||
var pool = new Pool('http://example.com/')
|
||||
pool.request('POST', '/foo', { bar: 'baz' })
|
||||
|
||||
assert.equal(poolee.request.callCount, 1, 'poolee.request was called once')
|
||||
|
||||
var args = poolee.request.getCall(0).args
|
||||
assert.equal(args.length, 2, 'poolee.request was passed two arguments')
|
||||
|
||||
var options = args[0]
|
||||
assert.equal(typeof options, 'object', 'options is object')
|
||||
assert.equal(Object.keys(options).length, 4, 'options has 4 properties')
|
||||
assert.equal(options.method, 'POST', 'options.method is POST')
|
||||
assert.equal(options.path, '/foo', 'options.path is /foo')
|
||||
assert.equal(typeof options.headers, 'object', 'options.headers is object')
|
||||
assert.equal(Object.keys(options.headers).length, 1, 'options.headers has 1 property')
|
||||
assert.equal(options.headers['Content-Type'], 'application/json', 'Content-Type header is application/json')
|
||||
assert.equal(options.data, '{"bar":"baz"}', 'options.data is correct')
|
||||
|
||||
var callback = args[1]
|
||||
assert.equal(typeof callback, 'function', 'callback is function')
|
||||
}
|
||||
)
|
||||
|
||||
it(
|
||||
'pool.request callback with error',
|
||||
() => {
|
||||
var pool = new Pool('http://example.com/')
|
||||
let p = pool.request()
|
||||
.then(function () {
|
||||
assert(false, 'request should have failed')
|
||||
}, function (error) {
|
||||
assert.equal(typeof error, 'string', 'error is string')
|
||||
assert.equal(error, 'foo', 'error is correct')
|
||||
})
|
||||
|
||||
var args = poolee.request.getCall(0).args
|
||||
var callback = args[1]
|
||||
callback('foo')
|
||||
return p
|
||||
}
|
||||
)
|
||||
|
||||
it(
|
||||
'pool.request callback with HTTP error response',
|
||||
() => {
|
||||
var pool = new Pool('http://example.com/')
|
||||
let p = pool.request()
|
||||
.then(function () {
|
||||
assert(false, 'request should have failed')
|
||||
}, function (error) {
|
||||
assert.ok(error instanceof Error, 'error is Error instance')
|
||||
assert.equal(error.statusCode, 404, 'error.statusCode is 404')
|
||||
assert.equal(error.message, 'wibble', 'error.message is correct')
|
||||
})
|
||||
|
||||
var args = poolee.request.getCall(0).args
|
||||
var callback = args[1]
|
||||
callback(null, { statusCode: 404 }, 'wibble')
|
||||
return p
|
||||
}
|
||||
)
|
||||
|
||||
it(
|
||||
'pool.request callback with HTTP error response and JSON body',
|
||||
() => {
|
||||
var pool = new Pool('http://example.com/')
|
||||
let p = pool.request()
|
||||
.then(function () {
|
||||
assert(false, 'request should have failed')
|
||||
}, function (error) {
|
||||
assert.equal(error instanceof Error, false, 'error is not Error instance')
|
||||
assert.equal(typeof error, 'object', 'error is object')
|
||||
assert.equal(Object.keys(error).length, 2, 'error has two properties')
|
||||
assert.equal(error.statusCode, 418, 'error.statusCode is 418')
|
||||
assert.equal(error.foo, 'bar', 'other error data is correct')
|
||||
})
|
||||
|
||||
var args = poolee.request.getCall(0).args
|
||||
var callback = args[1]
|
||||
callback(null, { statusCode: 418 }, '{"foo":"bar"}')
|
||||
return p
|
||||
}
|
||||
)
|
||||
|
||||
it(
|
||||
'pool.request callback with HTTP success response and empty body',
|
||||
() => {
|
||||
var pool = new Pool('http://example.com/')
|
||||
let p = pool.request()
|
||||
.then(function (result) {
|
||||
assert.equal(result, undefined, 'result is undefined')
|
||||
})
|
||||
|
||||
var args = poolee.request.getCall(0).args
|
||||
var callback = args[1]
|
||||
callback(null, { statusCode: 200 }, '')
|
||||
return p
|
||||
}
|
||||
)
|
||||
|
||||
it(
|
||||
'pool.request callback with HTTP success response and valid JSON body',
|
||||
() => {
|
||||
var pool = new Pool('http://example.com/')
|
||||
let p = pool.request()
|
||||
.then(function (result) {
|
||||
assert.equal(typeof result, 'object', 'result is object')
|
||||
assert.equal(Object.keys(result).length, 1, 'result has 1 property')
|
||||
assert.equal(result.foo, 'bar', 'result data is correct')
|
||||
})
|
||||
|
||||
var args = poolee.request.getCall(0).args
|
||||
var callback = args[1]
|
||||
callback(null, { statusCode: 200 }, '{"foo":"bar"}')
|
||||
return p
|
||||
}
|
||||
)
|
||||
|
||||
it(
|
||||
'pool.request callback with HTTP success response and invalid JSON body',
|
||||
() => {
|
||||
var pool = new Pool('http://example.com/')
|
||||
let p = pool.request()
|
||||
.then(function () {
|
||||
assert(false, 'request should have failed')
|
||||
}, function (error) {
|
||||
assert.ok(error instanceof Error, 'error is Error instance')
|
||||
assert.equal(error.statusCode, undefined, 'error.statusCode is undefined')
|
||||
assert.equal(error.message, 'Invalid JSON', 'error.message is correct')
|
||||
})
|
||||
|
||||
var args = poolee.request.getCall(0).args
|
||||
var callback = args[1]
|
||||
callback(null, { statusCode: 200 }, 'foo')
|
||||
return p
|
||||
}
|
||||
)
|
||||
|
||||
it(
|
||||
'pool.get',
|
||||
() => {
|
||||
var pool = new Pool('http://example.com/')
|
||||
sinon.stub(pool, 'request', function () {})
|
||||
pool.get('foo')
|
||||
|
||||
assert.equal(pool.request.callCount, 1, 'pool.request was called once')
|
||||
|
||||
var args = pool.request.getCall(0).args
|
||||
assert.equal(args.length, 2, 'pool.request was passed three arguments')
|
||||
assert.equal(args[0], 'GET', 'first argument to pool.request was POST')
|
||||
assert.equal(args[1], 'foo', 'second argument to pool.request was correct')
|
||||
}
|
||||
)
|
||||
|
||||
it(
|
||||
'pool.put',
|
||||
() => {
|
||||
var pool = new Pool('http://example.com/')
|
||||
sinon.stub(pool, 'request', function () {})
|
||||
pool.put('baz', 'qux')
|
||||
|
||||
assert.equal(pool.request.callCount, 1, 'pool.request was called once')
|
||||
|
||||
var args = pool.request.getCall(0).args
|
||||
assert.equal(args.length, 3, 'pool.request was passed three arguments')
|
||||
assert.equal(args[0], 'PUT', 'first argument to pool.request was POST')
|
||||
assert.equal(args[1], 'baz', 'second argument to pool.request was correct')
|
||||
assert.equal(args[2], 'qux', 'third argument to pool.request was correct')
|
||||
}
|
||||
)
|
||||
|
||||
it(
|
||||
'pool.post',
|
||||
() => {
|
||||
var pool = new Pool('http://example.com/')
|
||||
sinon.stub(pool, 'request', function () {})
|
||||
pool.post('foo', 'bar')
|
||||
|
||||
assert.equal(pool.request.callCount, 1, 'pool.request was called once')
|
||||
|
||||
var args = pool.request.getCall(0).args
|
||||
assert.equal(args.length, 3, 'pool.request was passed three arguments')
|
||||
assert.equal(args[0], 'POST', 'first argument to pool.request was POST')
|
||||
assert.equal(args[1], 'foo', 'second argument to pool.request was correct')
|
||||
assert.equal(args[2], 'bar', 'third argument to pool.request was correct')
|
||||
}
|
||||
)
|
||||
|
||||
it(
|
||||
'pool.del',
|
||||
() => {
|
||||
var pool = new Pool('http://example.com/')
|
||||
sinon.stub(pool, 'request', function () {})
|
||||
pool.del('foo', 'bar')
|
||||
|
||||
assert.equal(pool.request.callCount, 1, 'pool.request was called once')
|
||||
|
||||
var args = pool.request.getCall(0).args
|
||||
assert.equal(args.length, 3, 'pool.request was passed three arguments')
|
||||
assert.equal(args[0], 'DELETE', 'first argument to pool.request was POST')
|
||||
assert.equal(args[1], 'foo', 'second argument to pool.request was correct')
|
||||
assert.equal(args[2], 'bar', 'second argument can be data')
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
})
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -4,28 +4,26 @@
|
|||
|
||||
'use strict'
|
||||
|
||||
const test = require('../ptaptest')
|
||||
const assert = require('insist')
|
||||
const requestHelper = require('../../lib/routes/utils/request_helper')
|
||||
|
||||
test(
|
||||
'interface is correct',
|
||||
t => {
|
||||
t.equal(typeof requestHelper, 'object', 'object type should be exported')
|
||||
t.equal(Object.keys(requestHelper).length, 1, 'object should have one properties')
|
||||
t.equal(typeof requestHelper.wantsKeys, 'function', 'wantsKeys should be function')
|
||||
describe('requestHelper', () => {
|
||||
it(
|
||||
'interface is correct',
|
||||
() => {
|
||||
assert.equal(typeof requestHelper, 'object', 'object type should be exported')
|
||||
assert.equal(Object.keys(requestHelper).length, 1, 'object should have one properties')
|
||||
assert.equal(typeof requestHelper.wantsKeys, 'function', 'wantsKeys should be function')
|
||||
}
|
||||
)
|
||||
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'wantsKeys',
|
||||
t => {
|
||||
t.equal(!! requestHelper.wantsKeys({}), false, 'should return falsey if request.query is not set')
|
||||
t.equal(requestHelper.wantsKeys({ query: {} }), false, 'should return false if query.keys is not set')
|
||||
t.equal(requestHelper.wantsKeys({ query: { keys: 'wibble' } }), false, 'should return false if keys is not true')
|
||||
t.equal(requestHelper.wantsKeys({ query: { keys: 'true' } }), true, 'should return true if keys is true')
|
||||
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
it(
|
||||
'wantsKeys',
|
||||
() => {
|
||||
assert.equal(!! requestHelper.wantsKeys({}), false, 'should return falsey if request.query is not set')
|
||||
assert.equal(requestHelper.wantsKeys({ query: {} }), false, 'should return false if query.keys is not set')
|
||||
assert.equal(requestHelper.wantsKeys({ query: { keys: 'wibble' } }), false, 'should return false if keys is not true')
|
||||
assert.equal(requestHelper.wantsKeys({ query: { keys: 'true' } }), true, 'should return true if keys is true')
|
||||
}
|
||||
)
|
||||
})
|
||||
|
|
|
@ -2,7 +2,9 @@
|
|||
* 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/. */
|
||||
|
||||
var test = require('../ptaptest')
|
||||
'use strict'
|
||||
|
||||
const assert = require('insist')
|
||||
var promise = require('../../lib/promise')
|
||||
var config = { scrypt: { maxPending: 5 } }
|
||||
var log = {
|
||||
|
@ -12,43 +14,45 @@ var log = {
|
|||
|
||||
var scrypt = require('../../lib/crypto/scrypt')(log, config)
|
||||
|
||||
test(
|
||||
'scrypt basic',
|
||||
function (t) {
|
||||
var K1 = Buffer('f84913e3d8e6d624689d0a3e9678ac8dcc79d2c2f3d9641488cd9d6ef6cd83dd', 'hex')
|
||||
var salt = Buffer('identity.mozilla.com/picl/v1/scrypt')
|
||||
describe('scrypt', () => {
|
||||
it(
|
||||
'scrypt basic',
|
||||
() => {
|
||||
var K1 = Buffer('f84913e3d8e6d624689d0a3e9678ac8dcc79d2c2f3d9641488cd9d6ef6cd83dd', 'hex')
|
||||
var salt = Buffer('identity.mozilla.com/picl/v1/scrypt')
|
||||
|
||||
return scrypt.hash(K1, salt, 65536, 8, 1, 32)
|
||||
.then(
|
||||
function (K2) {
|
||||
t.equal(K2, '5b82f146a64126923e4167a0350bb181feba61f63cb1714012b19cb0be0119c5')
|
||||
return scrypt.hash(K1, salt, 65536, 8, 1, 32)
|
||||
.then(
|
||||
function (K2) {
|
||||
assert.equal(K2, '5b82f146a64126923e4167a0350bb181feba61f63cb1714012b19cb0be0119c5')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
it(
|
||||
'scrypt enforces maximum number of pending requests',
|
||||
() => {
|
||||
var K1 = Buffer('f84913e3d8e6d624689d0a3e9678ac8dcc79d2c2f3d9641488cd9d6ef6cd83dd', 'hex')
|
||||
var salt = Buffer('identity.mozilla.com/picl/v1/scrypt')
|
||||
// Check the we're using the lower maxPending setting from config.
|
||||
assert.equal(scrypt.maxPending, 5, 'maxPending is correctly set from config')
|
||||
// Send many concurrent requests.
|
||||
// Not yielding the event loop ensures they will pile up quickly.
|
||||
var promises = []
|
||||
for (var i = 0; i < 10; i++) {
|
||||
promises.push(scrypt.hash(K1, salt, 65536, 8, 1, 32))
|
||||
}
|
||||
return promise.all(promises).then(
|
||||
function () {
|
||||
assert(false, 'too many pending scrypt hashes were allowed')
|
||||
},
|
||||
function (err) {
|
||||
assert.equal(err.message, 'too many pending scrypt hashes')
|
||||
assert.equal(scrypt.numPendingHWM, 6, 'HWM should be maxPending+1')
|
||||
assert.equal(log.buffer[0].op, 'scrypt.maxPendingExceeded')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'scrypt enforces maximum number of pending requests',
|
||||
function (t) {
|
||||
var K1 = Buffer('f84913e3d8e6d624689d0a3e9678ac8dcc79d2c2f3d9641488cd9d6ef6cd83dd', 'hex')
|
||||
var salt = Buffer('identity.mozilla.com/picl/v1/scrypt')
|
||||
// Check the we're using the lower maxPending setting from config.
|
||||
t.equal(scrypt.maxPending, 5, 'maxPending is correctly set from config')
|
||||
// Send many concurrent requests.
|
||||
// Not yielding the event loop ensures they will pile up quickly.
|
||||
var promises = []
|
||||
for (var i = 0; i < 10; i++) {
|
||||
promises.push(scrypt.hash(K1, salt, 65536, 8, 1, 32))
|
||||
}
|
||||
return promise.all(promises).then(
|
||||
function () {
|
||||
t.fail('too many pending scrypt hashes were allowed')
|
||||
},
|
||||
function (err) {
|
||||
t.equal(err.message, 'too many pending scrypt hashes')
|
||||
t.equal(scrypt.numPendingHWM, 6, 'HWM should be maxPending+1')
|
||||
t.equal(log.buffer[0].op, 'scrypt.maxPendingExceeded')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
)
|
||||
})
|
||||
|
|
|
@ -2,8 +2,10 @@
|
|||
* 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 sinon = require('sinon')
|
||||
var test = require('../ptaptest')
|
||||
var log = { trace: function() {}, info: function () {} }
|
||||
var crypto = require('crypto')
|
||||
|
||||
|
@ -24,312 +26,314 @@ var ACCOUNT = {
|
|||
tokenVerificationId: crypto.randomBytes(16)
|
||||
}
|
||||
|
||||
test(
|
||||
'interface is correct',
|
||||
function (t) {
|
||||
return SessionToken.create(ACCOUNT)
|
||||
.then(function (token) {
|
||||
t.equal(typeof token.lastAuthAt, 'function', 'lastAuthAt method is defined')
|
||||
t.equal(typeof token.update, 'function', 'update method is defined')
|
||||
t.equal(typeof token.isFresh, 'function', 'isFresh method is defined')
|
||||
t.equal(typeof token.setUserAgentInfo, 'function', 'setUserAgentInfo method is defined')
|
||||
})
|
||||
}
|
||||
)
|
||||
describe('SessionToken', () => {
|
||||
it(
|
||||
'interface is correct',
|
||||
() => {
|
||||
return SessionToken.create(ACCOUNT)
|
||||
.then(function (token) {
|
||||
assert.equal(typeof token.lastAuthAt, 'function', 'lastAuthAt method is defined')
|
||||
assert.equal(typeof token.update, 'function', 'update method is defined')
|
||||
assert.equal(typeof token.isFresh, 'function', 'isFresh method is defined')
|
||||
assert.equal(typeof token.setUserAgentInfo, 'function', 'setUserAgentInfo method is defined')
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
're-creation from tokenData works',
|
||||
function (t) {
|
||||
var token = null
|
||||
return SessionToken.create(ACCOUNT)
|
||||
.then(
|
||||
function (x) {
|
||||
token = x
|
||||
t.equal(token.accountCreatedAt, ACCOUNT.createdAt)
|
||||
it(
|
||||
're-creation from tokenData works',
|
||||
() => {
|
||||
var token = null
|
||||
return SessionToken.create(ACCOUNT)
|
||||
.then(
|
||||
function (x) {
|
||||
token = x
|
||||
assert.equal(token.accountCreatedAt, ACCOUNT.createdAt)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
return SessionToken.fromHex(token.data, ACCOUNT)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (token2) {
|
||||
assert.deepEqual(token.data, token2.data)
|
||||
assert.deepEqual(token.id, token2.id)
|
||||
assert.deepEqual(token.authKey, token2.authKey)
|
||||
assert.deepEqual(token.bundleKey, token2.bundleKey)
|
||||
assert.deepEqual(token.uid, token2.uid)
|
||||
assert.equal(token.email, token2.email)
|
||||
assert.equal(token.emailCode, token2.emailCode)
|
||||
assert.equal(token.emailVerified, token2.emailVerified)
|
||||
assert.equal(token.accountCreatedAt, token2.accountCreatedAt)
|
||||
assert.equal(token.tokenVerified, token2.tokenVerified)
|
||||
assert.equal(token.tokenVerificationId, token2.tokenVerificationId)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
it(
|
||||
'create with NaN createdAt',
|
||||
() => {
|
||||
return SessionToken.create({
|
||||
createdAt: NaN,
|
||||
email: 'foo',
|
||||
uid: 'bar'
|
||||
}).then(
|
||||
function (token) {
|
||||
var now = Date.now()
|
||||
assert.ok(token.createdAt > now - 1000 && token.createdAt <= now)
|
||||
assert.equal(token.accountCreatedAt, null)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
return SessionToken.fromHex(token.data, ACCOUNT)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (token2) {
|
||||
t.deepEqual(token.data, token2.data)
|
||||
t.deepEqual(token.id, token2.id)
|
||||
t.deepEqual(token.authKey, token2.authKey)
|
||||
t.deepEqual(token.bundleKey, token2.bundleKey)
|
||||
t.deepEqual(token.uid, token2.uid)
|
||||
t.equal(token.email, token2.email)
|
||||
t.equal(token.emailCode, token2.emailCode)
|
||||
t.equal(token.emailVerified, token2.emailVerified)
|
||||
t.equal(token.accountCreatedAt, token2.accountCreatedAt)
|
||||
t.equal(token.tokenVerified, token2.tokenVerified)
|
||||
t.equal(token.tokenVerificationId, token2.tokenVerificationId)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'create with NaN createdAt',
|
||||
function (t) {
|
||||
return SessionToken.create({
|
||||
createdAt: NaN,
|
||||
email: 'foo',
|
||||
uid: 'bar'
|
||||
}).then(
|
||||
function (token) {
|
||||
var now = Date.now()
|
||||
t.ok(token.createdAt > now - 1000 && token.createdAt <= now)
|
||||
t.equal(token.accountCreatedAt, null)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
it(
|
||||
'sessionToken key derivations are test-vector compliant',
|
||||
() => {
|
||||
var token = null
|
||||
var tokenData = 'a0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebf'
|
||||
return SessionToken.fromHex(tokenData, ACCOUNT)
|
||||
.then(
|
||||
function (x) {
|
||||
token = x
|
||||
assert.equal(token.data.toString('hex'), tokenData)
|
||||
assert.equal(token.id.toString('hex'), 'c0a29dcf46174973da1378696e4c82ae10f723cf4f4d9f75e39f4ae3851595ab')
|
||||
assert.equal(token.authKey.toString('hex'), '9d8f22998ee7f5798b887042466b72d53e56ab0c094388bf65831f702d2febc0')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'sessionToken key derivations are test-vector compliant',
|
||||
function (t) {
|
||||
var token = null
|
||||
var tokenData = 'a0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebf'
|
||||
return SessionToken.fromHex(tokenData, ACCOUNT)
|
||||
.then(
|
||||
function (x) {
|
||||
token = x
|
||||
t.equal(token.data.toString('hex'), tokenData)
|
||||
t.equal(token.id.toString('hex'), 'c0a29dcf46174973da1378696e4c82ae10f723cf4f4d9f75e39f4ae3851595ab')
|
||||
t.equal(token.authKey.toString('hex'), '9d8f22998ee7f5798b887042466b72d53e56ab0c094388bf65831f702d2febc0')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
it(
|
||||
'SessionToken.setUserAgentInfo',
|
||||
() => {
|
||||
return SessionToken.create(ACCOUNT)
|
||||
.then(function (token) {
|
||||
token.setUserAgentInfo({
|
||||
data: 'foo',
|
||||
tokenId: 'foo',
|
||||
authKey: 'foo',
|
||||
bundleKey: 'foo',
|
||||
algorithm: 'foo',
|
||||
uid: 'foo',
|
||||
lifetime: 'foo',
|
||||
createdAt: 'foo',
|
||||
email: 'foo',
|
||||
emailCode: 'foo',
|
||||
emailVerified: 'foo',
|
||||
verifierSetAt: 'foo',
|
||||
locale: 'foo',
|
||||
accountCreatedAt: 'foo',
|
||||
uaBrowser: 'foo',
|
||||
uaBrowserVersion: 'bar',
|
||||
uaOS: 'baz',
|
||||
uaOSVersion: 'qux',
|
||||
uaDeviceType: 'wibble',
|
||||
lastAccessTime: 'mnngh'
|
||||
})
|
||||
assert.notEqual(token.data, 'foo', 'data was not updated')
|
||||
assert.notEqual(token.tokenId, 'foo', 'tokenId was not updated')
|
||||
assert.notEqual(token.authKey, 'foo', 'authKey was not updated')
|
||||
assert.notEqual(token.bundleKey, 'foo', 'bundleKey was not updated')
|
||||
assert.notEqual(token.algorithm, 'foo', 'algorithm was not updated')
|
||||
assert.notEqual(token.uid, 'foo', 'uid was not updated')
|
||||
assert.notEqual(token.lifetime, 'foo', 'lifetime was not updated')
|
||||
assert.notEqual(token.createdAt, 'foo', 'createdAt was not updated')
|
||||
assert.notEqual(token.email, 'foo', 'email was not updated')
|
||||
assert.notEqual(token.emailVerified, 'foo', 'emailVerified was not updated')
|
||||
assert.notEqual(token.verifierSetAt, 'foo', 'verifierSetAt was not updated')
|
||||
assert.notEqual(token.locale, 'foo', 'locale was not updated')
|
||||
assert.notEqual(token.accountCreatedAt, 'foo', 'accountCreatedAt was not updated')
|
||||
assert.equal(token.uaBrowser, 'foo', 'uaBrowser was updated')
|
||||
assert.equal(token.uaBrowserVersion, 'bar', 'uaBrowserVersion was updated')
|
||||
assert.equal(token.uaOS, 'baz', 'uaOS was updated')
|
||||
assert.equal(token.uaOSVersion, 'qux', 'uaOSVersion was updated')
|
||||
assert.equal(token.uaDeviceType, 'wibble', 'uaDeviceType was updated')
|
||||
assert.equal(token.lastAccessTime, 'mnngh', 'lastAccessTime was updated')
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'SessionToken.setUserAgentInfo',
|
||||
function (t) {
|
||||
return SessionToken.create(ACCOUNT)
|
||||
.then(function (token) {
|
||||
token.setUserAgentInfo({
|
||||
data: 'foo',
|
||||
tokenId: 'foo',
|
||||
authKey: 'foo',
|
||||
bundleKey: 'foo',
|
||||
algorithm: 'foo',
|
||||
uid: 'foo',
|
||||
lifetime: 'foo',
|
||||
createdAt: 'foo',
|
||||
email: 'foo',
|
||||
emailCode: 'foo',
|
||||
emailVerified: 'foo',
|
||||
verifierSetAt: 'foo',
|
||||
locale: 'foo',
|
||||
accountCreatedAt: 'foo',
|
||||
it(
|
||||
'SessionToken.isFresh with lastAccessTime updates enabled',
|
||||
() => {
|
||||
config.lastAccessTimeUpdates.enabled = true
|
||||
config.lastAccessTimeUpdates.sampleRate = 1
|
||||
config.lastAccessTimeUpdates.enabledEmailAddresses = /.+/
|
||||
return SessionToken.create({
|
||||
uaBrowser: 'foo',
|
||||
uaBrowserVersion: 'bar',
|
||||
uaOS: 'baz',
|
||||
uaOSVersion: 'qux',
|
||||
uaDeviceType: 'wibble',
|
||||
lastAccessTime: 0
|
||||
}).then(token => {
|
||||
assert.equal(token.isFresh({
|
||||
uaBrowser: 'foo',
|
||||
uaBrowserVersion: 'bar',
|
||||
uaOS: 'baz',
|
||||
uaOSVersion: 'qux',
|
||||
uaDeviceType: 'wibble',
|
||||
lastAccessTime: 'mnngh'
|
||||
})
|
||||
t.notEqual(token.data, 'foo', 'data was not updated')
|
||||
t.notEqual(token.tokenId, 'foo', 'tokenId was not updated')
|
||||
t.notEqual(token.authKey, 'foo', 'authKey was not updated')
|
||||
t.notEqual(token.bundleKey, 'foo', 'bundleKey was not updated')
|
||||
t.notEqual(token.algorithm, 'foo', 'algorithm was not updated')
|
||||
t.notEqual(token.uid, 'foo', 'uid was not updated')
|
||||
t.notEqual(token.lifetime, 'foo', 'lifetime was not updated')
|
||||
t.notEqual(token.createdAt, 'foo', 'createdAt was not updated')
|
||||
t.notEqual(token.email, 'foo', 'email was not updated')
|
||||
t.notEqual(token.emailVerified, 'foo', 'emailVerified was not updated')
|
||||
t.notEqual(token.verifierSetAt, 'foo', 'verifierSetAt was not updated')
|
||||
t.notEqual(token.locale, 'foo', 'locale was not updated')
|
||||
t.notEqual(token.accountCreatedAt, 'foo', 'accountCreatedAt was not updated')
|
||||
t.equal(token.uaBrowser, 'foo', 'uaBrowser was updated')
|
||||
t.equal(token.uaBrowserVersion, 'bar', 'uaBrowserVersion was updated')
|
||||
t.equal(token.uaOS, 'baz', 'uaOS was updated')
|
||||
t.equal(token.uaOSVersion, 'qux', 'uaOSVersion was updated')
|
||||
t.equal(token.uaDeviceType, 'wibble', 'uaDeviceType was updated')
|
||||
t.equal(token.lastAccessTime, 'mnngh', 'lastAccessTime was updated')
|
||||
lastAccessTime: 0
|
||||
}), true, 'returns true when all fields are the same')
|
||||
assert.equal(token.isFresh({
|
||||
uaBrowser: 'Foo',
|
||||
uaBrowserVersion: 'bar',
|
||||
uaOS: 'baz',
|
||||
uaOSVersion: 'qux',
|
||||
uaDeviceType: 'wibble',
|
||||
lastAccessTime: 0
|
||||
}), false, 'returns false when uaBrowser is different')
|
||||
assert.equal(token.isFresh({
|
||||
uaBrowser: 'foo',
|
||||
uaBrowserVersion: 'baR',
|
||||
uaOS: 'baz',
|
||||
uaOSVersion: 'qux',
|
||||
uaDeviceType: 'wibble',
|
||||
lastAccessTime: 0
|
||||
}), false, 'returns false when uaBrowserVersion is different')
|
||||
assert.equal(token.isFresh({
|
||||
uaBrowser: 'foo',
|
||||
uaBrowserVersion: 'bar',
|
||||
uaOS: 'foo',
|
||||
uaOSVersion: 'qux',
|
||||
uaDeviceType: 'wibble',
|
||||
lastAccessTime: 0
|
||||
}), false, 'returns false when uaOS is different')
|
||||
assert.equal(token.isFresh({
|
||||
uaBrowser: 'foo',
|
||||
uaBrowserVersion: 'bar',
|
||||
uaOS: 'baz',
|
||||
uaOSVersion: 'QUX',
|
||||
uaDeviceType: 'wibble',
|
||||
lastAccessTime: 0
|
||||
}), false, 'returns false when uaOSVersion is different')
|
||||
assert.equal(token.isFresh({
|
||||
uaBrowser: 'foo',
|
||||
uaBrowserVersion: 'bar',
|
||||
uaOS: 'baz',
|
||||
uaOSVersion: 'qux',
|
||||
uaDeviceType: 'wobble',
|
||||
lastAccessTime: 0
|
||||
}), false, 'returns false when uaDeviceType is different')
|
||||
assert.equal(token.isFresh({
|
||||
uaBrowser: 'foo',
|
||||
uaBrowserVersion: 'bar',
|
||||
uaOS: 'baz',
|
||||
uaOSVersion: 'qux',
|
||||
uaDeviceType: 'wibble',
|
||||
lastAccessTime: TOKEN_FRESHNESS_THRESHOLD
|
||||
}), false, 'returns false when lastAccessTime is TOKEN_FRESHNESS_THRESHOLD milliseconds newer')
|
||||
assert.equal(token.isFresh({
|
||||
uaBrowser: 'foo',
|
||||
uaBrowserVersion: 'bar',
|
||||
uaOS: 'baz',
|
||||
uaOSVersion: 'qux',
|
||||
uaDeviceType: 'wibble',
|
||||
lastAccessTime: 3599999
|
||||
}), true, 'returns true when lastAccessTime is 3,599,999 milliseconds newer')
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'SessionToken.isFresh with lastAccessTime updates enabled',
|
||||
t => {
|
||||
config.lastAccessTimeUpdates.enabled = true
|
||||
config.lastAccessTimeUpdates.sampleRate = 1
|
||||
config.lastAccessTimeUpdates.enabledEmailAddresses = /.+/
|
||||
return SessionToken.create({
|
||||
uaBrowser: 'foo',
|
||||
uaBrowserVersion: 'bar',
|
||||
uaOS: 'baz',
|
||||
uaOSVersion: 'qux',
|
||||
uaDeviceType: 'wibble',
|
||||
lastAccessTime: 0
|
||||
}).then(token => {
|
||||
t.equal(token.isFresh({
|
||||
it(
|
||||
'SessionToken.isFresh with lastAccessTime updates disabled',
|
||||
() => {
|
||||
config.lastAccessTimeUpdates.enabled = false
|
||||
return SessionToken.create({
|
||||
uaBrowser: 'foo',
|
||||
uaBrowserVersion: 'bar',
|
||||
uaOS: 'baz',
|
||||
uaOSVersion: 'qux',
|
||||
uaDeviceType: 'wibble',
|
||||
lastAccessTime: 0
|
||||
}), true, 'returns true when all fields are the same')
|
||||
t.equal(token.isFresh({
|
||||
uaBrowser: 'Foo',
|
||||
uaBrowserVersion: 'bar',
|
||||
uaOS: 'baz',
|
||||
uaOSVersion: 'qux',
|
||||
uaDeviceType: 'wibble',
|
||||
lastAccessTime: 0
|
||||
}), false, 'returns false when uaBrowser is different')
|
||||
t.equal(token.isFresh({
|
||||
uaBrowser: 'foo',
|
||||
uaBrowserVersion: 'baR',
|
||||
uaOS: 'baz',
|
||||
uaOSVersion: 'qux',
|
||||
uaDeviceType: 'wibble',
|
||||
lastAccessTime: 0
|
||||
}), false, 'returns false when uaBrowserVersion is different')
|
||||
t.equal(token.isFresh({
|
||||
uaBrowser: 'foo',
|
||||
uaBrowserVersion: 'bar',
|
||||
uaOS: 'foo',
|
||||
uaOSVersion: 'qux',
|
||||
uaDeviceType: 'wibble',
|
||||
lastAccessTime: 0
|
||||
}), false, 'returns false when uaOS is different')
|
||||
t.equal(token.isFresh({
|
||||
uaBrowser: 'foo',
|
||||
uaBrowserVersion: 'bar',
|
||||
uaOS: 'baz',
|
||||
uaOSVersion: 'QUX',
|
||||
uaDeviceType: 'wibble',
|
||||
lastAccessTime: 0
|
||||
}), false, 'returns false when uaOSVersion is different')
|
||||
t.equal(token.isFresh({
|
||||
uaBrowser: 'foo',
|
||||
uaBrowserVersion: 'bar',
|
||||
uaOS: 'baz',
|
||||
uaOSVersion: 'qux',
|
||||
uaDeviceType: 'wobble',
|
||||
lastAccessTime: 0
|
||||
}), false, 'returns false when uaDeviceType is different')
|
||||
t.equal(token.isFresh({
|
||||
uaBrowser: 'foo',
|
||||
uaBrowserVersion: 'bar',
|
||||
uaOS: 'baz',
|
||||
uaOSVersion: 'qux',
|
||||
uaDeviceType: 'wibble',
|
||||
lastAccessTime: TOKEN_FRESHNESS_THRESHOLD
|
||||
}), false, 'returns false when lastAccessTime is TOKEN_FRESHNESS_THRESHOLD milliseconds newer')
|
||||
t.equal(token.isFresh({
|
||||
uaBrowser: 'foo',
|
||||
uaBrowserVersion: 'bar',
|
||||
uaOS: 'baz',
|
||||
uaOSVersion: 'qux',
|
||||
uaDeviceType: 'wibble',
|
||||
lastAccessTime: 3599999
|
||||
}), true, 'returns true when lastAccessTime is 3,599,999 milliseconds newer')
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'SessionToken.isFresh with lastAccessTime updates disabled',
|
||||
t => {
|
||||
config.lastAccessTimeUpdates.enabled = false
|
||||
return SessionToken.create({
|
||||
uaBrowser: 'foo',
|
||||
uaBrowserVersion: 'bar',
|
||||
uaOS: 'baz',
|
||||
uaOSVersion: 'qux',
|
||||
uaDeviceType: 'wibble',
|
||||
lastAccessTime: 0
|
||||
}).then(token => {
|
||||
t.equal(token.isFresh({
|
||||
uaBrowser: 'foo',
|
||||
uaBrowserVersion: 'bar',
|
||||
uaOS: 'baz',
|
||||
uaOSVersion: 'qux',
|
||||
uaDeviceType: 'wibble',
|
||||
lastAccessTime: TOKEN_FRESHNESS_THRESHOLD
|
||||
}), true, 'returns true when lastAccessTime is TOKEN_FRESHNESS_THRESHOLD milliseconds newer')
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'SessionToken.update on fresh token',
|
||||
function (t) {
|
||||
return SessionToken.create(
|
||||
).then(function (token) {
|
||||
sinon.stub(SessionToken.prototype, 'isFresh', function () {
|
||||
return true
|
||||
}).then(token => {
|
||||
assert.equal(token.isFresh({
|
||||
uaBrowser: 'foo',
|
||||
uaBrowserVersion: 'bar',
|
||||
uaOS: 'baz',
|
||||
uaOSVersion: 'qux',
|
||||
uaDeviceType: 'wibble',
|
||||
lastAccessTime: TOKEN_FRESHNESS_THRESHOLD
|
||||
}), true, 'returns true when lastAccessTime is TOKEN_FRESHNESS_THRESHOLD milliseconds newer')
|
||||
})
|
||||
sinon.spy(SessionToken.prototype, 'setUserAgentInfo')
|
||||
}
|
||||
)
|
||||
|
||||
t.equal(
|
||||
token.update(
|
||||
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:41.0) Gecko/20100101 Firefox/41.0'
|
||||
), false, 'returns'
|
||||
)
|
||||
|
||||
t.equal(SessionToken.prototype.isFresh.callCount, 1, 'isFresh was called once')
|
||||
t.equal(SessionToken.prototype.isFresh.thisValues[0], token, 'isFresh context was token')
|
||||
var isFreshArgs = SessionToken.prototype.isFresh.args[0]
|
||||
t.equal(isFreshArgs.length, 1, 'isFresh was passed one argument')
|
||||
var isFreshData = isFreshArgs[0]
|
||||
t.equal(typeof isFreshData, 'object', 'isFresh was passed an object')
|
||||
t.equal(Object.keys(isFreshData).length, 6, 'isFresh data had six properties')
|
||||
t.equal(isFreshData.uaBrowser, 'Firefox', 'uaBrowser was correct')
|
||||
t.equal(isFreshData.uaBrowserVersion, '41', 'uaBrowserVersion was correct')
|
||||
t.equal(isFreshData.uaOS, 'Mac OS X', 'uaOS was correct')
|
||||
t.equal(isFreshData.uaOSVersion, '10.10', 'uaOSVersion was correct')
|
||||
t.equal(isFreshData.uaDeviceType, null, 'uaDeviceType was correct')
|
||||
t.ok(isFreshData.lastAccessTime > Date.now() - 10000, 'lastAccessTime was greater than 10 seconds ago')
|
||||
t.ok(isFreshData.lastAccessTime < Date.now(), 'lastAccessTime was less then Date.now()')
|
||||
|
||||
t.equal(SessionToken.prototype.setUserAgentInfo.callCount, 0, 'setUserAgentInfo was not called')
|
||||
})
|
||||
.finally(function () {
|
||||
SessionToken.prototype.isFresh.restore()
|
||||
SessionToken.prototype.setUserAgentInfo.restore()
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'SessionToken.update on stale token',
|
||||
function (t) {
|
||||
return SessionToken.create()
|
||||
.then(function (token) {
|
||||
it(
|
||||
'SessionToken.update on fresh token',
|
||||
() => {
|
||||
return SessionToken.create(
|
||||
).then(function (token) {
|
||||
sinon.stub(SessionToken.prototype, 'isFresh', function () {
|
||||
return false
|
||||
return true
|
||||
})
|
||||
sinon.spy(SessionToken.prototype, 'setUserAgentInfo')
|
||||
|
||||
t.equal(
|
||||
assert.equal(
|
||||
token.update(
|
||||
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:41.0) Gecko/20100101 Firefox/41.0'
|
||||
), true, 'returns true'
|
||||
), false, 'returns'
|
||||
)
|
||||
|
||||
t.equal(SessionToken.prototype.isFresh.callCount, 1, 'isFresh was called once')
|
||||
var isFreshArgs = SessionToken.prototype.setUserAgentInfo.args[0]
|
||||
t.equal(isFreshArgs.length, 1, 'isFresh was passed one argument')
|
||||
assert.equal(SessionToken.prototype.isFresh.callCount, 1, 'isFresh was called once')
|
||||
assert.equal(SessionToken.prototype.isFresh.thisValues[0], token, 'isFresh context was token')
|
||||
var isFreshArgs = SessionToken.prototype.isFresh.args[0]
|
||||
assert.equal(isFreshArgs.length, 1, 'isFresh was passed one argument')
|
||||
var isFreshData = isFreshArgs[0]
|
||||
assert.equal(typeof isFreshData, 'object', 'isFresh was passed an object')
|
||||
assert.equal(Object.keys(isFreshData).length, 6, 'isFresh data had six properties')
|
||||
assert.equal(isFreshData.uaBrowser, 'Firefox', 'uaBrowser was correct')
|
||||
assert.equal(isFreshData.uaBrowserVersion, '41', 'uaBrowserVersion was correct')
|
||||
assert.equal(isFreshData.uaOS, 'Mac OS X', 'uaOS was correct')
|
||||
assert.equal(isFreshData.uaOSVersion, '10.10', 'uaOSVersion was correct')
|
||||
assert.equal(isFreshData.uaDeviceType, null, 'uaDeviceType was correct')
|
||||
assert.ok(isFreshData.lastAccessTime > Date.now() - 10000, 'lastAccessTime was greater than 10 seconds ago')
|
||||
assert.ok(isFreshData.lastAccessTime < Date.now(), 'lastAccessTime was less then Date.now()')
|
||||
|
||||
t.equal(SessionToken.prototype.setUserAgentInfo.callCount, 1, 'setUserAgentInfo called once')
|
||||
t.equal(SessionToken.prototype.setUserAgentInfo.thisValues[0], token, 'setUserAgentInfo context was token')
|
||||
var setUserAgentInfoArgs = SessionToken.prototype.setUserAgentInfo.args[0]
|
||||
t.equal(setUserAgentInfoArgs.length, 1, 'setUserAgentInfo was passed one argument')
|
||||
t.deepEqual(setUserAgentInfoArgs[0], isFreshArgs[0], 'setUserAgentInfo was passed correct argument')
|
||||
assert.equal(SessionToken.prototype.setUserAgentInfo.callCount, 0, 'setUserAgentInfo was not called')
|
||||
})
|
||||
.finally(function () {
|
||||
SessionToken.prototype.isFresh.restore()
|
||||
SessionToken.prototype.setUserAgentInfo.restore()
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
it(
|
||||
'SessionToken.update on stale token',
|
||||
() => {
|
||||
return SessionToken.create()
|
||||
.then(function (token) {
|
||||
sinon.stub(SessionToken.prototype, 'isFresh', function () {
|
||||
return false
|
||||
})
|
||||
sinon.spy(SessionToken.prototype, 'setUserAgentInfo')
|
||||
|
||||
assert.equal(
|
||||
token.update(
|
||||
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:41.0) Gecko/20100101 Firefox/41.0'
|
||||
), true, 'returns true'
|
||||
)
|
||||
|
||||
assert.equal(SessionToken.prototype.isFresh.callCount, 1, 'isFresh was called once')
|
||||
var isFreshArgs = SessionToken.prototype.setUserAgentInfo.args[0]
|
||||
assert.equal(isFreshArgs.length, 1, 'isFresh was passed one argument')
|
||||
|
||||
assert.equal(SessionToken.prototype.setUserAgentInfo.callCount, 1, 'setUserAgentInfo called once')
|
||||
assert.equal(SessionToken.prototype.setUserAgentInfo.thisValues[0], token, 'setUserAgentInfo context was token')
|
||||
var setUserAgentInfoArgs = SessionToken.prototype.setUserAgentInfo.args[0]
|
||||
assert.equal(setUserAgentInfoArgs.length, 1, 'setUserAgentInfo was passed one argument')
|
||||
assert.deepEqual(setUserAgentInfoArgs[0], isFreshArgs[0], 'setUserAgentInfo was passed correct argument')
|
||||
})
|
||||
.finally(function () {
|
||||
SessionToken.prototype.isFresh.restore()
|
||||
SessionToken.prototype.setUserAgentInfo.restore()
|
||||
})
|
||||
}
|
||||
)
|
||||
})
|
||||
|
|
|
@ -2,6 +2,9 @@
|
|||
* 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 crypto = require('crypto')
|
||||
var uuid = require('uuid')
|
||||
var error = require('../../lib/error')
|
||||
|
@ -9,151 +12,152 @@ var getRoute = require('../routes_helpers').getRoute
|
|||
var isA = require('joi')
|
||||
var mocks = require('../mocks')
|
||||
var P = require('../../lib/promise')
|
||||
var test = require('../ptaptest')
|
||||
|
||||
test(
|
||||
'/certificate/sign',
|
||||
function (t) {
|
||||
t.plan(4)
|
||||
var deviceId = crypto.randomBytes(16)
|
||||
var mockDevices = mocks.mockDevices({
|
||||
deviceId: deviceId
|
||||
})
|
||||
const mockLog = mocks.spyLog()
|
||||
const mockRequest = mocks.mockRequest({
|
||||
credentials: {
|
||||
accountCreatedAt: Date.now(),
|
||||
emailVerified: true,
|
||||
lastAuthAt: function () {
|
||||
return Date.now()
|
||||
},
|
||||
locale: 'en',
|
||||
tokenId: crypto.randomBytes(16),
|
||||
uid: uuid.v4('binary')
|
||||
},
|
||||
log: mockLog,
|
||||
payload: {
|
||||
duration: 0,
|
||||
publicKey: {
|
||||
algorithm: 'RS',
|
||||
n: 'bar',
|
||||
e: 'baz'
|
||||
}
|
||||
},
|
||||
query: {}
|
||||
})
|
||||
|
||||
t.test('without service', function (t) {
|
||||
return runTest({
|
||||
devices: mockDevices,
|
||||
log: mockLog
|
||||
}, mockRequest, function () {
|
||||
t.equal(mockDevices.upsert.callCount, 1, 'devices.upsert was called once')
|
||||
var args = mockDevices.upsert.args[0]
|
||||
t.equal(args.length, 3, 'devices.upsert was passed one argument')
|
||||
t.equal(args[0], mockRequest, 'first argument was request object')
|
||||
t.equal(args[1], mockRequest.auth.credentials, 'second argument was sessionToken')
|
||||
t.deepEqual(args[2], {}, 'third argument was empty object')
|
||||
|
||||
t.equal(mockLog.activityEvent.callCount, 1, 'log.activityEvent was called once')
|
||||
args = mockLog.activityEvent.args[0]
|
||||
t.equal(args.length, 3, 'log.activityEvent was passed three arguments')
|
||||
t.equal(args[0], 'account.signed', 'first argument was event name')
|
||||
t.equal(args[1], mockRequest, 'second argument was request object')
|
||||
t.deepEqual(args[2], {
|
||||
uid: mockRequest.auth.credentials.uid.toString('hex'),
|
||||
account_created_at: mockRequest.auth.credentials.accountCreatedAt,
|
||||
device_id: deviceId.toString('hex')
|
||||
}, 'third argument was event data')
|
||||
})
|
||||
.then(function () {
|
||||
mockLog.activityEvent.reset()
|
||||
mockDevices.upsert.reset()
|
||||
})
|
||||
})
|
||||
|
||||
t.test('with service=sync', function (t) {
|
||||
mockRequest.query.service = 'sync'
|
||||
|
||||
return runTest({
|
||||
devices: mockDevices,
|
||||
log: mockLog
|
||||
}, mockRequest, function () {
|
||||
t.equal(mockDevices.upsert.callCount, 1, 'devices.upsert was called once')
|
||||
t.equal(mockLog.activityEvent.callCount, 1, 'log.activityEvent was called once')
|
||||
})
|
||||
.then(function () {
|
||||
mockLog.activityEvent.reset()
|
||||
mockDevices.upsert.reset()
|
||||
})
|
||||
})
|
||||
|
||||
t.test('with service=foo', function (t) {
|
||||
mockRequest.query.service = 'foo'
|
||||
|
||||
return runTest({
|
||||
devices: mockDevices,
|
||||
log: mockLog
|
||||
}, mockRequest, function () {
|
||||
t.equal(mockDevices.upsert.callCount, 0, 'devices.upsert was not called')
|
||||
t.equal(mockLog.activityEvent.callCount, 1, 'log.activityEvent was called once')
|
||||
t.equal(mockLog.activityEvent.args[0][2].device_id, undefined, 'device_id was undefined')
|
||||
})
|
||||
.then(function () {
|
||||
mockLog.activityEvent.reset()
|
||||
mockDevices.upsert.reset()
|
||||
})
|
||||
})
|
||||
|
||||
t.test('with deviceId', function (t) {
|
||||
mockRequest.query.service = 'sync'
|
||||
mockRequest.auth.credentials.deviceId = crypto.randomBytes(16)
|
||||
|
||||
return runTest({
|
||||
devices: mockDevices,
|
||||
log: mockLog
|
||||
}, mockRequest, function () {
|
||||
t.equal(mockDevices.upsert.callCount, 0, 'devices.upsert was not called')
|
||||
t.equal(mockLog.activityEvent.callCount, 1, 'log.activityEvent was called once')
|
||||
t.equal(mockLog.activityEvent.args[0][2].device_id, mockRequest.auth.credentials.deviceId.toString('hex'), 'device_id was correct')
|
||||
})
|
||||
.then(function () {
|
||||
mockLog.activityEvent.reset()
|
||||
mockDevices.upsert.reset()
|
||||
})
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
function runTest (options, request, assertions) {
|
||||
return new P(function (resolve) {
|
||||
getRoute(makeRoutes(options), '/certificate/sign')
|
||||
.handler(request, resolve)
|
||||
describe('/certificate/sign', () => {
|
||||
var deviceId = crypto.randomBytes(16)
|
||||
var mockDevices = mocks.mockDevices({
|
||||
deviceId: deviceId
|
||||
})
|
||||
.then(assertions)
|
||||
}
|
||||
|
||||
function makeRoutes (options) {
|
||||
options = options || {}
|
||||
|
||||
var log = options.log || mocks.mockLog()
|
||||
|
||||
return require('../../lib/routes/sign')(
|
||||
log,
|
||||
P,
|
||||
isA,
|
||||
error,
|
||||
options.signer || {
|
||||
sign: function () {
|
||||
return P.resolve({})
|
||||
const mockLog = mocks.spyLog()
|
||||
const mockRequest = mocks.mockRequest({
|
||||
credentials: {
|
||||
accountCreatedAt: Date.now(),
|
||||
emailVerified: true,
|
||||
lastAuthAt: function () {
|
||||
return Date.now()
|
||||
},
|
||||
locale: 'en',
|
||||
tokenId: crypto.randomBytes(16),
|
||||
uid: uuid.v4('binary')
|
||||
},
|
||||
log: mockLog,
|
||||
payload: {
|
||||
duration: 0,
|
||||
publicKey: {
|
||||
algorithm: 'RS',
|
||||
n: 'bar',
|
||||
e: 'baz'
|
||||
}
|
||||
},
|
||||
options.db || {
|
||||
updateSessionToken: function () {},
|
||||
updateLocale: function () {}
|
||||
},
|
||||
options.domain || 'wibble',
|
||||
options.devices
|
||||
)
|
||||
}
|
||||
query: {}
|
||||
})
|
||||
|
||||
it('without service', function () {
|
||||
return runTest({
|
||||
devices: mockDevices,
|
||||
log: mockLog
|
||||
}, mockRequest, function () {
|
||||
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 one argument')
|
||||
assert.equal(args[0], mockRequest, 'first argument was request object')
|
||||
assert.equal(args[1], mockRequest.auth.credentials, 'second argument was sessionToken')
|
||||
assert.deepEqual(args[2], {}, 'third argument was empty object')
|
||||
|
||||
assert.equal(mockLog.activityEvent.callCount, 1, 'log.activityEvent was called once')
|
||||
args = mockLog.activityEvent.args[0]
|
||||
assert.equal(args.length, 3, 'log.activityEvent was passed three arguments')
|
||||
assert.equal(args[0], 'account.signed', 'first argument was event name')
|
||||
assert.equal(args[1], mockRequest, 'second argument was request object')
|
||||
assert.deepEqual(args[2], {
|
||||
uid: mockRequest.auth.credentials.uid.toString('hex'),
|
||||
account_created_at: mockRequest.auth.credentials.accountCreatedAt,
|
||||
device_id: deviceId.toString('hex')
|
||||
}, 'third argument was event data')
|
||||
})
|
||||
.then(function () {
|
||||
mockLog.activityEvent.reset()
|
||||
mockDevices.upsert.reset()
|
||||
})
|
||||
})
|
||||
|
||||
it('with service=sync', () => {
|
||||
mockRequest.query.service = 'sync'
|
||||
|
||||
return runTest({
|
||||
devices: mockDevices,
|
||||
log: mockLog
|
||||
}, mockRequest, function () {
|
||||
assert.equal(mockDevices.upsert.callCount, 1, 'devices.upsert was called once')
|
||||
assert.equal(mockLog.activityEvent.callCount, 1, 'log.activityEvent was called once')
|
||||
})
|
||||
.then(function () {
|
||||
mockLog.activityEvent.reset()
|
||||
mockDevices.upsert.reset()
|
||||
})
|
||||
})
|
||||
|
||||
it('with service=foo', () => {
|
||||
mockRequest.query.service = 'foo'
|
||||
|
||||
return runTest({
|
||||
devices: mockDevices,
|
||||
log: mockLog
|
||||
}, mockRequest, function () {
|
||||
assert.equal(mockDevices.upsert.callCount, 0, 'devices.upsert was not called')
|
||||
assert.equal(mockLog.activityEvent.callCount, 1, 'log.activityEvent was called once')
|
||||
assert.equal(mockLog.activityEvent.args[0][2].device_id, undefined, 'device_id was undefined')
|
||||
})
|
||||
.then(function () {
|
||||
mockLog.activityEvent.reset()
|
||||
mockDevices.upsert.reset()
|
||||
})
|
||||
})
|
||||
|
||||
it('with deviceId', () => {
|
||||
mockRequest.query.service = 'sync'
|
||||
mockRequest.auth.credentials.deviceId = crypto.randomBytes(16)
|
||||
|
||||
return runTest({
|
||||
devices: mockDevices,
|
||||
log: mockLog
|
||||
}, mockRequest, function () {
|
||||
assert.equal(mockDevices.upsert.callCount, 0, 'devices.upsert was not called')
|
||||
assert.equal(mockLog.activityEvent.callCount, 1, 'log.activityEvent was called once')
|
||||
assert.equal(mockLog.activityEvent.args[0][2].device_id, mockRequest.auth.credentials.deviceId.toString('hex'), 'device_id was correct')
|
||||
})
|
||||
.then(function () {
|
||||
mockLog.activityEvent.reset()
|
||||
mockDevices.upsert.reset()
|
||||
})
|
||||
})
|
||||
|
||||
function runTest (options, request, assertions) {
|
||||
return new P(function (resolve, reject) {
|
||||
getRoute(makeRoutes(options), '/certificate/sign')
|
||||
.handler(request, (res) => {
|
||||
if (res instanceof Error) {
|
||||
reject(res)
|
||||
} else {
|
||||
resolve(res)
|
||||
}
|
||||
})
|
||||
})
|
||||
.then(assertions)
|
||||
}
|
||||
|
||||
function makeRoutes (options) {
|
||||
options = options || {}
|
||||
|
||||
var log = options.log || mocks.mockLog()
|
||||
|
||||
return require('../../lib/routes/sign')(
|
||||
log,
|
||||
P,
|
||||
isA,
|
||||
error,
|
||||
options.signer || {
|
||||
sign: function () {
|
||||
return P.resolve({})
|
||||
}
|
||||
},
|
||||
options.db || {
|
||||
updateSessionToken: function () {},
|
||||
updateLocale: function () {}
|
||||
},
|
||||
options.domain || 'wibble',
|
||||
options.devices
|
||||
)
|
||||
}
|
||||
|
||||
})
|
||||
|
|
|
@ -2,226 +2,230 @@
|
|||
* 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/. */
|
||||
|
||||
var tap = require('tap')
|
||||
var test = tap.test
|
||||
'use strict'
|
||||
|
||||
const assert = require('insist')
|
||||
var StatsDCollector = require('../../lib/metrics/statsd')
|
||||
var mockLog = require('../mocks').mockLog()
|
||||
|
||||
test(
|
||||
'statsd init failure cases',
|
||||
function (t) {
|
||||
describe('metrics/statsd', () => {
|
||||
it(
|
||||
'statsd init failure cases',
|
||||
() => {
|
||||
assert.throws(() => {
|
||||
void new StatsDCollector()
|
||||
}, 'Log is required')
|
||||
|
||||
try {
|
||||
void new StatsDCollector()
|
||||
} catch (e) {
|
||||
t.equal(e.message, 'Log is required')
|
||||
assert.doesNotThrow(() => {
|
||||
var statsd = new StatsDCollector(mockLog)
|
||||
statsd.init()
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
try {
|
||||
it(
|
||||
'statsd init',
|
||||
() => {
|
||||
var statsd = new StatsDCollector(mockLog)
|
||||
statsd.init()
|
||||
} catch (e) {
|
||||
t.fail('should not throw')
|
||||
assert.equal(statsd.connected, true)
|
||||
}
|
||||
)
|
||||
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'statsd init',
|
||||
function (t) {
|
||||
var statsd = new StatsDCollector(mockLog)
|
||||
statsd.init()
|
||||
t.equal(statsd.connected, true)
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'statsd write',
|
||||
function (t) {
|
||||
function StatsDMock() {
|
||||
return {
|
||||
socket: {},
|
||||
increment: function (name, value, sampleRate, tags) {
|
||||
t.equal(name, 'fxa.auth.some-event')
|
||||
t.equal(value, 1)
|
||||
t.ok(sampleRate)
|
||||
t.equal(Array.isArray(tags), true)
|
||||
t.equal(tags.length, 0)
|
||||
t.end()
|
||||
it(
|
||||
'statsd write',
|
||||
() => {
|
||||
let count = 0
|
||||
function StatsDMock() {
|
||||
return {
|
||||
socket: {},
|
||||
increment: function (name, value, sampleRate, tags) {
|
||||
assert.equal(name, 'fxa.auth.some-event')
|
||||
assert.equal(value, 1)
|
||||
assert.ok(sampleRate)
|
||||
assert.equal(Array.isArray(tags), true)
|
||||
assert.equal(tags.length, 0)
|
||||
count++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var statsd = new StatsDCollector(mockLog)
|
||||
statsd.init()
|
||||
statsd.client = new StatsDMock()
|
||||
statsd.write({
|
||||
event: 'some-event',
|
||||
uid: 'id'
|
||||
})
|
||||
assert.equal(count, 1)
|
||||
}
|
||||
)
|
||||
|
||||
var statsd = new StatsDCollector(mockLog)
|
||||
statsd.init()
|
||||
statsd.client = new StatsDMock()
|
||||
statsd.write({
|
||||
event: 'some-event',
|
||||
uid: 'id'
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'statsd write with tags',
|
||||
function (t) {
|
||||
function StatsDMock() {
|
||||
return {
|
||||
socket: {},
|
||||
increment: function (name, value, sampleRate, tags) {
|
||||
t.equal(name, 'fxa.auth.some-event')
|
||||
t.equal(value, 1)
|
||||
t.ok(sampleRate)
|
||||
t.deepEquals(tags, [
|
||||
'agent_ua_family:Firefox',
|
||||
'agent_ua_version:43.0',
|
||||
'agent_ua_version_major:43',
|
||||
'agent_os_version:10.11',
|
||||
'agent_os_family:Mac OS X',
|
||||
'agent_os_major:10'
|
||||
])
|
||||
t.end()
|
||||
it(
|
||||
'statsd write with tags',
|
||||
() => {
|
||||
let count = 0
|
||||
function StatsDMock() {
|
||||
return {
|
||||
socket: {},
|
||||
increment: function (name, value, sampleRate, tags) {
|
||||
assert.equal(name, 'fxa.auth.some-event')
|
||||
assert.equal(value, 1)
|
||||
assert.ok(sampleRate)
|
||||
assert.deepEqual(tags, [
|
||||
'agent_ua_family:Firefox',
|
||||
'agent_ua_version:43.0',
|
||||
'agent_ua_version_major:43',
|
||||
'agent_os_version:10.11',
|
||||
'agent_os_family:Mac OS X',
|
||||
'agent_os_major:10'
|
||||
])
|
||||
count++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var statsd = new StatsDCollector(mockLog)
|
||||
statsd.init()
|
||||
statsd.client = new StatsDMock()
|
||||
statsd.write({
|
||||
event: 'some-event',
|
||||
uid: 'id',
|
||||
userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:43.0) Gecko/20100101 Firefox/43.0'
|
||||
})
|
||||
assert.equal(count, 1)
|
||||
}
|
||||
)
|
||||
|
||||
var statsd = new StatsDCollector(mockLog)
|
||||
statsd.init()
|
||||
statsd.client = new StatsDMock()
|
||||
statsd.write({
|
||||
event: 'some-event',
|
||||
uid: 'id',
|
||||
userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:43.0) Gecko/20100101 Firefox/43.0'
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'statsd write via log.increment',
|
||||
function (t) {
|
||||
function StatsDMock() {
|
||||
return {
|
||||
socket: {},
|
||||
increment: function (name, value, sampleRate, tags) {
|
||||
t.equal(name, 'fxa.auth.some-event')
|
||||
t.equal(value, 1)
|
||||
t.ok(sampleRate)
|
||||
t.equal(Array.isArray(tags), true)
|
||||
t.equal(tags.length, 0)
|
||||
t.end()
|
||||
it(
|
||||
'statsd write via log.increment',
|
||||
() => {
|
||||
let count = 0
|
||||
function StatsDMock() {
|
||||
return {
|
||||
socket: {},
|
||||
increment: function (name, value, sampleRate, tags) {
|
||||
assert.equal(name, 'fxa.auth.some-event')
|
||||
assert.equal(value, 1)
|
||||
assert.ok(sampleRate)
|
||||
assert.equal(Array.isArray(tags), true)
|
||||
assert.equal(tags.length, 0)
|
||||
count++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var statsd = new StatsDCollector(mockLog)
|
||||
statsd.init()
|
||||
statsd.client = new StatsDMock()
|
||||
var log = require('../../lib/log')('info')
|
||||
log.statsd = statsd
|
||||
log.increment('some-event')
|
||||
assert.equal(count, 1)
|
||||
}
|
||||
)
|
||||
|
||||
var statsd = new StatsDCollector(mockLog)
|
||||
statsd.init()
|
||||
statsd.client = new StatsDMock()
|
||||
var log = require('../../lib/log')('info')
|
||||
log.statsd = statsd
|
||||
log.increment('some-event')
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'statsd write error',
|
||||
function (t) {
|
||||
var mockLog = {
|
||||
error: function (log) {
|
||||
t.equal(log.op, 'statsd.increment')
|
||||
t.equal(log.err.message, 'Failed to send message')
|
||||
t.end()
|
||||
}
|
||||
}
|
||||
|
||||
function StatsDMock() {
|
||||
return {
|
||||
socket: {},
|
||||
increment: function (name, value, sampleRate, tags, cb) {
|
||||
cb(new Error('Failed to send message'))
|
||||
it(
|
||||
'statsd write error',
|
||||
() => {
|
||||
let count = 0
|
||||
var mockLog = {
|
||||
error: function (log) {
|
||||
assert.equal(log.op, 'statsd.increment')
|
||||
assert.equal(log.err.message, 'Failed to send message')
|
||||
count++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var statsd = new StatsDCollector(mockLog)
|
||||
statsd.init()
|
||||
statsd.client = new StatsDMock()
|
||||
statsd.write({
|
||||
event: 'some-event',
|
||||
uid: 'id'
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'statsd.timing',
|
||||
function (t) {
|
||||
function StatsDMock() {
|
||||
return {
|
||||
socket: {},
|
||||
increment: function () {
|
||||
t.fail('statsd.increment should not be called')
|
||||
t.end()
|
||||
},
|
||||
timing: function () {
|
||||
t.equal(arguments.length, 5, 'statsd.timing received the correct number arguments')
|
||||
t.equal(arguments[0], 'fxa.auth.foo.time', 'statsd.timing received the correct name argument')
|
||||
t.equal(arguments[1], 1, 'statsd.timing received the correct timing argument')
|
||||
t.equal(typeof arguments[2], 'number', 'statsd.timing received the correct timing argument')
|
||||
t.equal(arguments[3], undefined, 'statsd.timing received the correct tags argument')
|
||||
t.equal(typeof arguments[4], 'function', 'statsd.timing received the correct callback argument')
|
||||
t.end()
|
||||
function StatsDMock() {
|
||||
return {
|
||||
socket: {},
|
||||
increment: function (name, value, sampleRate, tags, cb) {
|
||||
cb(new Error('Failed to send message'))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var statsd = new StatsDCollector(mockLog)
|
||||
statsd.init()
|
||||
statsd.client = new StatsDMock()
|
||||
statsd.write({
|
||||
event: 'some-event',
|
||||
uid: 'id'
|
||||
})
|
||||
assert.equal(count, 1)
|
||||
}
|
||||
)
|
||||
|
||||
var statsd = new StatsDCollector(mockLog)
|
||||
statsd.init()
|
||||
statsd.client = new StatsDMock()
|
||||
var log = require('../../lib/log')('info')
|
||||
log.statsd = statsd
|
||||
log.timing('foo', 1)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'statsd.timing error',
|
||||
function (t) {
|
||||
var mockLog = {
|
||||
error: function (log) {
|
||||
t.equal(log.op, 'statsd.timing')
|
||||
t.equal(log.err, 'foo')
|
||||
t.end()
|
||||
}
|
||||
}
|
||||
|
||||
function StatsDMock() {
|
||||
return {
|
||||
socket: {},
|
||||
timing: function () {
|
||||
arguments[4]('foo')
|
||||
it(
|
||||
'statsd.timing',
|
||||
() => {
|
||||
let count = 0
|
||||
function StatsDMock() {
|
||||
return {
|
||||
socket: {},
|
||||
increment: function () {
|
||||
assert(false, 'statsd.increment should not be called')
|
||||
},
|
||||
timing: function () {
|
||||
assert.equal(arguments.length, 5, 'statsd.timing received the correct number arguments')
|
||||
assert.equal(arguments[0], 'fxa.auth.foo.time', 'statsd.timing received the correct name argument')
|
||||
assert.equal(arguments[1], 1, 'statsd.timing received the correct timing argument')
|
||||
assert.equal(typeof arguments[2], 'number', 'statsd.timing received the correct timing argument')
|
||||
assert.equal(arguments[3], undefined, 'statsd.timing received the correct tags argument')
|
||||
assert.equal(typeof arguments[4], 'function', 'statsd.timing received the correct callback argument')
|
||||
count++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var statsd = new StatsDCollector(mockLog)
|
||||
statsd.init()
|
||||
statsd.client = new StatsDMock()
|
||||
var log = require('../../lib/log')('info')
|
||||
log.statsd = statsd
|
||||
log.timing('foo', 1)
|
||||
assert.equal(count, 1)
|
||||
}
|
||||
)
|
||||
|
||||
var statsd = new StatsDCollector(mockLog)
|
||||
statsd.init()
|
||||
statsd.client = new StatsDMock()
|
||||
statsd.timing('wibble', 42)
|
||||
}
|
||||
)
|
||||
it(
|
||||
'statsd.timing error',
|
||||
() => {
|
||||
let count = 0
|
||||
var mockLog = {
|
||||
error: function (log) {
|
||||
assert.equal(log.op, 'statsd.timing')
|
||||
assert.equal(log.err, 'foo')
|
||||
count++
|
||||
}
|
||||
}
|
||||
|
||||
test(
|
||||
'statsd close',
|
||||
function (t) {
|
||||
var statsd = new StatsDCollector(mockLog)
|
||||
statsd.init()
|
||||
t.equal(statsd.connected, true)
|
||||
statsd.close()
|
||||
t.equal(statsd.connected, false)
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
function StatsDMock() {
|
||||
return {
|
||||
socket: {},
|
||||
timing: function () {
|
||||
arguments[4]('foo')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var statsd = new StatsDCollector(mockLog)
|
||||
statsd.init()
|
||||
statsd.client = new StatsDMock()
|
||||
statsd.timing('wibble', 42)
|
||||
assert.equal(count, 1)
|
||||
}
|
||||
)
|
||||
|
||||
it(
|
||||
'statsd close',
|
||||
() => {
|
||||
var statsd = new StatsDCollector(mockLog)
|
||||
statsd.init()
|
||||
assert.equal(statsd.connected, true)
|
||||
statsd.close()
|
||||
assert.equal(statsd.connected, false)
|
||||
}
|
||||
)
|
||||
})
|
||||
|
|
|
@ -4,12 +4,12 @@
|
|||
|
||||
'use strict'
|
||||
|
||||
const assert = require('insist')
|
||||
var crypto = require('crypto')
|
||||
var hkdf = require('../../lib/crypto/hkdf')
|
||||
var mocks = require('../mocks')
|
||||
var P = require('../../lib/promise')
|
||||
var sinon = require('sinon')
|
||||
var test = require('tap').test
|
||||
|
||||
var Bundle = {
|
||||
bundle: sinon.spy(),
|
||||
|
@ -18,58 +18,60 @@ var Bundle = {
|
|||
var log = mocks.spyLog()
|
||||
var modulePath = '../../lib/tokens/token'
|
||||
|
||||
test('NODE_ENV=dev', function (t) {
|
||||
process.env.NODE_ENV = 'dev'
|
||||
var Token = require(modulePath)(log, crypto, P, hkdf, Bundle, null)
|
||||
describe('Token', () => {
|
||||
|
||||
t.plan(4)
|
||||
describe('NODE_ENV=dev', () => {
|
||||
let Token
|
||||
before(() => {
|
||||
delete require.cache[require.resolve(modulePath)]
|
||||
delete require.cache[require.resolve('../../config')]
|
||||
process.env.NODE_ENV = 'dev'
|
||||
Token = require(modulePath)(log, crypto, P, hkdf, Bundle, null)
|
||||
})
|
||||
|
||||
t.test('Token constructor was exported', function (t) {
|
||||
t.equal(typeof Token, 'function', 'Token is function')
|
||||
t.equal(Token.name, 'Token', 'function is called Token')
|
||||
t.equal(Token.length, 2, 'function expects two arguments')
|
||||
t.end()
|
||||
it('Token constructor was exported', () => {
|
||||
assert.equal(typeof Token, 'function', 'Token is function')
|
||||
assert.equal(Token.name, 'Token', 'function is called Token')
|
||||
assert.equal(Token.length, 2, 'function expects two arguments')
|
||||
})
|
||||
|
||||
it('Token constructor sets createdAt', () => {
|
||||
var now = Date.now() - 1
|
||||
var token = new Token({}, { createdAt: now })
|
||||
|
||||
assert.equal(token.createdAt, now, 'token.createdAt is correct')
|
||||
})
|
||||
|
||||
it('Token constructor does not set createdAt if it is negative', () => {
|
||||
var notNow = -Date.now()
|
||||
var token = new Token({}, { createdAt: notNow })
|
||||
|
||||
assert.ok(token.createdAt > 0, 'token.createdAt seems correct')
|
||||
})
|
||||
|
||||
it('Token constructor does not set createdAt if it is in the future', () => {
|
||||
var notNow = Date.now() + 1000
|
||||
var token = new Token({}, { createdAt: notNow })
|
||||
|
||||
assert.ok(token.createdAt > 0 && token.createdAt < notNow, 'token.createdAt seems correct')
|
||||
})
|
||||
})
|
||||
|
||||
t.test('Token constructor sets createdAt', function (t) {
|
||||
var now = Date.now() - 1
|
||||
var token = new Token({}, { createdAt: now })
|
||||
describe('NODE_ENV=prod', () => {
|
||||
let Token
|
||||
before(() => {
|
||||
delete require.cache[require.resolve(modulePath)]
|
||||
delete require.cache[require.resolve('../../config')]
|
||||
process.env.NODE_ENV = 'prod'
|
||||
Token = require(modulePath)(log, crypto, P, hkdf, Bundle, null)
|
||||
})
|
||||
|
||||
t.equal(token.createdAt, now, 'token.createdAt is correct')
|
||||
t.end()
|
||||
it('Token constructor does not set createdAt', () => {
|
||||
var notNow = Date.now() - 1
|
||||
var token = new Token({}, { createdAt: notNow })
|
||||
|
||||
assert.ok(token.createdAt > notNow, 'token.createdAt seems correct')
|
||||
})
|
||||
})
|
||||
|
||||
t.test('Token constructor does not set createdAt if it is negative', function (t) {
|
||||
var notNow = -Date.now()
|
||||
var token = new Token({}, { createdAt: notNow })
|
||||
|
||||
t.ok(token.createdAt > 0, 'token.createdAt seems correct')
|
||||
t.end()
|
||||
})
|
||||
|
||||
t.test('Token constructor does not set createdAt if it is in the future', function (t) {
|
||||
var notNow = Date.now() + 1000
|
||||
var token = new Token({}, { createdAt: notNow })
|
||||
|
||||
t.ok(token.createdAt > 0 && token.createdAt < notNow, 'token.createdAt seems correct')
|
||||
t.end()
|
||||
})
|
||||
})
|
||||
|
||||
test('NODE_ENV=prod', function (t) {
|
||||
process.env.NODE_ENV = 'prod'
|
||||
delete require.cache[require.resolve(modulePath)]
|
||||
delete require.cache[require.resolve('../../config')]
|
||||
var Token = require(modulePath)(log, crypto, P, hkdf, Bundle, null)
|
||||
|
||||
t.plan(1)
|
||||
|
||||
t.test('Token constructor does not set createdAt', function (t) {
|
||||
var notNow = Date.now() - 1
|
||||
var token = new Token({}, { createdAt: notNow })
|
||||
|
||||
t.ok(token.createdAt > notNow, 'token.createdAt seems correct')
|
||||
t.end()
|
||||
})
|
||||
})
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
'use strict'
|
||||
|
||||
var test = require('../ptaptest')
|
||||
const assert = require('insist')
|
||||
var mocks = require('../mocks')
|
||||
var proxyquire = require('proxyquire')
|
||||
var sinon = require('sinon')
|
||||
|
@ -24,494 +24,480 @@ var userAgent = proxyquire('../../lib/userAgent', {
|
|||
|
||||
var log = mocks.spyLog()
|
||||
|
||||
test(
|
||||
'exports function',
|
||||
function (t) {
|
||||
t.equal(typeof userAgent, 'function')
|
||||
t.equal(userAgent.length, 2)
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'sets data correctly',
|
||||
function (t) {
|
||||
parserResult = {
|
||||
ua: {
|
||||
family: 'foo',
|
||||
major: '1',
|
||||
minor: '0'
|
||||
},
|
||||
os: {
|
||||
family: 'bar',
|
||||
major: '2',
|
||||
minor: '0'
|
||||
},
|
||||
device: {
|
||||
family: 'baz'
|
||||
}
|
||||
describe('userAgent', () => {
|
||||
it(
|
||||
'exports function',
|
||||
() => {
|
||||
assert.equal(typeof userAgent, 'function')
|
||||
assert.equal(userAgent.length, 2)
|
||||
}
|
||||
var context = {}
|
||||
var result = userAgent.call(context, 'qux', log)
|
||||
)
|
||||
|
||||
t.equal(uaParser.parse.callCount, 1)
|
||||
t.ok(uaParser.parse.calledWithExactly('qux'))
|
||||
|
||||
t.equal(result, context)
|
||||
t.equal(Object.keys(result).length, 5)
|
||||
t.equal(result.uaBrowser, 'foo')
|
||||
t.equal(result.uaBrowserVersion, '1')
|
||||
t.equal(result.uaOS, 'bar')
|
||||
t.equal(result.uaOSVersion, '2')
|
||||
t.equal(result.uaDeviceType, 'mobile')
|
||||
|
||||
t.equal(log.info.callCount, 0)
|
||||
|
||||
t.end()
|
||||
uaParser.parse.reset()
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'ignores family:Other',
|
||||
function (t) {
|
||||
parserResult = {
|
||||
ua: {
|
||||
family: 'Other',
|
||||
major: '1',
|
||||
minor: '0'
|
||||
},
|
||||
os: {
|
||||
family: 'Other',
|
||||
major: '2',
|
||||
minor: '0'
|
||||
},
|
||||
device: {
|
||||
family: 'Other'
|
||||
it(
|
||||
'sets data correctly',
|
||||
() => {
|
||||
parserResult = {
|
||||
ua: {
|
||||
family: 'foo',
|
||||
major: '1',
|
||||
minor: '0'
|
||||
},
|
||||
os: {
|
||||
family: 'bar',
|
||||
major: '2',
|
||||
minor: '0'
|
||||
},
|
||||
device: {
|
||||
family: 'baz'
|
||||
}
|
||||
}
|
||||
var context = {}
|
||||
var result = userAgent.call(context, 'qux', log)
|
||||
|
||||
assert.equal(uaParser.parse.callCount, 1)
|
||||
assert.ok(uaParser.parse.calledWithExactly('qux'))
|
||||
|
||||
assert.equal(result, context)
|
||||
assert.equal(Object.keys(result).length, 5)
|
||||
assert.equal(result.uaBrowser, 'foo')
|
||||
assert.equal(result.uaBrowserVersion, '1')
|
||||
assert.equal(result.uaOS, 'bar')
|
||||
assert.equal(result.uaOSVersion, '2')
|
||||
assert.equal(result.uaDeviceType, 'mobile')
|
||||
|
||||
assert.equal(log.info.callCount, 0)
|
||||
|
||||
uaParser.parse.reset()
|
||||
}
|
||||
var context = {}
|
||||
var result = userAgent.call(context, 'wibble', log)
|
||||
)
|
||||
|
||||
t.equal(uaParser.parse.callCount, 1)
|
||||
t.ok(uaParser.parse.calledWithExactly('wibble'))
|
||||
|
||||
t.equal(result, context)
|
||||
t.equal(Object.keys(result).length, 5)
|
||||
t.equal(result.uaBrowser, 'wibble')
|
||||
t.equal(result.uaOS, null)
|
||||
t.equal(result.uaDeviceType, null)
|
||||
|
||||
t.equal(log.info.callCount, 1)
|
||||
var args = log.info.args[0]
|
||||
t.equal(args.length, 1)
|
||||
t.deepEqual(args[0], {
|
||||
op: 'userAgent:truncate',
|
||||
userAgent: 'wibble'
|
||||
})
|
||||
|
||||
t.end()
|
||||
uaParser.parse.reset()
|
||||
log.info.reset()
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'appends minor version if set',
|
||||
function (t) {
|
||||
parserResult = {
|
||||
ua: {
|
||||
family: 'foo',
|
||||
major: '1',
|
||||
minor: '1'
|
||||
},
|
||||
os: {
|
||||
family: 'bar',
|
||||
major: '2',
|
||||
minor: '34567'
|
||||
},
|
||||
device: {
|
||||
family: 'baz'
|
||||
it(
|
||||
'ignores family:Other',
|
||||
() => {
|
||||
parserResult = {
|
||||
ua: {
|
||||
family: 'Other',
|
||||
major: '1',
|
||||
minor: '0'
|
||||
},
|
||||
os: {
|
||||
family: 'Other',
|
||||
major: '2',
|
||||
minor: '0'
|
||||
},
|
||||
device: {
|
||||
family: 'Other'
|
||||
}
|
||||
}
|
||||
var context = {}
|
||||
var result = userAgent.call(context, 'wibble', log)
|
||||
|
||||
assert.equal(uaParser.parse.callCount, 1)
|
||||
assert.ok(uaParser.parse.calledWithExactly('wibble'))
|
||||
|
||||
assert.equal(result, context)
|
||||
assert.equal(Object.keys(result).length, 5)
|
||||
assert.equal(result.uaBrowser, 'wibble')
|
||||
assert.equal(result.uaOS, null)
|
||||
assert.equal(result.uaDeviceType, null)
|
||||
|
||||
assert.equal(log.info.callCount, 1)
|
||||
var args = log.info.args[0]
|
||||
assert.equal(args.length, 1)
|
||||
assert.deepEqual(args[0], {
|
||||
op: 'userAgent:truncate',
|
||||
userAgent: 'wibble'
|
||||
})
|
||||
|
||||
uaParser.parse.reset()
|
||||
log.info.reset()
|
||||
}
|
||||
var context = {}
|
||||
var result = userAgent.call(context, log)
|
||||
)
|
||||
|
||||
t.equal(result.uaBrowserVersion, '1.1')
|
||||
t.equal(result.uaOSVersion, '2.34567')
|
||||
|
||||
t.equal(log.info.callCount, 0)
|
||||
|
||||
t.end()
|
||||
uaParser.parse.reset()
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'recognises Android phones as a mobile OS',
|
||||
function (t) {
|
||||
parserResult = {
|
||||
ua: {
|
||||
family: 'foo',
|
||||
major: '1',
|
||||
minor: '0'
|
||||
},
|
||||
os: {
|
||||
family: 'Android',
|
||||
major: '2',
|
||||
minor: '0'
|
||||
},
|
||||
device: {
|
||||
family: 'Other'
|
||||
it(
|
||||
'appends minor version if set',
|
||||
() => {
|
||||
parserResult = {
|
||||
ua: {
|
||||
family: 'foo',
|
||||
major: '1',
|
||||
minor: '1'
|
||||
},
|
||||
os: {
|
||||
family: 'bar',
|
||||
major: '2',
|
||||
minor: '34567'
|
||||
},
|
||||
device: {
|
||||
family: 'baz'
|
||||
}
|
||||
}
|
||||
var context = {}
|
||||
var result = userAgent.call(context, log)
|
||||
|
||||
assert.equal(result.uaBrowserVersion, '1.1')
|
||||
assert.equal(result.uaOSVersion, '2.34567')
|
||||
|
||||
assert.equal(log.info.callCount, 0)
|
||||
|
||||
uaParser.parse.reset()
|
||||
}
|
||||
var context = {}
|
||||
var result = userAgent.call(context, log)
|
||||
)
|
||||
|
||||
t.equal(result.uaDeviceType, 'mobile')
|
||||
|
||||
t.equal(log.info.callCount, 0)
|
||||
|
||||
t.end()
|
||||
uaParser.parse.reset()
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'recognises iOS as a mobile OS',
|
||||
function (t) {
|
||||
parserResult = {
|
||||
ua: {
|
||||
family: 'foo',
|
||||
major: '1',
|
||||
minor: '0'
|
||||
},
|
||||
os: {
|
||||
family: 'iOS',
|
||||
major: '2',
|
||||
minor: '0'
|
||||
},
|
||||
device: {
|
||||
family: 'Other'
|
||||
it(
|
||||
'recognises Android phones as a mobile OS',
|
||||
() => {
|
||||
parserResult = {
|
||||
ua: {
|
||||
family: 'foo',
|
||||
major: '1',
|
||||
minor: '0'
|
||||
},
|
||||
os: {
|
||||
family: 'Android',
|
||||
major: '2',
|
||||
minor: '0'
|
||||
},
|
||||
device: {
|
||||
family: 'Other'
|
||||
}
|
||||
}
|
||||
var context = {}
|
||||
var result = userAgent.call(context, log)
|
||||
|
||||
assert.equal(result.uaDeviceType, 'mobile')
|
||||
|
||||
assert.equal(log.info.callCount, 0)
|
||||
|
||||
uaParser.parse.reset()
|
||||
}
|
||||
var context = {}
|
||||
var result = userAgent.call(context, log)
|
||||
)
|
||||
|
||||
t.equal(result.uaDeviceType, 'mobile')
|
||||
|
||||
t.equal(log.info.callCount, 0)
|
||||
|
||||
t.end()
|
||||
uaParser.parse.reset()
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'recognises Firefox OS as a mobile OS',
|
||||
function (t) {
|
||||
parserResult = {
|
||||
ua: {
|
||||
family: 'foo',
|
||||
major: '1',
|
||||
minor: '0'
|
||||
},
|
||||
os: {
|
||||
family: 'Firefox OS',
|
||||
major: '2',
|
||||
minor: '0'
|
||||
},
|
||||
device: {
|
||||
family: 'Other'
|
||||
it(
|
||||
'recognises iOS as a mobile OS',
|
||||
() => {
|
||||
parserResult = {
|
||||
ua: {
|
||||
family: 'foo',
|
||||
major: '1',
|
||||
minor: '0'
|
||||
},
|
||||
os: {
|
||||
family: 'iOS',
|
||||
major: '2',
|
||||
minor: '0'
|
||||
},
|
||||
device: {
|
||||
family: 'Other'
|
||||
}
|
||||
}
|
||||
var context = {}
|
||||
var result = userAgent.call(context, log)
|
||||
|
||||
assert.equal(result.uaDeviceType, 'mobile')
|
||||
|
||||
assert.equal(log.info.callCount, 0)
|
||||
|
||||
uaParser.parse.reset()
|
||||
}
|
||||
var context = {}
|
||||
var result = userAgent.call(context, log)
|
||||
)
|
||||
|
||||
t.equal(result.uaDeviceType, 'mobile')
|
||||
|
||||
t.equal(log.info.callCount, 0)
|
||||
|
||||
t.end()
|
||||
uaParser.parse.reset()
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'recognises Windows Phone as a mobile OS',
|
||||
function (t) {
|
||||
parserResult = {
|
||||
ua: {
|
||||
family: 'foo',
|
||||
major: '1',
|
||||
minor: '0'
|
||||
},
|
||||
os: {
|
||||
family: 'Windows Phone',
|
||||
major: '2',
|
||||
minor: '0'
|
||||
},
|
||||
device: {
|
||||
family: 'Other'
|
||||
it(
|
||||
'recognises Firefox OS as a mobile OS',
|
||||
() => {
|
||||
parserResult = {
|
||||
ua: {
|
||||
family: 'foo',
|
||||
major: '1',
|
||||
minor: '0'
|
||||
},
|
||||
os: {
|
||||
family: 'Firefox OS',
|
||||
major: '2',
|
||||
minor: '0'
|
||||
},
|
||||
device: {
|
||||
family: 'Other'
|
||||
}
|
||||
}
|
||||
var context = {}
|
||||
var result = userAgent.call(context, log)
|
||||
|
||||
assert.equal(result.uaDeviceType, 'mobile')
|
||||
|
||||
assert.equal(log.info.callCount, 0)
|
||||
|
||||
uaParser.parse.reset()
|
||||
}
|
||||
var context = {}
|
||||
var result = userAgent.call(context, log)
|
||||
)
|
||||
|
||||
t.equal(result.uaDeviceType, 'mobile')
|
||||
|
||||
t.equal(log.info.callCount, 0)
|
||||
|
||||
t.end()
|
||||
uaParser.parse.reset()
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'recognises BlackBerry OS as a mobile OS',
|
||||
function (t) {
|
||||
parserResult = {
|
||||
ua: {
|
||||
family: 'foo',
|
||||
major: '1',
|
||||
minor: '0'
|
||||
},
|
||||
os: {
|
||||
family: 'BlackBerry OS',
|
||||
major: '2',
|
||||
minor: '0'
|
||||
},
|
||||
device: {
|
||||
family: 'Other'
|
||||
it(
|
||||
'recognises Windows Phone as a mobile OS',
|
||||
() => {
|
||||
parserResult = {
|
||||
ua: {
|
||||
family: 'foo',
|
||||
major: '1',
|
||||
minor: '0'
|
||||
},
|
||||
os: {
|
||||
family: 'Windows Phone',
|
||||
major: '2',
|
||||
minor: '0'
|
||||
},
|
||||
device: {
|
||||
family: 'Other'
|
||||
}
|
||||
}
|
||||
var context = {}
|
||||
var result = userAgent.call(context, log)
|
||||
|
||||
assert.equal(result.uaDeviceType, 'mobile')
|
||||
|
||||
assert.equal(log.info.callCount, 0)
|
||||
|
||||
uaParser.parse.reset()
|
||||
}
|
||||
var context = {}
|
||||
var result = userAgent.call(context, log)
|
||||
)
|
||||
|
||||
t.equal(result.uaDeviceType, 'mobile')
|
||||
|
||||
t.equal(log.info.callCount, 0)
|
||||
|
||||
t.end()
|
||||
uaParser.parse.reset()
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'does not recognise Mac OS X as a mobile OS',
|
||||
function (t) {
|
||||
parserResult = {
|
||||
ua: {
|
||||
family: 'foo',
|
||||
major: '1',
|
||||
minor: '0'
|
||||
},
|
||||
os: {
|
||||
family: 'Mac OS X',
|
||||
major: '2',
|
||||
minor: '0'
|
||||
},
|
||||
device: {
|
||||
family: 'Other'
|
||||
it(
|
||||
'recognises BlackBerry OS as a mobile OS',
|
||||
() => {
|
||||
parserResult = {
|
||||
ua: {
|
||||
family: 'foo',
|
||||
major: '1',
|
||||
minor: '0'
|
||||
},
|
||||
os: {
|
||||
family: 'BlackBerry OS',
|
||||
major: '2',
|
||||
minor: '0'
|
||||
},
|
||||
device: {
|
||||
family: 'Other'
|
||||
}
|
||||
}
|
||||
var context = {}
|
||||
var result = userAgent.call(context, log)
|
||||
|
||||
assert.equal(result.uaDeviceType, 'mobile')
|
||||
|
||||
assert.equal(log.info.callCount, 0)
|
||||
|
||||
uaParser.parse.reset()
|
||||
}
|
||||
var context = {}
|
||||
var result = userAgent.call(context, log)
|
||||
)
|
||||
|
||||
t.equal(result.uaDeviceType, null)
|
||||
|
||||
t.equal(log.info.callCount, 0)
|
||||
|
||||
t.end()
|
||||
uaParser.parse.reset()
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'does not recognise Linux as a mobile OS',
|
||||
function (t) {
|
||||
parserResult = {
|
||||
ua: {
|
||||
family: 'foo',
|
||||
major: '1',
|
||||
minor: '0'
|
||||
},
|
||||
os: {
|
||||
family: 'Linux',
|
||||
major: '2',
|
||||
minor: '0'
|
||||
},
|
||||
device: {
|
||||
family: 'Other'
|
||||
it(
|
||||
'does not recognise Mac OS X as a mobile OS',
|
||||
() => {
|
||||
parserResult = {
|
||||
ua: {
|
||||
family: 'foo',
|
||||
major: '1',
|
||||
minor: '0'
|
||||
},
|
||||
os: {
|
||||
family: 'Mac OS X',
|
||||
major: '2',
|
||||
minor: '0'
|
||||
},
|
||||
device: {
|
||||
family: 'Other'
|
||||
}
|
||||
}
|
||||
var context = {}
|
||||
var result = userAgent.call(context, log)
|
||||
|
||||
assert.equal(result.uaDeviceType, null)
|
||||
|
||||
assert.equal(log.info.callCount, 0)
|
||||
|
||||
uaParser.parse.reset()
|
||||
}
|
||||
var context = {}
|
||||
var result = userAgent.call(context, log)
|
||||
)
|
||||
|
||||
t.equal(result.uaDeviceType, null)
|
||||
|
||||
t.equal(log.info.callCount, 0)
|
||||
|
||||
t.end()
|
||||
uaParser.parse.reset()
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'does not recognise Windows as a mobile OS',
|
||||
function (t) {
|
||||
parserResult = {
|
||||
ua: {
|
||||
family: 'foo',
|
||||
major: '1',
|
||||
minor: '0'
|
||||
},
|
||||
os: {
|
||||
family: 'Windows',
|
||||
major: '2',
|
||||
minor: '0'
|
||||
},
|
||||
device: {
|
||||
family: 'Other'
|
||||
it(
|
||||
'does not recognise Linux as a mobile OS',
|
||||
() => {
|
||||
parserResult = {
|
||||
ua: {
|
||||
family: 'foo',
|
||||
major: '1',
|
||||
minor: '0'
|
||||
},
|
||||
os: {
|
||||
family: 'Linux',
|
||||
major: '2',
|
||||
minor: '0'
|
||||
},
|
||||
device: {
|
||||
family: 'Other'
|
||||
}
|
||||
}
|
||||
var context = {}
|
||||
var result = userAgent.call(context, log)
|
||||
|
||||
assert.equal(result.uaDeviceType, null)
|
||||
|
||||
assert.equal(log.info.callCount, 0)
|
||||
|
||||
uaParser.parse.reset()
|
||||
}
|
||||
var context = {}
|
||||
var result = userAgent.call(context, log)
|
||||
)
|
||||
|
||||
t.equal(result.uaDeviceType, null)
|
||||
|
||||
t.equal(log.info.callCount, 0)
|
||||
|
||||
t.end()
|
||||
uaParser.parse.reset()
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'recognises iPads as tablets',
|
||||
function (t) {
|
||||
parserResult = {
|
||||
userAgent: 'Mozilla/5.0 (iPad; CPU OS 7_0 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko) Mobile/11A465',
|
||||
ua: {
|
||||
family: 'Mobile Safari UI/WKWebView',
|
||||
major: '7',
|
||||
minor: '0'
|
||||
},
|
||||
os: {
|
||||
family: 'iOS',
|
||||
major: '7',
|
||||
minor: '0'
|
||||
},
|
||||
device: {
|
||||
family: 'iPad'
|
||||
it(
|
||||
'does not recognise Windows as a mobile OS',
|
||||
() => {
|
||||
parserResult = {
|
||||
ua: {
|
||||
family: 'foo',
|
||||
major: '1',
|
||||
minor: '0'
|
||||
},
|
||||
os: {
|
||||
family: 'Windows',
|
||||
major: '2',
|
||||
minor: '0'
|
||||
},
|
||||
device: {
|
||||
family: 'Other'
|
||||
}
|
||||
}
|
||||
var context = {}
|
||||
var result = userAgent.call(context, log)
|
||||
|
||||
assert.equal(result.uaDeviceType, null)
|
||||
|
||||
assert.equal(log.info.callCount, 0)
|
||||
|
||||
uaParser.parse.reset()
|
||||
}
|
||||
var context = {}
|
||||
var result = userAgent.call(context, log)
|
||||
)
|
||||
|
||||
t.equal(result.uaDeviceType, 'tablet')
|
||||
|
||||
t.end()
|
||||
uaParser.parse.reset()
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
test(
|
||||
'recognises Android tablets as tablets',
|
||||
function (t) {
|
||||
parserResult = {
|
||||
userAgent: 'Mozilla/5.0 (Linux; Android 4.4.2; Nexus 7 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.59 Safari/537.36',
|
||||
ua: {
|
||||
family: 'Chrome Mobile',
|
||||
major: '31',
|
||||
minor: '0'
|
||||
},
|
||||
os: {
|
||||
family: 'Android',
|
||||
major: '4',
|
||||
minor: '4'
|
||||
},
|
||||
device: {
|
||||
family: 'Nexus 7'
|
||||
it(
|
||||
'recognises iPads as tablets',
|
||||
() => {
|
||||
parserResult = {
|
||||
userAgent: 'Mozilla/5.0 (iPad; CPU OS 7_0 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko) Mobile/11A465',
|
||||
ua: {
|
||||
family: 'Mobile Safari UI/WKWebView',
|
||||
major: '7',
|
||||
minor: '0'
|
||||
},
|
||||
os: {
|
||||
family: 'iOS',
|
||||
major: '7',
|
||||
minor: '0'
|
||||
},
|
||||
device: {
|
||||
family: 'iPad'
|
||||
}
|
||||
}
|
||||
var context = {}
|
||||
var result = userAgent.call(context, log)
|
||||
|
||||
assert.equal(result.uaDeviceType, 'tablet')
|
||||
|
||||
uaParser.parse.reset()
|
||||
}
|
||||
var context = {}
|
||||
var result = userAgent.call(context, log)
|
||||
)
|
||||
|
||||
t.equal(result.uaDeviceType, 'tablet')
|
||||
|
||||
t.end()
|
||||
uaParser.parse.reset()
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'uaBrowser falls back to truncated user agent string',
|
||||
function (t) {
|
||||
parserResult = {
|
||||
ua: {
|
||||
family: 'Other'
|
||||
},
|
||||
os: {
|
||||
family: 'Other'
|
||||
},
|
||||
device: {
|
||||
family: 'Other'
|
||||
it(
|
||||
'recognises Android tablets as tablets',
|
||||
() => {
|
||||
parserResult = {
|
||||
userAgent: 'Mozilla/5.0 (Linux; Android 4.4.2; Nexus 7 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.59 Safari/537.36',
|
||||
ua: {
|
||||
family: 'Chrome Mobile',
|
||||
major: '31',
|
||||
minor: '0'
|
||||
},
|
||||
os: {
|
||||
family: 'Android',
|
||||
major: '4',
|
||||
minor: '4'
|
||||
},
|
||||
device: {
|
||||
family: 'Nexus 7'
|
||||
}
|
||||
}
|
||||
var context = {}
|
||||
var result = userAgent.call(context, log)
|
||||
|
||||
assert.equal(result.uaDeviceType, 'tablet')
|
||||
|
||||
uaParser.parse.reset()
|
||||
}
|
||||
var context = {}
|
||||
var userAgentString = new Array(201).join('x')
|
||||
var result = userAgent.call(context, userAgentString, log)
|
||||
)
|
||||
|
||||
t.equal(result.uaBrowser, new Array(61).join('x') + ELLIPSIS)
|
||||
|
||||
t.equal(log.info.callCount, 1)
|
||||
var args = log.info.args[0]
|
||||
t.equal(args.length, 1)
|
||||
t.deepEqual(args[0], {
|
||||
op: 'userAgent:truncate',
|
||||
userAgent: userAgentString
|
||||
})
|
||||
|
||||
t.end()
|
||||
uaParser.parse.reset()
|
||||
log.info.reset()
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'truncated fallback is relaxed for parentheses',
|
||||
function (t) {
|
||||
parserResult = {
|
||||
ua: {
|
||||
family: 'Other'
|
||||
},
|
||||
os: {
|
||||
family: 'Other'
|
||||
},
|
||||
device: {
|
||||
family: 'Other'
|
||||
it(
|
||||
'uaBrowser falls back to truncated user agent string',
|
||||
() => {
|
||||
parserResult = {
|
||||
ua: {
|
||||
family: 'Other'
|
||||
},
|
||||
os: {
|
||||
family: 'Other'
|
||||
},
|
||||
device: {
|
||||
family: 'Other'
|
||||
}
|
||||
}
|
||||
var context = {}
|
||||
var userAgentString = new Array(201).join('x')
|
||||
var result = userAgent.call(context, userAgentString, log)
|
||||
|
||||
assert.equal(result.uaBrowser, new Array(61).join('x') + ELLIPSIS)
|
||||
|
||||
assert.equal(log.info.callCount, 1)
|
||||
var args = log.info.args[0]
|
||||
assert.equal(args.length, 1)
|
||||
assert.deepEqual(args[0], {
|
||||
op: 'userAgent:truncate',
|
||||
userAgent: userAgentString
|
||||
})
|
||||
|
||||
uaParser.parse.reset()
|
||||
log.info.reset()
|
||||
}
|
||||
var context = {}
|
||||
var expected = new Array(11).join('x') + ' (' + new Array(61).join('y') + ')'
|
||||
var userAgentString = expected + new Array(101).join('z')
|
||||
var result = userAgent.call(context, userAgentString, log)
|
||||
)
|
||||
|
||||
t.equal(result.uaBrowser, expected + ELLIPSIS)
|
||||
it(
|
||||
'truncated fallback is relaxed for parentheses',
|
||||
() => {
|
||||
parserResult = {
|
||||
ua: {
|
||||
family: 'Other'
|
||||
},
|
||||
os: {
|
||||
family: 'Other'
|
||||
},
|
||||
device: {
|
||||
family: 'Other'
|
||||
}
|
||||
}
|
||||
var context = {}
|
||||
var expected = new Array(11).join('x') + ' (' + new Array(61).join('y') + ')'
|
||||
var userAgentString = expected + new Array(101).join('z')
|
||||
var result = userAgent.call(context, userAgentString, log)
|
||||
|
||||
t.equal(log.info.callCount, 1)
|
||||
var args = log.info.args[0]
|
||||
t.equal(args.length, 1)
|
||||
t.deepEqual(args[0], {
|
||||
op: 'userAgent:truncate',
|
||||
userAgent: userAgentString
|
||||
})
|
||||
assert.equal(result.uaBrowser, expected + ELLIPSIS)
|
||||
|
||||
t.end()
|
||||
uaParser.parse.reset()
|
||||
log.info.reset()
|
||||
}
|
||||
)
|
||||
assert.equal(log.info.callCount, 1)
|
||||
var args = log.info.args[0]
|
||||
assert.equal(args.length, 1)
|
||||
assert.deepEqual(args[0], {
|
||||
op: 'userAgent:truncate',
|
||||
userAgent: userAgentString
|
||||
})
|
||||
|
||||
uaParser.parse.reset()
|
||||
log.info.reset()
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
|
|
|
@ -2,11 +2,12 @@
|
|||
* 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/. */
|
||||
|
||||
var tap = require('tap')
|
||||
'use strict'
|
||||
|
||||
const assert = require('insist')
|
||||
var proxyquire = require('proxyquire')
|
||||
var uuid = require('uuid')
|
||||
|
||||
var test = tap.test
|
||||
var P = require('../../lib/promise')
|
||||
var mockLog = require('../mocks').mockLog
|
||||
|
||||
|
@ -29,109 +30,115 @@ var mockDb = {
|
|||
}
|
||||
}
|
||||
|
||||
test(
|
||||
'creates reminders with valid options and rate',
|
||||
function (t) {
|
||||
var moduleMocks = {
|
||||
'../config': {
|
||||
'get': function (item) {
|
||||
if (item === 'verificationReminders') {
|
||||
return {
|
||||
rate: 1
|
||||
describe('verification reminders', () => {
|
||||
it(
|
||||
'creates reminders with valid options and rate',
|
||||
() => {
|
||||
var moduleMocks = {
|
||||
'../config': {
|
||||
'get': function (item) {
|
||||
if (item === 'verificationReminders') {
|
||||
return {
|
||||
rate: 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var addedTimes = 0
|
||||
var thisMockLog = mockLog({
|
||||
increment: function (name) {
|
||||
if (name === 'verification-reminders.created') {
|
||||
addedTimes++
|
||||
if (addedTimes === 5) {
|
||||
t.end()
|
||||
var addedTimes = 0
|
||||
var thisMockLog = mockLog({
|
||||
increment: function (name) {
|
||||
if (name === 'verification-reminders.created') {
|
||||
addedTimes++
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
var verificationReminder = proxyquire('../../lib/verification-reminders', moduleMocks)(thisMockLog, mockDb)
|
||||
|
||||
verificationReminder.create(reminderData)
|
||||
verificationReminder.create(reminderData)
|
||||
verificationReminder.create(reminderData)
|
||||
verificationReminder.create(reminderData)
|
||||
verificationReminder.create(reminderData)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'does not create reminders when rate is 0',
|
||||
function (t) {
|
||||
var moduleMocks = {
|
||||
'../config': {
|
||||
'get': function (item) {
|
||||
if (item === 'verificationReminders') {
|
||||
return {
|
||||
rate: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var verificationReminder = proxyquire('../../lib/verification-reminders', moduleMocks)(mockLog, mockDb)
|
||||
verificationReminder.create(reminderData)
|
||||
.then(function (result) {
|
||||
if (result === false) {
|
||||
t.end()
|
||||
}
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'deletes reminders',
|
||||
function (t) {
|
||||
var thisMockLog = mockLog({
|
||||
increment: function (name) {
|
||||
if (name === 'verification-reminders.deleted') {
|
||||
t.end()
|
||||
var verificationReminder = proxyquire('../../lib/verification-reminders', moduleMocks)(thisMockLog, mockDb)
|
||||
|
||||
return P.all([
|
||||
verificationReminder.create(reminderData),
|
||||
verificationReminder.create(reminderData),
|
||||
verificationReminder.create(reminderData),
|
||||
verificationReminder.create(reminderData),
|
||||
verificationReminder.create(reminderData)
|
||||
]).then(() => {
|
||||
assert.equal(addedTimes, 5)
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
it(
|
||||
'does not create reminders when rate is 0',
|
||||
() => {
|
||||
var moduleMocks = {
|
||||
'../config': {
|
||||
'get': function (item) {
|
||||
if (item === 'verificationReminders') {
|
||||
return {
|
||||
rate: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
var thisMockDb = {
|
||||
deleteVerificationReminder: function (reminderData) {
|
||||
t.ok(reminderData.email)
|
||||
t.ok(reminderData.type)
|
||||
return P.resolve()
|
||||
}
|
||||
|
||||
var verificationReminder = proxyquire('../../lib/verification-reminders', moduleMocks)(mockLog, mockDb)
|
||||
verificationReminder.create(reminderData)
|
||||
.then(function (result) {
|
||||
assert.equal(result, false)
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
var verificationReminder = proxyquire('../../lib/verification-reminders', {})(thisMockLog, thisMockDb)
|
||||
verificationReminder.delete(reminderData)
|
||||
}
|
||||
)
|
||||
it(
|
||||
'deletes reminders',
|
||||
() => {
|
||||
let count = 0
|
||||
var thisMockLog = mockLog({
|
||||
increment: function (name) {
|
||||
if (name === 'verification-reminders.deleted') {
|
||||
count++
|
||||
}
|
||||
}
|
||||
})
|
||||
var thisMockDb = {
|
||||
deleteVerificationReminder: function (reminderData) {
|
||||
assert.ok(reminderData.email)
|
||||
assert.ok(reminderData.type)
|
||||
return P.resolve()
|
||||
}
|
||||
}
|
||||
|
||||
test(
|
||||
'deletes reminders can catch errors',
|
||||
function (t) {
|
||||
var thisMockLog = mockLog({
|
||||
error: function (logErr) {
|
||||
t.equal(logErr.op, 'verification-reminder.delete')
|
||||
t.ok(logErr.err.message)
|
||||
t.end()
|
||||
}
|
||||
})
|
||||
var thisMockDb = {
|
||||
deleteVerificationReminder: function () {
|
||||
return P.reject(new Error('Something is wrong'))
|
||||
}
|
||||
var verificationReminder = proxyquire('../../lib/verification-reminders', {})(thisMockLog, thisMockDb)
|
||||
return verificationReminder.delete(reminderData).then(() => {
|
||||
assert.equal(count, 1)
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
var verificationReminder = proxyquire('../../lib/verification-reminders', {})(thisMockLog, thisMockDb)
|
||||
verificationReminder.delete(reminderData)
|
||||
}
|
||||
)
|
||||
it(
|
||||
'deletes reminders can catch errors',
|
||||
() => {
|
||||
let count = 0
|
||||
var thisMockLog = mockLog({
|
||||
error: function (logErr) {
|
||||
assert.equal(logErr.op, 'verification-reminder.delete')
|
||||
assert.ok(logErr.err.message)
|
||||
count++
|
||||
}
|
||||
})
|
||||
var thisMockDb = {
|
||||
deleteVerificationReminder: function () {
|
||||
return P.reject(new Error('Something is wrong'))
|
||||
}
|
||||
}
|
||||
|
||||
var verificationReminder = proxyquire('../../lib/verification-reminders', {})(thisMockLog, thisMockDb)
|
||||
return verificationReminder.delete(reminderData).then(() => {
|
||||
assert.equal(count, 1)
|
||||
})
|
||||
}
|
||||
)
|
||||
})
|
||||
|
|
|
@ -7,13 +7,19 @@ var request = require('request')
|
|||
const EventEmitter = require('events').EventEmitter
|
||||
|
||||
/* eslint-disable no-console */
|
||||
module.exports = function (host, port) {
|
||||
module.exports = function (host, port, printLogs) {
|
||||
|
||||
host = host || '127.0.0.1'
|
||||
port = port || 9001
|
||||
|
||||
const eventEmitter = new EventEmitter()
|
||||
|
||||
function log() {
|
||||
if (printLogs) {
|
||||
console.log.apply(console, arguments)
|
||||
}
|
||||
}
|
||||
|
||||
function waitForCode(email) {
|
||||
return waitForEmail(email)
|
||||
.then(
|
||||
|
@ -26,10 +32,11 @@ module.exports = function (host, port) {
|
|||
|
||||
function loop(name, tries, cb) {
|
||||
var url = 'http://' + host + ':' + port + '/mail/' + encodeURIComponent(name)
|
||||
console.log('checking mail', url)
|
||||
log('checking mail', url)
|
||||
request({ url: url, method: 'GET' },
|
||||
function (err, res, body) {
|
||||
console.log('mail status', res && res.statusCode, 'tries', tries)
|
||||
log('mail status', res && res.statusCode, 'tries', tries)
|
||||
log('mail body', body)
|
||||
var json = null
|
||||
try {
|
||||
json = JSON.parse(body)[0]
|
||||
|
@ -44,7 +51,7 @@ module.exports = function (host, port) {
|
|||
}
|
||||
return setTimeout(loop.bind(null, name, --tries, cb), 1000)
|
||||
}
|
||||
console.log('deleting mail', url)
|
||||
log('deleting mail', url)
|
||||
request({ url: url, method: 'DELETE' },
|
||||
function (err, res, body) {
|
||||
cb(err, json)
|
||||
|
|
|
@ -26,4 +26,12 @@ api.route(
|
|||
]
|
||||
)
|
||||
|
||||
api.start()
|
||||
process.on('SIGINT', () => {
|
||||
process.exit(0)
|
||||
})
|
||||
|
||||
api.start((err) => {
|
||||
if (err) {
|
||||
console.log(err) // eslint-disable-line no-console
|
||||
}
|
||||
})
|
||||
|
|
|
@ -1,57 +0,0 @@
|
|||
/* 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/. */
|
||||
|
||||
/*
|
||||
* A promise-ified version of tap.test.
|
||||
*
|
||||
* This module provides a 'test' function that operates just like tap.test, but
|
||||
* will properly close a promise if the test returns one. This makes it easier
|
||||
* to ensure that any unhandled errors cause the test to fail. Use like so:
|
||||
*
|
||||
* var test = require('./ptap')
|
||||
*
|
||||
* test(
|
||||
* 'an example test',
|
||||
* function (t) {
|
||||
* return someAPI.thingThatReturnsPromise()
|
||||
* .then(function(result) {
|
||||
* t.assertEqual(result, 42)
|
||||
* })
|
||||
* }
|
||||
* )
|
||||
*
|
||||
* Because the test function returns a promise, we get the following for free:
|
||||
*
|
||||
* * wait for the promise to resolve, and call t.end() when it does
|
||||
* * check for unhandled errors and fail the test if they occur
|
||||
*
|
||||
*/
|
||||
|
||||
/* eslint-disable no-console */
|
||||
var tap = require('tap')
|
||||
|
||||
module.exports = function(name, testfunc, parentTest) {
|
||||
var t = parentTest || tap
|
||||
if (!testfunc) {
|
||||
return t.test(name)
|
||||
}
|
||||
var wrappedtestfunc = function(t) {
|
||||
var res = testfunc(t)
|
||||
if (typeof res !== 'undefined') {
|
||||
if (typeof res.done === 'function') {
|
||||
res.done(
|
||||
function() {
|
||||
t.end()
|
||||
},
|
||||
function(err) {
|
||||
console.error(err.stack)
|
||||
t.fail(err.message || err.error || err)
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
return t.test(name, wrappedtestfunc)
|
||||
}
|
|
@ -2,20 +2,29 @@
|
|||
* 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/. */
|
||||
|
||||
var test = require('tap').test
|
||||
'use strict'
|
||||
|
||||
const assert = require('insist')
|
||||
var TestServer = require('../test_server')
|
||||
var crypto = require('crypto')
|
||||
const Client = require('../client')()
|
||||
var config = require('../../config').getProperties()
|
||||
// XXX: update this later to avoid issues.
|
||||
process.env.NODE_ENV = 'dev'
|
||||
|
||||
TestServer.start(config)
|
||||
.then(function main(server) {
|
||||
describe('remote account create', function() {
|
||||
this.timeout(15000)
|
||||
let server
|
||||
before(() => {
|
||||
// XXX: update this later to avoid issues.
|
||||
process.env.NODE_ENV = 'dev'
|
||||
return TestServer.start(config)
|
||||
.then(s => {
|
||||
server = s
|
||||
})
|
||||
})
|
||||
|
||||
test(
|
||||
it(
|
||||
'unverified account fail when getting keys',
|
||||
function (t) {
|
||||
() => {
|
||||
var email = server.uniqueEmail()
|
||||
var password = 'allyourbasearebelongtous'
|
||||
var client = null
|
||||
|
@ -23,7 +32,7 @@ TestServer.start(config)
|
|||
.then(
|
||||
function (x) {
|
||||
client = x
|
||||
t.ok(client.authAt, 'authAt was set')
|
||||
assert.ok(client.authAt, 'authAt was set')
|
||||
}
|
||||
)
|
||||
.then(
|
||||
|
@ -33,19 +42,19 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function (keys) {
|
||||
t.fail('got keys before verifying email')
|
||||
assert(false, 'got keys before verifying email')
|
||||
},
|
||||
function (err) {
|
||||
t.equal(err.errno, 104, 'Unverified account error code')
|
||||
t.equal(err.message, 'Unverified account', 'Unverified account error message')
|
||||
assert.equal(err.errno, 104, 'Unverified account error code')
|
||||
assert.equal(err.message, 'Unverified account', 'Unverified account error message')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'create and verify account',
|
||||
function (t) {
|
||||
() => {
|
||||
var email = server.uniqueEmail()
|
||||
var password = 'allyourbasearebelongtous'
|
||||
var client = null
|
||||
|
@ -53,7 +62,7 @@ TestServer.start(config)
|
|||
.then(
|
||||
function (x) {
|
||||
client = x
|
||||
t.ok(client.authAt, 'authAt was set')
|
||||
assert.ok(client.authAt, 'authAt was set')
|
||||
}
|
||||
)
|
||||
.then(
|
||||
|
@ -63,7 +72,7 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function (status) {
|
||||
t.equal(status.verified, false)
|
||||
assert.equal(status.verified, false)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
|
@ -83,7 +92,7 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function (emailData) {
|
||||
t.equal(
|
||||
assert.equal(
|
||||
emailData.headers['x-link'].indexOf(config.smtp.syncUrl),
|
||||
0,
|
||||
'sync url present')
|
||||
|
@ -96,16 +105,16 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function (status) {
|
||||
t.equal(status.verified, true)
|
||||
assert.equal(status.verified, true)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
test(
|
||||
it(
|
||||
'create account with service identifier and resume',
|
||||
function (t) {
|
||||
() => {
|
||||
var email = server.uniqueEmail()
|
||||
var password = 'allyourbasearebelongtous'
|
||||
var client = null // eslint-disable-line no-unused-vars
|
||||
|
@ -123,16 +132,16 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function (emailData) {
|
||||
t.equal(emailData.headers['x-service-id'], 'abcdef')
|
||||
t.ok(emailData.headers['x-link'].indexOf('resume=foo') > -1)
|
||||
assert.equal(emailData.headers['x-service-id'], 'abcdef')
|
||||
assert.ok(emailData.headers['x-link'].indexOf('resume=foo') > -1)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'create account allows localization of emails',
|
||||
function (t) {
|
||||
() => {
|
||||
var email = server.uniqueEmail()
|
||||
var password = 'allyourbasearebelongtous'
|
||||
var client = null
|
||||
|
@ -149,8 +158,8 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function (emailData) {
|
||||
t.assert(emailData.text.indexOf('Activate now') !== -1, 'not en-US')
|
||||
t.assert(emailData.text.indexOf('Ativar agora') === -1, 'not pt-BR')
|
||||
assert(emailData.text.indexOf('Activate now') !== -1, 'not en-US')
|
||||
assert(emailData.text.indexOf('Ativar agora') === -1, 'not pt-BR')
|
||||
return client.destroyAccount()
|
||||
}
|
||||
)
|
||||
|
@ -171,35 +180,35 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function (emailData) {
|
||||
t.assert(emailData.text.indexOf('Activate now') === -1, 'not en-US')
|
||||
t.assert(emailData.text.indexOf('Ativar agora') !== -1, 'is pt-BR')
|
||||
assert(emailData.text.indexOf('Activate now') === -1, 'not en-US')
|
||||
assert(emailData.text.indexOf('Ativar agora') !== -1, 'is pt-BR')
|
||||
return client.destroyAccount()
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'Unknown account should not exist',
|
||||
function (t) {
|
||||
() => {
|
||||
var client = new Client(config.publicUrl)
|
||||
client.email = server.uniqueEmail()
|
||||
client.authPW = crypto.randomBytes(32)
|
||||
return client.auth()
|
||||
.then(
|
||||
function () {
|
||||
t.fail('account should not exist')
|
||||
assert(false, 'account should not exist')
|
||||
},
|
||||
function (err) {
|
||||
t.equal(err.errno, 102, 'account does not exist')
|
||||
assert.equal(err.errno, 102, 'account does not exist')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'/account/create works with proper data',
|
||||
function (t) {
|
||||
() => {
|
||||
var email = server.uniqueEmail()
|
||||
var password = 'ilikepancakes'
|
||||
var client
|
||||
|
@ -207,7 +216,7 @@ TestServer.start(config)
|
|||
.then(
|
||||
function (x) {
|
||||
client = x
|
||||
t.ok(client.uid, 'account created')
|
||||
assert.ok(client.uid, 'account created')
|
||||
}
|
||||
).then(
|
||||
function () {
|
||||
|
@ -215,15 +224,15 @@ TestServer.start(config)
|
|||
}
|
||||
).then(
|
||||
function () {
|
||||
t.ok(client.sessionToken, 'client can login')
|
||||
assert.ok(client.sessionToken, 'client can login')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'/account/create returns a sessionToken',
|
||||
function (t) {
|
||||
() => {
|
||||
var email = server.uniqueEmail()
|
||||
var password = 'ilikepancakes'
|
||||
var client = new Client(config.publicUrl)
|
||||
|
@ -233,8 +242,8 @@ TestServer.start(config)
|
|||
return c.api.accountCreate(c.email, c.authPW)
|
||||
.then(
|
||||
function (response) {
|
||||
t.ok(response.sessionToken, 'has a sessionToken')
|
||||
t.equal(response.keyFetchToken, undefined, 'no keyFetchToken without keys=true')
|
||||
assert.ok(response.sessionToken, 'has a sessionToken')
|
||||
assert.equal(response.keyFetchToken, undefined, 'no keyFetchToken without keys=true')
|
||||
}
|
||||
)
|
||||
}
|
||||
|
@ -242,9 +251,9 @@ TestServer.start(config)
|
|||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'/account/create returns a keyFetchToken when keys=true',
|
||||
function (t) {
|
||||
() => {
|
||||
var email = server.uniqueEmail()
|
||||
var password = 'ilikepancakes'
|
||||
var client = new Client(config.publicUrl)
|
||||
|
@ -254,8 +263,8 @@ TestServer.start(config)
|
|||
return c.api.accountCreate(c.email, c.authPW, { keys: true })
|
||||
.then(
|
||||
function (response) {
|
||||
t.ok(response.sessionToken, 'has a sessionToken')
|
||||
t.ok(response.keyFetchToken, 'keyFetchToken with keys=true')
|
||||
assert.ok(response.sessionToken, 'has a sessionToken')
|
||||
assert.ok(response.keyFetchToken, 'keyFetchToken with keys=true')
|
||||
}
|
||||
)
|
||||
}
|
||||
|
@ -263,9 +272,9 @@ TestServer.start(config)
|
|||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'signup with same email, different case',
|
||||
function (t) {
|
||||
() => {
|
||||
var email = server.uniqueEmail()
|
||||
var email2 = email.toUpperCase()
|
||||
var password = 'abcdef'
|
||||
|
@ -276,18 +285,18 @@ TestServer.start(config)
|
|||
}
|
||||
)
|
||||
.then(
|
||||
t.fail,
|
||||
assert.fail,
|
||||
function (err) {
|
||||
t.equal(err.code, 400)
|
||||
t.equal(err.errno, 101, 'Account already exists')
|
||||
assert.equal(err.code, 400)
|
||||
assert.equal(err.errno, 101, 'Account already exists')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
're-signup against an unverified email',
|
||||
function (t) {
|
||||
() => {
|
||||
var email = server.uniqueEmail()
|
||||
var password = 'abcdef'
|
||||
return Client.create(config.publicUrl, email, password)
|
||||
|
@ -304,15 +313,15 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function (client) {
|
||||
t.ok(client.uid, 'account created')
|
||||
assert.ok(client.uid, 'account created')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'invalid redirectTo',
|
||||
function (t) {
|
||||
() => {
|
||||
var api = new Client.Api(config.publicUrl)
|
||||
var email = server.uniqueEmail()
|
||||
var authPW = '0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF'
|
||||
|
@ -321,9 +330,9 @@ TestServer.start(config)
|
|||
}
|
||||
return api.accountCreate(email, authPW, options)
|
||||
.then(
|
||||
t.fail,
|
||||
assert.fail,
|
||||
function (err) {
|
||||
t.equal(err.errno, 107, 'bad redirectTo rejected')
|
||||
assert.equal(err.errno, 107, 'bad redirectTo rejected')
|
||||
}
|
||||
)
|
||||
.then(
|
||||
|
@ -332,17 +341,17 @@ TestServer.start(config)
|
|||
}
|
||||
)
|
||||
.then(
|
||||
t.fail,
|
||||
assert.fail,
|
||||
function (err) {
|
||||
t.equal(err.errno, 107, 'bad redirectTo rejected')
|
||||
assert.equal(err.errno, 107, 'bad redirectTo rejected')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'another invalid redirectTo',
|
||||
function (t) {
|
||||
() => {
|
||||
var api = new Client.Api(config.publicUrl)
|
||||
var email = server.uniqueEmail()
|
||||
var authPW = '0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF'
|
||||
|
@ -352,9 +361,9 @@ TestServer.start(config)
|
|||
|
||||
return api.accountCreate(email, authPW, options)
|
||||
.then(
|
||||
t.fail,
|
||||
assert.fail,
|
||||
function (err) {
|
||||
t.equal(err.errno, 107, 'bad redirectTo rejected')
|
||||
assert.equal(err.errno, 107, 'bad redirectTo rejected')
|
||||
}
|
||||
)
|
||||
.then(
|
||||
|
@ -365,46 +374,46 @@ TestServer.start(config)
|
|||
}
|
||||
)
|
||||
.then(
|
||||
t.fail,
|
||||
assert.fail,
|
||||
function (err) {
|
||||
t.equal(err.errno, 107, 'bad redirectTo rejected')
|
||||
assert.equal(err.errno, 107, 'bad redirectTo rejected')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'create account with service query parameter',
|
||||
function (t) {
|
||||
() => {
|
||||
var email = server.uniqueEmail()
|
||||
return Client.create(config.publicUrl, email, 'foo', { serviceQuery: 'bar' })
|
||||
.then(function () {
|
||||
return server.mailbox.waitForEmail(email)
|
||||
})
|
||||
.then(function (emailData) {
|
||||
t.equal(emailData.headers['x-service-id'], 'bar', 'service query parameter was propagated')
|
||||
assert.equal(emailData.headers['x-service-id'], 'bar', 'service query parameter was propagated')
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'account creation works with unicode email address',
|
||||
function (t) {
|
||||
() => {
|
||||
var email = server.uniqueUnicodeEmail()
|
||||
return Client.create(config.publicUrl, email, 'foo')
|
||||
.then(function (client) {
|
||||
t.ok(client, 'created account')
|
||||
assert.ok(client, 'created account')
|
||||
return server.mailbox.waitForEmail(email)
|
||||
})
|
||||
.then(function (emailData) {
|
||||
t.ok(emailData, 'received email')
|
||||
assert.ok(emailData, 'received email')
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'account creation works with minimal metricsContext metadata',
|
||||
function (t) {
|
||||
() => {
|
||||
var email = server.uniqueEmail()
|
||||
return Client.create(config.publicUrl, email, 'foo', {
|
||||
metricsContext: {
|
||||
|
@ -412,14 +421,14 @@ TestServer.start(config)
|
|||
flowBeginTime: 1
|
||||
}
|
||||
}).then(function (client) {
|
||||
t.ok(client, 'created account')
|
||||
assert.ok(client, 'created account')
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'account creation fails with invalid metricsContext flowId',
|
||||
function (t) {
|
||||
() => {
|
||||
var email = server.uniqueEmail()
|
||||
return Client.create(config.publicUrl, email, 'foo', {
|
||||
metricsContext: {
|
||||
|
@ -427,16 +436,16 @@ TestServer.start(config)
|
|||
flowBeginTime: 1
|
||||
}
|
||||
}).then(function () {
|
||||
t.fail('account creation should have failed')
|
||||
assert(false, 'account creation should have failed')
|
||||
}, function (err) {
|
||||
t.ok(err, 'account creation failed')
|
||||
assert.ok(err, 'account creation failed')
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'account creation fails with invalid metricsContext flowBeginTime',
|
||||
function (t) {
|
||||
() => {
|
||||
var email = server.uniqueEmail()
|
||||
return Client.create(config.publicUrl, email, 'foo', {
|
||||
metricsContext: {
|
||||
|
@ -444,16 +453,16 @@ TestServer.start(config)
|
|||
flowBeginTime: 0
|
||||
}
|
||||
}).then(function () {
|
||||
t.fail('account creation should have failed')
|
||||
assert(false, 'account creation should have failed')
|
||||
}, function (err) {
|
||||
t.ok(err, 'account creation failed')
|
||||
assert.ok(err, 'account creation failed')
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'account creation works with maximal metricsContext metadata',
|
||||
function (t) {
|
||||
() => {
|
||||
var email = server.uniqueEmail()
|
||||
return Client.create(config.publicUrl, email, 'foo', {
|
||||
metricsContext: {
|
||||
|
@ -470,58 +479,58 @@ TestServer.start(config)
|
|||
utmTerm: 'frang'
|
||||
}
|
||||
}).then(function (client) {
|
||||
t.ok(client, 'created account')
|
||||
assert.ok(client, 'created account')
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'account creation works with empty metricsContext metadata',
|
||||
function (t) {
|
||||
() => {
|
||||
var email = server.uniqueEmail()
|
||||
return Client.create(config.publicUrl, email, 'foo', {
|
||||
metricsContext: {}
|
||||
}).then(function (client) {
|
||||
t.ok(client, 'created account')
|
||||
assert.ok(client, 'created account')
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'account creation fails with missing flowBeginTime',
|
||||
function (t) {
|
||||
() => {
|
||||
var email = server.uniqueEmail()
|
||||
return Client.create(config.publicUrl, email, 'foo', {
|
||||
metricsContext: {
|
||||
flowId: 'deadbeefbaadf00ddeadbeefbaadf00ddeadbeefbaadf00ddeadbeefbaadf00d'
|
||||
}
|
||||
}).then(function () {
|
||||
t.fail('account creation should have failed')
|
||||
assert(false, 'account creation should have failed')
|
||||
}, function (err) {
|
||||
t.ok(err, 'account creation failed')
|
||||
assert.ok(err, 'account creation failed')
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'account creation fails with missing flowId',
|
||||
function (t) {
|
||||
() => {
|
||||
var email = server.uniqueEmail()
|
||||
return Client.create(config.publicUrl, email, 'foo', {
|
||||
metricsContext: {
|
||||
flowBeginTime: Date.now()
|
||||
}
|
||||
}).then(function () {
|
||||
t.fail('account creation should have failed')
|
||||
assert(false, 'account creation should have failed')
|
||||
}, function (err) {
|
||||
t.ok(err, 'account creation failed')
|
||||
assert.ok(err, 'account creation failed')
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'create account for non-sync service does not get post-verify email',
|
||||
function (t) {
|
||||
() => {
|
||||
var email = server.uniqueEmail()
|
||||
var password = 'allyourbasearebelongtous'
|
||||
var client = null
|
||||
|
@ -529,7 +538,7 @@ TestServer.start(config)
|
|||
.then(
|
||||
function (x) {
|
||||
client = x
|
||||
t.ok('account was created')
|
||||
assert.ok('account was created')
|
||||
}
|
||||
)
|
||||
.then(
|
||||
|
@ -549,7 +558,7 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function (status) {
|
||||
t.equal(status.verified, true)
|
||||
assert.equal(status.verified, true)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
|
@ -567,15 +576,15 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function (code) {
|
||||
t.ok(code, 'the next email was reset-password, not post-verify')
|
||||
assert.ok(code, 'the next email was reset-password, not post-verify')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'create account for unspecified service does not get post-verify email',
|
||||
function (t) {
|
||||
() => {
|
||||
var email = server.uniqueEmail()
|
||||
var password = 'allyourbasearebelongtous'
|
||||
var client = null
|
||||
|
@ -583,7 +592,7 @@ TestServer.start(config)
|
|||
.then(
|
||||
function (x) {
|
||||
client = x
|
||||
t.ok('account was created')
|
||||
assert.ok('account was created')
|
||||
}
|
||||
)
|
||||
.then(
|
||||
|
@ -603,7 +612,7 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function (status) {
|
||||
t.equal(status.verified, true)
|
||||
assert.equal(status.verified, true)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
|
@ -621,17 +630,13 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function (code) {
|
||||
t.ok(code, 'the next email was reset-password, not post-verify')
|
||||
assert.ok(code, 'the next email was reset-password, not post-verify')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'teardown',
|
||||
function (t) {
|
||||
server.stop()
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
after(() => {
|
||||
return TestServer.stop(server)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -2,18 +2,29 @@
|
|||
* 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/. */
|
||||
|
||||
var test = require('../ptaptest')
|
||||
var TestServer = require('../test_server')
|
||||
'use strict'
|
||||
|
||||
const assert = require('insist')
|
||||
const TestServer = require('../test_server')
|
||||
const Client = require('../client')()
|
||||
|
||||
var config = require('../../config').getProperties()
|
||||
const config = require('../../config').getProperties()
|
||||
|
||||
TestServer.start(config)
|
||||
.then(function main(server) {
|
||||
describe('remote account destroy', () => {
|
||||
|
||||
test(
|
||||
let server
|
||||
|
||||
before(function() {
|
||||
this.timeout(15000)
|
||||
return TestServer.start(config)
|
||||
.then(s => {
|
||||
server = s
|
||||
})
|
||||
})
|
||||
|
||||
it(
|
||||
'account destroy',
|
||||
function (t) {
|
||||
() => {
|
||||
var email = server.uniqueEmail()
|
||||
var password = 'allyourbasearebelongtous'
|
||||
var client = null
|
||||
|
@ -36,18 +47,18 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function (keys) {
|
||||
t.fail('account not destroyed')
|
||||
assert(false, 'account not destroyed')
|
||||
},
|
||||
function (err) {
|
||||
t.equal(err.message, 'Unknown account', 'account destroyed')
|
||||
assert.equal(err.message, 'Unknown account', 'account destroyed')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'invalid authPW on account destroy',
|
||||
function (t) {
|
||||
() => {
|
||||
var email = server.uniqueEmail()
|
||||
var password = 'ok'
|
||||
return Client.createAndVerify(config.publicUrl, email, password, server.mailbox)
|
||||
|
@ -58,19 +69,17 @@ TestServer.start(config)
|
|||
}
|
||||
)
|
||||
.then(
|
||||
t.fail,
|
||||
() => {
|
||||
assert(false)
|
||||
},
|
||||
function (err) {
|
||||
t.equal(err.errno, 103)
|
||||
assert.equal(err.errno, 103)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'teardown',
|
||||
function (t) {
|
||||
server.stop()
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
after(() => {
|
||||
return TestServer.stop(server)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -2,8 +2,10 @@
|
|||
* 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/. */
|
||||
|
||||
var test = require('../ptaptest')
|
||||
var TestServer = require('../test_server')
|
||||
'use strict'
|
||||
|
||||
const assert = require('insist')
|
||||
const TestServer = require('../test_server')
|
||||
const Client = require('../client')()
|
||||
|
||||
var config = require('../../config').getProperties()
|
||||
|
@ -13,12 +15,20 @@ var key = {
|
|||
'e': '65537'
|
||||
}
|
||||
|
||||
TestServer.start(config)
|
||||
.then(function main(server) {
|
||||
describe('remote account locale', function() {
|
||||
this.timeout(15000)
|
||||
|
||||
test(
|
||||
let server
|
||||
before(() => {
|
||||
return TestServer.start(config)
|
||||
.then(s => {
|
||||
server = s
|
||||
})
|
||||
})
|
||||
|
||||
it(
|
||||
'signing a cert against an account with no locale will save the locale',
|
||||
function (t) {
|
||||
() => {
|
||||
var email = server.uniqueEmail()
|
||||
var password = 'ilikepancakes'
|
||||
var client
|
||||
|
@ -31,7 +41,7 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function (response) {
|
||||
t.ok(!response.locale, 'account has no locale')
|
||||
assert.ok(!response.locale, 'account has no locale')
|
||||
return client.login()
|
||||
}
|
||||
)
|
||||
|
@ -52,15 +62,15 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function (response) {
|
||||
t.equal(response.locale, 'en-US', 'account has a locale')
|
||||
assert.equal(response.locale, 'en-US', 'account has a locale')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'a really long (invalid) locale',
|
||||
function (t) {
|
||||
() => {
|
||||
var email = server.uniqueEmail()
|
||||
var password = 'ilikepancakes'
|
||||
return Client.create(
|
||||
|
@ -76,15 +86,15 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function (response) {
|
||||
t.ok(!response.locale, 'account has no locale')
|
||||
assert.ok(!response.locale, 'account has no locale')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'a really long (valid) locale',
|
||||
function (t) {
|
||||
() => {
|
||||
var email = server.uniqueEmail()
|
||||
var password = 'ilikepancakes'
|
||||
return Client.create(
|
||||
|
@ -100,17 +110,14 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function (response) {
|
||||
t.equal(response.locale, 'en-US,en;q=0.8', 'account has no locale')
|
||||
assert.equal(response.locale, 'en-US,en;q=0.8', 'account has no locale')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'teardown',
|
||||
function (t) {
|
||||
server.stop()
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
after(() => {
|
||||
return TestServer.stop(server)
|
||||
})
|
||||
|
||||
})
|
||||
|
|
|
@ -2,19 +2,29 @@
|
|||
* 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('assert')
|
||||
const Client = require('../client')()
|
||||
var crypto = require('crypto')
|
||||
var test = require('tap').test
|
||||
var TestServer = require('../test_server')
|
||||
|
||||
var config = require('../../config').getProperties()
|
||||
|
||||
TestServer.start(config)
|
||||
.then(function main(server) {
|
||||
describe('remote account login', () => {
|
||||
let server
|
||||
|
||||
test(
|
||||
before(function() {
|
||||
this.timeout(15000)
|
||||
return TestServer.start(config)
|
||||
.then(s => {
|
||||
server = s
|
||||
})
|
||||
})
|
||||
|
||||
it(
|
||||
'the email is returned in the error on Incorrect password errors',
|
||||
function (t) {
|
||||
() => {
|
||||
var email = server.uniqueEmail()
|
||||
var password = 'abcdef'
|
||||
return Client.createAndVerify(config.publicUrl, email, password, server.mailbox)
|
||||
|
@ -24,19 +34,19 @@ TestServer.start(config)
|
|||
}
|
||||
)
|
||||
.then(
|
||||
t.fail,
|
||||
() => assert(false),
|
||||
function (err) {
|
||||
t.equal(err.code, 400)
|
||||
t.equal(err.errno, 103)
|
||||
t.equal(err.email, email)
|
||||
assert.equal(err.code, 400)
|
||||
assert.equal(err.errno, 103)
|
||||
assert.equal(err.email, email)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'the email is returned in the error on Incorrect email case errors with correct password',
|
||||
function (t) {
|
||||
() => {
|
||||
var signupEmail = server.uniqueEmail()
|
||||
var loginEmail = signupEmail.toUpperCase()
|
||||
var password = 'abcdef'
|
||||
|
@ -47,37 +57,37 @@ TestServer.start(config)
|
|||
}
|
||||
)
|
||||
.then(
|
||||
t.fail,
|
||||
() => assert(false),
|
||||
function (err) {
|
||||
t.equal(err.code, 400)
|
||||
t.equal(err.errno, 120)
|
||||
t.equal(err.email, signupEmail)
|
||||
assert.equal(err.code, 400)
|
||||
assert.equal(err.errno, 120)
|
||||
assert.equal(err.email, signupEmail)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'Unknown account should not exist',
|
||||
function (t) {
|
||||
() => {
|
||||
var client = new Client(config.publicUrl)
|
||||
client.email = server.uniqueEmail()
|
||||
client.authPW = crypto.randomBytes(32)
|
||||
return client.login()
|
||||
.then(
|
||||
function () {
|
||||
t.fail('account should not exist')
|
||||
assert(false, 'account should not exist')
|
||||
},
|
||||
function (err) {
|
||||
t.equal(err.errno, 102, 'account does not exist')
|
||||
assert.equal(err.errno, 102, 'account does not exist')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'No keyFetchToken without keys=true',
|
||||
function (t) {
|
||||
() => {
|
||||
var email = server.uniqueEmail()
|
||||
var password = 'abcdef'
|
||||
return Client.createAndVerify(config.publicUrl, email, password, server.mailbox)
|
||||
|
@ -88,15 +98,15 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function (c) {
|
||||
t.equal(c.keyFetchToken, null, 'should not have keyFetchToken')
|
||||
assert.equal(c.keyFetchToken, null, 'should not have keyFetchToken')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'login works with unicode email address',
|
||||
function (t) {
|
||||
() => {
|
||||
var email = server.uniqueUnicodeEmail()
|
||||
var password = 'wibble'
|
||||
return Client.createAndVerify(config.publicUrl, email, password, server.mailbox)
|
||||
|
@ -107,15 +117,15 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function (client) {
|
||||
t.ok(client, 'logged in to account')
|
||||
assert.ok(client, 'logged in to account')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'account login works with minimal metricsContext metadata',
|
||||
function (t) {
|
||||
() => {
|
||||
var email = server.uniqueEmail()
|
||||
return Client.createAndVerify(config.publicUrl, email, 'foo', server.mailbox)
|
||||
.then(function () {
|
||||
|
@ -127,14 +137,14 @@ TestServer.start(config)
|
|||
})
|
||||
})
|
||||
.then(function (client) {
|
||||
t.ok(client, 'logged in to account')
|
||||
assert.ok(client, 'logged in to account')
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'account login fails with invalid metricsContext flowId',
|
||||
function (t) {
|
||||
() => {
|
||||
var email = server.uniqueEmail()
|
||||
return Client.createAndVerify(config.publicUrl, email, 'foo', server.mailbox)
|
||||
.then(function () {
|
||||
|
@ -146,16 +156,16 @@ TestServer.start(config)
|
|||
})
|
||||
})
|
||||
.then(function () {
|
||||
t.fail('account login should have failed')
|
||||
assert(false, 'account login should have failed')
|
||||
}, function (err) {
|
||||
t.ok(err, 'account login failed')
|
||||
assert.ok(err, 'account login failed')
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'account login fails with invalid metricsContext flowBeginTime',
|
||||
function (t) {
|
||||
() => {
|
||||
var email = server.uniqueEmail()
|
||||
return Client.createAndVerify(config.publicUrl, email, 'foo', server.mailbox)
|
||||
.then(function () {
|
||||
|
@ -167,18 +177,14 @@ TestServer.start(config)
|
|||
})
|
||||
})
|
||||
.then(function () {
|
||||
t.fail('account login should have failed')
|
||||
assert(false, 'account login should have failed')
|
||||
}, function (err) {
|
||||
t.ok(err, 'account login failed')
|
||||
assert.ok(err, 'account login failed')
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'teardown',
|
||||
function (t) {
|
||||
server.stop()
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
after(() => {
|
||||
return TestServer.stop(server)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -2,15 +2,14 @@
|
|||
* 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/. */
|
||||
|
||||
var test = require('tap').test
|
||||
'use strict'
|
||||
|
||||
const assert = require('insist')
|
||||
var TestServer = require('../test_server')
|
||||
const Client = require('../client')()
|
||||
var JWTool = require('fxa-jwtool')
|
||||
|
||||
var config = require('../../config').getProperties()
|
||||
process.env.TRUSTED_JKUS = 'http://127.0.0.1:9000/.well-known/public-keys'
|
||||
process.env.SIGNIN_CONFIRMATION_ENABLED = false
|
||||
|
||||
var secretKey = JWTool.JWK.fromFile(
|
||||
config.secretKeyFile,
|
||||
{
|
||||
|
@ -25,12 +24,22 @@ function nowSeconds() {
|
|||
return Math.floor(Date.now() / 1000)
|
||||
}
|
||||
|
||||
TestServer.start(config)
|
||||
.then(function main(server) {
|
||||
describe('remote account preverified token', function() {
|
||||
this.timeout(15000)
|
||||
let server
|
||||
before(() => {
|
||||
process.env.TRUSTED_JKUS = 'http://127.0.0.1:9000/.well-known/public-keys'
|
||||
process.env.SIGNIN_CONFIRMATION_ENABLED = false
|
||||
|
||||
test(
|
||||
return TestServer.start(config)
|
||||
.then(s => {
|
||||
server = s
|
||||
})
|
||||
})
|
||||
|
||||
it(
|
||||
'a valid preVerifyToken creates a verified account',
|
||||
function (t) {
|
||||
() => {
|
||||
var email = server.uniqueEmail()
|
||||
var password = 'ok'
|
||||
var token = secretKey.signSync(
|
||||
|
@ -48,16 +57,16 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function (keys) {
|
||||
t.ok(Buffer.isBuffer(keys.kA), 'kA exists')
|
||||
t.ok(Buffer.isBuffer(keys.wrapKb), 'wrapKb exists')
|
||||
assert.ok(Buffer.isBuffer(keys.kA), 'kA exists')
|
||||
assert.ok(Buffer.isBuffer(keys.wrapKb), 'wrapKb exists')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'an invalid preVerifyToken return an invalid verification code error',
|
||||
function (t) {
|
||||
() => {
|
||||
var email = server.uniqueEmail()
|
||||
var password = 'ok'
|
||||
var token = secretKey.signSync(
|
||||
|
@ -71,15 +80,15 @@ TestServer.start(config)
|
|||
.then(
|
||||
fail,
|
||||
function (err) {
|
||||
t.equal(err.errno, 105, 'invalid verification code')
|
||||
assert.equal(err.errno, 105, 'invalid verification code')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
're-signup against an unverified email',
|
||||
function (t) {
|
||||
function() {
|
||||
var email = server.uniqueEmail()
|
||||
var password = 'abcdef'
|
||||
return Client.create(config.publicUrl, email, password)
|
||||
|
@ -103,24 +112,20 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function (client) {
|
||||
t.ok(client.uid, 'account created')
|
||||
assert.ok(client.uid, 'account created')
|
||||
return client.keys()
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (keys) {
|
||||
t.ok(Buffer.isBuffer(keys.kA), 'kA exists')
|
||||
t.ok(Buffer.isBuffer(keys.wrapKb), 'wrapKb exists')
|
||||
assert.ok(Buffer.isBuffer(keys.kA), 'kA exists')
|
||||
assert.ok(Buffer.isBuffer(keys.wrapKb), 'wrapKb exists')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'teardown',
|
||||
function (t) {
|
||||
server.stop()
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
after(() => {
|
||||
return TestServer.stop(server)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -2,12 +2,13 @@
|
|||
* 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 path = require('path')
|
||||
var test = require('../ptaptest')
|
||||
var TestServer = require('../test_server')
|
||||
const Client = require('../client')()
|
||||
|
||||
process.env.CONFIG_FILES = path.join(__dirname, '../config/mock_oauth.json')
|
||||
var config = require('../../config').getProperties()
|
||||
|
||||
function makeMockOAuthHeader(opts) {
|
||||
|
@ -15,12 +16,21 @@ function makeMockOAuthHeader(opts) {
|
|||
return 'Bearer ' + token
|
||||
}
|
||||
|
||||
TestServer.start(config)
|
||||
.then(function main(server) {
|
||||
describe('remote account profile', function() {
|
||||
this.timeout(15000)
|
||||
|
||||
test(
|
||||
let server
|
||||
before(() => {
|
||||
process.env.CONFIG_FILES = path.join(__dirname, '../config/mock_oauth.json')
|
||||
return TestServer.start(config)
|
||||
.then(s => {
|
||||
server = s
|
||||
})
|
||||
})
|
||||
|
||||
it(
|
||||
'account profile authenticated with session returns profile data',
|
||||
function (t) {
|
||||
() => {
|
||||
return Client.create(config.publicUrl, server.uniqueEmail(), 'password', { lang: 'en-US' })
|
||||
.then(
|
||||
function (c) {
|
||||
|
@ -29,16 +39,16 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function (response) {
|
||||
t.ok(response.email, 'email address is returned')
|
||||
t.equal(response.locale, 'en-US', 'locale is returned')
|
||||
assert.ok(response.email, 'email address is returned')
|
||||
assert.equal(response.locale, 'en-US', 'locale is returned')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'account profile authenticated with oauth returns profile data',
|
||||
function (t) {
|
||||
() => {
|
||||
return Client.create(config.publicUrl, server.uniqueEmail(), 'password', { lang: 'en-US' })
|
||||
.then(
|
||||
function (c) {
|
||||
|
@ -52,16 +62,16 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function (response) {
|
||||
t.ok(response.email, 'email address is returned')
|
||||
t.equal(response.locale, 'en-US', 'locale is returned')
|
||||
assert.ok(response.email, 'email address is returned')
|
||||
assert.equal(response.locale, 'en-US', 'locale is returned')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'account profile authenticated with invalid oauth token returns an error',
|
||||
function (t) {
|
||||
() => {
|
||||
return Client.create(config.publicUrl, server.uniqueEmail(), 'password', { lang: 'en-US' })
|
||||
.then(
|
||||
function (c) {
|
||||
|
@ -75,24 +85,24 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function () {
|
||||
t.fail('should get an error')
|
||||
assert(false, 'should get an error')
|
||||
},
|
||||
function (e) {
|
||||
t.equal(e.code, 401, 'correct error status code')
|
||||
t.equal(e.errno, 110, 'correct errno')
|
||||
assert.equal(e.code, 401, 'correct error status code')
|
||||
assert.equal(e.errno, 110, 'correct errno')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'account status authenticated with oauth for unknown uid returns an error',
|
||||
function (t) {
|
||||
() => {
|
||||
return Client.create(config.publicUrl, server.uniqueEmail(), 'password', { lang: 'en-US' })
|
||||
.then(
|
||||
function (c) {
|
||||
var UNKNOWN_UID = 'abcdef123456'
|
||||
t.notEqual(c.uid, UNKNOWN_UID)
|
||||
assert.notEqual(c.uid, UNKNOWN_UID)
|
||||
return c.api.accountProfile(null, {
|
||||
Authorization: makeMockOAuthHeader({
|
||||
user: UNKNOWN_UID,
|
||||
|
@ -103,19 +113,19 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function () {
|
||||
t.fail('should get an error')
|
||||
assert(false, 'should get an error')
|
||||
},
|
||||
function (e) {
|
||||
t.equal(e.code, 400, 'correct error status code')
|
||||
t.equal(e.errno, 102, 'correct errno')
|
||||
assert.equal(e.code, 400, 'correct error status code')
|
||||
assert.equal(e.errno, 102, 'correct errno')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'account status authenticated with oauth for wrong scope returns no info',
|
||||
function (t) {
|
||||
() => {
|
||||
return Client.create(config.publicUrl, server.uniqueEmail(), 'password', { lang: 'en-US' })
|
||||
.then(
|
||||
function (c) {
|
||||
|
@ -129,15 +139,15 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function (response) {
|
||||
t.deepEqual(response, {}, 'no info should be returned')
|
||||
assert.deepEqual(response, {}, 'no info should be returned')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'account profile authenticated with limited oauth scopes returns limited profile data',
|
||||
function (t) {
|
||||
() => {
|
||||
var client
|
||||
return Client.create(config.publicUrl, server.uniqueEmail(), 'password', { lang: 'en-US' })
|
||||
.then(
|
||||
|
@ -153,8 +163,8 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function (response) {
|
||||
t.ok(response.email, 'email address is returned')
|
||||
t.ok(!response.locale, 'locale should not be returned')
|
||||
assert.ok(response.email, 'email address is returned')
|
||||
assert.ok(!response.locale, 'locale should not be returned')
|
||||
}
|
||||
)
|
||||
.then(
|
||||
|
@ -169,16 +179,16 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function (response) {
|
||||
t.ok(!response.email, 'email address should not be returned')
|
||||
t.equal(response.locale, 'en-US', 'locale is returned')
|
||||
assert.ok(!response.email, 'email address should not be returned')
|
||||
assert.equal(response.locale, 'en-US', 'locale is returned')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'account profile authenticated with oauth :write scopes returns profile data',
|
||||
function (t) {
|
||||
() => {
|
||||
var client
|
||||
return Client.create(config.publicUrl, server.uniqueEmail(), 'password', { lang: 'en-US' })
|
||||
.then(
|
||||
|
@ -194,8 +204,8 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function (response) {
|
||||
t.ok(response.email, 'email address is returned')
|
||||
t.ok(response.locale, 'locale is returned')
|
||||
assert.ok(response.email, 'email address is returned')
|
||||
assert.ok(response.locale, 'locale is returned')
|
||||
}
|
||||
)
|
||||
.then(
|
||||
|
@ -210,8 +220,8 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function (response) {
|
||||
t.ok(!response.email, 'email address should not be returned')
|
||||
t.ok(response.locale, 'locale is returned')
|
||||
assert.ok(!response.email, 'email address should not be returned')
|
||||
assert.ok(response.locale, 'locale is returned')
|
||||
}
|
||||
)
|
||||
.then(
|
||||
|
@ -226,16 +236,16 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function (response) {
|
||||
t.ok(response.email, 'email address is returned')
|
||||
t.ok(!response.locale, 'locale should not be returned')
|
||||
assert.ok(response.email, 'email address is returned')
|
||||
assert.ok(!response.locale, 'locale should not be returned')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'account profile works with unicode email address',
|
||||
function (t) {
|
||||
() => {
|
||||
var email = server.uniqueUnicodeEmail()
|
||||
return Client.create(config.publicUrl, email, 'password')
|
||||
.then(
|
||||
|
@ -245,17 +255,14 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function (response) {
|
||||
t.equal(response.email, email, 'email address is returned')
|
||||
assert.equal(response.email, email, 'email address is returned')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'teardown',
|
||||
function (t) {
|
||||
server.stop()
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
after(() => {
|
||||
delete process.env.CONFIG_FILES
|
||||
return TestServer.stop(server)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -2,233 +2,239 @@
|
|||
* 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/. */
|
||||
|
||||
var test = require('tap').test
|
||||
'use strict'
|
||||
|
||||
const assert = require('insist')
|
||||
var url = require('url')
|
||||
const Client = require('../client')()
|
||||
var TestServer = require('../test_server')
|
||||
|
||||
var config = require('../../config').getProperties()
|
||||
process.env.SIGNIN_CONFIRMATION_ENABLED = false
|
||||
|
||||
TestServer.start(config)
|
||||
.then(function main(server) {
|
||||
|
||||
test(
|
||||
'account reset w/o sessionToken',
|
||||
function (t) {
|
||||
var email = server.uniqueEmail()
|
||||
var password = 'allyourbasearebelongtous'
|
||||
var newPassword = 'ez'
|
||||
var wrapKb, kA, client
|
||||
|
||||
return Client.createAndVerify(config.publicUrl, email, password, server.mailbox, {keys:true})
|
||||
.then(
|
||||
function (x) {
|
||||
client = x
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
return client.keys()
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (keys) {
|
||||
wrapKb = keys.wrapKb
|
||||
kA = keys.kA
|
||||
return client.forgotPassword()
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
return server.mailbox.waitForCode(email)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (code) {
|
||||
t.throws(function() {
|
||||
client.resetPassword(newPassword)
|
||||
})
|
||||
return resetPassword(client, code, newPassword, {sessionToken: false})
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (response) {
|
||||
t.notOk(response.sessionToken, 'session token is not in response')
|
||||
t.notOk(response.keyFetchToken, 'keyFetchToken token is not in response')
|
||||
t.notOk(response.verified, 'verified is not in response')
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
return server.mailbox.waitForEmail(email)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (emailData) {
|
||||
var link = emailData.headers['x-link']
|
||||
var query = url.parse(link, true).query
|
||||
t.ok(query.email, 'email is in the link')
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
// make sure we can still login after password reset
|
||||
return Client.login(config.publicUrl, email, newPassword, server.mailbox, {keys:true})
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (x) {
|
||||
client = x
|
||||
return client.keys()
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (keys) {
|
||||
t.ok(Buffer.isBuffer(keys.wrapKb), 'yep, wrapKb')
|
||||
t.notDeepEqual(wrapKb, keys.wrapKb, 'wrapKb was reset')
|
||||
t.deepEqual(kA, keys.kA, 'kA was not reset')
|
||||
t.equal(client.kB.length, 32, 'kB exists, has the right length')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'account reset with keys',
|
||||
function (t) {
|
||||
var email = server.uniqueEmail()
|
||||
var password = 'allyourbasearebelongtous'
|
||||
var newPassword = 'ez'
|
||||
var wrapKb, kA, client
|
||||
|
||||
return Client.createAndVerify(config.publicUrl, email, password, server.mailbox, {keys:true})
|
||||
.then(
|
||||
function (x) {
|
||||
client = x
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
return client.keys()
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (keys) {
|
||||
wrapKb = keys.wrapKb
|
||||
kA = keys.kA
|
||||
return client.forgotPassword()
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
return server.mailbox.waitForCode(email)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (code) {
|
||||
t.throws(function() {
|
||||
client.resetPassword(newPassword)
|
||||
})
|
||||
return resetPassword(client, code, newPassword, {keys:true})
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (response) {
|
||||
t.ok(response.sessionToken, 'session token is in response')
|
||||
t.ok(response.keyFetchToken, 'keyFetchToken token is in response')
|
||||
t.equal(response.verified, true, 'verified is true')
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
return server.mailbox.waitForEmail(email)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (emailData) {
|
||||
var link = emailData.headers['x-link']
|
||||
var query = url.parse(link, true).query
|
||||
t.ok(query.email, 'email is in the link')
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
// make sure we can still login after password reset
|
||||
return Client.login(config.publicUrl, email, newPassword, server.mailbox, {keys:true})
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (x) {
|
||||
client = x
|
||||
return client.keys()
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (keys) {
|
||||
t.ok(Buffer.isBuffer(keys.wrapKb), 'yep, wrapKb')
|
||||
t.notDeepEqual(wrapKb, keys.wrapKb, 'wrapKb was reset')
|
||||
t.deepEqual(kA, keys.kA, 'kA was not reset')
|
||||
t.equal(client.kB.length, 32, 'kB exists, has the right length')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'account reset w/o keys, with sessionToken',
|
||||
function (t) {
|
||||
var email = server.uniqueEmail()
|
||||
var password = 'allyourbasearebelongtous'
|
||||
var newPassword = 'ez'
|
||||
var client
|
||||
|
||||
return Client.createAndVerify(config.publicUrl, email, password, server.mailbox)
|
||||
.then(
|
||||
function (x) {
|
||||
client = x
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
return client.forgotPassword()
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
return server.mailbox.waitForCode(email)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (code) {
|
||||
t.throws(function() {
|
||||
client.resetPassword(newPassword)
|
||||
})
|
||||
return resetPassword(client, code, newPassword)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (response) {
|
||||
t.ok(response.sessionToken, 'session token is in response')
|
||||
t.notOk(response.keyFetchToken, 'keyFetchToken token is not in response')
|
||||
t.equal(response.verified, true, 'verified is true')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'teardown',
|
||||
function (t) {
|
||||
server.stop()
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
describe('remote account reset', function() {
|
||||
this.timeout(15000)
|
||||
let server
|
||||
before(() => {
|
||||
process.env.SIGNIN_CONFIRMATION_ENABLED = false
|
||||
return TestServer.start(config)
|
||||
.then(s => {
|
||||
server = s
|
||||
})
|
||||
})
|
||||
|
||||
function resetPassword(client, code, newPassword, options) {
|
||||
return client.verifyPasswordResetCode(code)
|
||||
.then(function() {
|
||||
return client.resetPassword(newPassword, {}, options)
|
||||
})
|
||||
}
|
||||
it(
|
||||
'account reset w/o sessionToken',
|
||||
() => {
|
||||
var email = server.uniqueEmail()
|
||||
var password = 'allyourbasearebelongtous'
|
||||
var newPassword = 'ez'
|
||||
var wrapKb, kA, client
|
||||
|
||||
return Client.createAndVerify(config.publicUrl, email, password, server.mailbox, {keys:true})
|
||||
.then(
|
||||
function (x) {
|
||||
client = x
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
return client.keys()
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (keys) {
|
||||
wrapKb = keys.wrapKb
|
||||
kA = keys.kA
|
||||
return client.forgotPassword()
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
return server.mailbox.waitForCode(email)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (code) {
|
||||
assert.throws(function() {
|
||||
client.resetPassword(newPassword)
|
||||
})
|
||||
return resetPassword(client, code, newPassword, {sessionToken: false})
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (response) {
|
||||
assert(!response.sessionToken, 'session token is not in response')
|
||||
assert(!response.keyFetchToken, 'keyFetchToken token is not in response')
|
||||
assert(!response.verified, 'verified is not in response')
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
return server.mailbox.waitForEmail(email)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (emailData) {
|
||||
var link = emailData.headers['x-link']
|
||||
var query = url.parse(link, true).query
|
||||
assert.ok(query.email, 'email is in the link')
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
// make sure we can still login after password reset
|
||||
return Client.login(config.publicUrl, email, newPassword, server.mailbox, {keys:true})
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (x) {
|
||||
client = x
|
||||
return client.keys()
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (keys) {
|
||||
assert.ok(Buffer.isBuffer(keys.wrapKb), 'yep, wrapKb')
|
||||
assert.notDeepEqual(wrapKb, keys.wrapKb, 'wrapKb was reset')
|
||||
assert.deepEqual(kA, keys.kA, 'kA was not reset')
|
||||
assert.equal(client.kB.length, 32, 'kB exists, has the right length')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
it(
|
||||
'account reset with keys',
|
||||
() => {
|
||||
var email = server.uniqueEmail()
|
||||
var password = 'allyourbasearebelongtous'
|
||||
var newPassword = 'ez'
|
||||
var wrapKb, kA, client
|
||||
|
||||
return Client.createAndVerify(config.publicUrl, email, password, server.mailbox, {keys:true})
|
||||
.then(
|
||||
function (x) {
|
||||
client = x
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
return client.keys()
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (keys) {
|
||||
wrapKb = keys.wrapKb
|
||||
kA = keys.kA
|
||||
return client.forgotPassword()
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
return server.mailbox.waitForCode(email)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (code) {
|
||||
assert.throws(function() {
|
||||
client.resetPassword(newPassword)
|
||||
})
|
||||
return resetPassword(client, code, newPassword, {keys:true})
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (response) {
|
||||
assert.ok(response.sessionToken, 'session token is in response')
|
||||
assert.ok(response.keyFetchToken, 'keyFetchToken token is in response')
|
||||
assert.equal(response.verified, true, 'verified is true')
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
return server.mailbox.waitForEmail(email)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (emailData) {
|
||||
var link = emailData.headers['x-link']
|
||||
var query = url.parse(link, true).query
|
||||
assert.ok(query.email, 'email is in the link')
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
// make sure we can still login after password reset
|
||||
return Client.login(config.publicUrl, email, newPassword, server.mailbox, {keys:true})
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (x) {
|
||||
client = x
|
||||
return client.keys()
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (keys) {
|
||||
assert.ok(Buffer.isBuffer(keys.wrapKb), 'yep, wrapKb')
|
||||
assert.notDeepEqual(wrapKb, keys.wrapKb, 'wrapKb was reset')
|
||||
assert.deepEqual(kA, keys.kA, 'kA was not reset')
|
||||
assert.equal(client.kB.length, 32, 'kB exists, has the right length')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
it(
|
||||
'account reset w/o keys, with sessionToken',
|
||||
() => {
|
||||
var email = server.uniqueEmail()
|
||||
var password = 'allyourbasearebelongtous'
|
||||
var newPassword = 'ez'
|
||||
var client
|
||||
|
||||
return Client.createAndVerify(config.publicUrl, email, password, server.mailbox)
|
||||
.then(
|
||||
function (x) {
|
||||
client = x
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
return client.forgotPassword()
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
return server.mailbox.waitForCode(email)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (code) {
|
||||
assert.throws(function() {
|
||||
client.resetPassword(newPassword)
|
||||
})
|
||||
return resetPassword(client, code, newPassword)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (response) {
|
||||
assert.ok(response.sessionToken, 'session token is in response')
|
||||
assert(!response.keyFetchToken, 'keyFetchToken token is not in response')
|
||||
assert.equal(response.verified, true, 'verified is true')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
after(() => {
|
||||
delete process.env.SIGNIN_CONFIRMATION_ENABLE
|
||||
return TestServer.stop(server)
|
||||
})
|
||||
|
||||
function resetPassword(client, code, newPassword, options) {
|
||||
return client.verifyPasswordResetCode(code)
|
||||
.then(function() {
|
||||
return client.resetPassword(newPassword, {}, options)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
|
|
@ -2,129 +2,137 @@
|
|||
* 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/. */
|
||||
|
||||
var test = require('../ptaptest')
|
||||
'use strict'
|
||||
|
||||
const assert = require('insist')
|
||||
var TestServer = require('../test_server')
|
||||
const Client = require('../client')()
|
||||
|
||||
test(
|
||||
'signin confirmation can be disabled',
|
||||
function (t) {
|
||||
var config = require('../../config').getProperties()
|
||||
process.env.SIGNIN_CONFIRMATION_ENABLED = false
|
||||
var server, email, client
|
||||
var password = 'allyourbasearebelongtous'
|
||||
describe('remote account signin verification enable', function() {
|
||||
this.timeout(30000)
|
||||
it(
|
||||
'signin confirmation can be disabled',
|
||||
() => {
|
||||
process.env.SIGNIN_CONFIRMATION_ENABLED = false
|
||||
var config = require('../../config').getProperties()
|
||||
var server, email, client
|
||||
var password = 'allyourbasearebelongtous'
|
||||
|
||||
TestServer.start(config)
|
||||
.then(function main(serverObj) {
|
||||
server = serverObj
|
||||
email = server.uniqueEmail()
|
||||
})
|
||||
.then(function() {
|
||||
return Client.createAndVerify(config.publicUrl, email, password, server.mailbox, {keys:true})
|
||||
})
|
||||
.then(
|
||||
function (x) {
|
||||
client = x
|
||||
t.ok(client.authAt, 'authAt was set')
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
return client.emailStatus()
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (status) {
|
||||
t.equal(status.verified, true, 'account is verified')
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
return client.login({keys:true})
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (response) {
|
||||
t.notEqual(response.verificationMethod, 'email', 'verification method not set')
|
||||
t.notEqual(response.verificationReason, 'login', 'verification reason not set')
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
return client.emailStatus()
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (status) {
|
||||
t.equal(status.verified, true, 'account is verified')
|
||||
}
|
||||
)
|
||||
.done(function() {
|
||||
server.stop()
|
||||
t.end()
|
||||
})
|
||||
}
|
||||
)
|
||||
return TestServer.start(config)
|
||||
.then(function main(serverObj) {
|
||||
server = serverObj
|
||||
email = server.uniqueEmail()
|
||||
})
|
||||
.then(function() {
|
||||
return Client.createAndVerify(config.publicUrl, email, password, server.mailbox, {keys:true})
|
||||
})
|
||||
.then(
|
||||
function (x) {
|
||||
client = x
|
||||
assert.ok(client.authAt, 'authAt was set')
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
return client.emailStatus()
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (status) {
|
||||
assert.equal(status.verified, true, 'account is verified')
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
return client.login({keys:true})
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (response) {
|
||||
assert.notEqual(response.verificationMethod, 'email', 'verification method not set')
|
||||
assert.notEqual(response.verificationReason, 'login', 'verification reason not set')
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
return client.emailStatus()
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (status) {
|
||||
assert.equal(status.verified, true, 'account is verified')
|
||||
}
|
||||
)
|
||||
.then(function() {
|
||||
return TestServer.stop(server)
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'signin confirmation can be enabled',
|
||||
function (t) {
|
||||
process.env.SIGNIN_CONFIRMATION_ENABLED = true
|
||||
process.env.SIGNIN_CONFIRMATION_RATE = 1.0
|
||||
var config = require('../../config').getProperties()
|
||||
var server, email, client
|
||||
var password = 'allyourbasearebelongtous'
|
||||
it(
|
||||
'signin confirmation can be enabled',
|
||||
() => {
|
||||
process.env.SIGNIN_CONFIRMATION_ENABLED = true
|
||||
process.env.SIGNIN_CONFIRMATION_RATE = 1.0
|
||||
var config = require('../../config').getProperties()
|
||||
var server, email, client
|
||||
var password = 'allyourbasearebelongtous'
|
||||
|
||||
TestServer.start(config)
|
||||
.then(function main(serverObj) {
|
||||
server = serverObj
|
||||
email = server.uniqueEmail()
|
||||
})
|
||||
.then(function() {
|
||||
return Client.createAndVerify(config.publicUrl, email, password, server.mailbox, {keys:true})
|
||||
})
|
||||
.then(
|
||||
function (x) {
|
||||
client = x
|
||||
t.ok(client.authAt, 'authAt was set')
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
return client.emailStatus()
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (status) {
|
||||
t.equal(status.verified, true, 'account is verified')
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
return client.login({keys:true})
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (response) {
|
||||
t.equal(response.verificationMethod, 'email', 'verification method set')
|
||||
t.equal(response.verificationReason, 'login', 'verification reason set')
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
return client.emailStatus()
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (status) {
|
||||
t.equal(status.verified, false, 'account is not verified')
|
||||
t.equal(status.emailVerified, true, 'email is verified')
|
||||
t.equal(status.sessionVerified, false, 'session is not verified')
|
||||
}
|
||||
)
|
||||
.done(function() {
|
||||
server.stop()
|
||||
t.end()
|
||||
})
|
||||
}
|
||||
)
|
||||
TestServer.start(config)
|
||||
.then(function main(serverObj) {
|
||||
server = serverObj
|
||||
email = server.uniqueEmail()
|
||||
})
|
||||
.then(function() {
|
||||
return Client.createAndVerify(config.publicUrl, email, password, server.mailbox, {keys:true})
|
||||
})
|
||||
.then(
|
||||
function (x) {
|
||||
client = x
|
||||
assert.ok(client.authAt, 'authAt was set')
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
return client.emailStatus()
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (status) {
|
||||
assert.equal(status.verified, true, 'account is verified')
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
return client.login({keys:true})
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (response) {
|
||||
assert.equal(response.verificationMethod, 'email', 'verification method set')
|
||||
assert.equal(response.verificationReason, 'login', 'verification reason set')
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
return client.emailStatus()
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (status) {
|
||||
assert.equal(status.verified, false, 'account is not verified')
|
||||
assert.equal(status.emailVerified, true, 'email is verified')
|
||||
assert.equal(status.sessionVerified, false, 'session is not verified')
|
||||
}
|
||||
)
|
||||
.then(function() {
|
||||
return TestServer.stop(server)
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
after(() => {
|
||||
delete process.env.SIGNIN_CONFIRMATION_ENABLED
|
||||
TestServer.stop()
|
||||
})
|
||||
})
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -2,18 +2,27 @@
|
|||
* 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/. */
|
||||
|
||||
var test = require('../ptaptest')
|
||||
'use strict'
|
||||
|
||||
const assert = require('insist')
|
||||
var TestServer = require('../test_server')
|
||||
const Client = require('../client')()
|
||||
|
||||
var config = require('../../config').getProperties()
|
||||
|
||||
TestServer.start(config)
|
||||
.then(function main(server) {
|
||||
describe('remote account status', function() {
|
||||
this.timeout(15000)
|
||||
let server
|
||||
before(() => {
|
||||
return TestServer.start(config)
|
||||
.then(s => {
|
||||
server = s
|
||||
})
|
||||
})
|
||||
|
||||
test(
|
||||
it(
|
||||
'account status with existing account',
|
||||
function (t) {
|
||||
() => {
|
||||
return Client.create(config.publicUrl, server.uniqueEmail(), 'password')
|
||||
.then(
|
||||
function (c) {
|
||||
|
@ -22,15 +31,15 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function (response) {
|
||||
t.ok(response.exists, 'account exists')
|
||||
assert.ok(response.exists, 'account exists')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'account status includes locale when authenticated',
|
||||
function (t) {
|
||||
() => {
|
||||
return Client.create(config.publicUrl, server.uniqueEmail(), 'password', { lang: 'en-US' })
|
||||
.then(
|
||||
function (c) {
|
||||
|
@ -39,15 +48,15 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function (response) {
|
||||
t.equal(response.locale, 'en-US', 'locale is stored')
|
||||
assert.equal(response.locale, 'en-US', 'locale is stored')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'account status does not include locale when unauthenticated',
|
||||
function (t) {
|
||||
() => {
|
||||
return Client.create(config.publicUrl, server.uniqueEmail(), 'password', { lang: 'en-US' })
|
||||
.then(
|
||||
function (c) {
|
||||
|
@ -56,15 +65,15 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function (response) {
|
||||
t.ok(!response.locale, 'locale is not present')
|
||||
assert.ok(!response.locale, 'locale is not present')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'account status unauthenticated with no uid returns an error',
|
||||
function (t) {
|
||||
() => {
|
||||
return Client.create(config.publicUrl, server.uniqueEmail(), 'password', { lang: 'en-US' })
|
||||
.then(
|
||||
function (c) {
|
||||
|
@ -73,32 +82,32 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function () {
|
||||
t.fail('should get an error')
|
||||
assert(false, 'should get an error')
|
||||
},
|
||||
function (e) {
|
||||
t.equal(e.code, 400, 'correct error status code')
|
||||
t.equal(e.errno, 108, 'correct errno')
|
||||
assert.equal(e.code, 400, 'correct error status code')
|
||||
assert.equal(e.errno, 108, 'correct errno')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'account status with non-existing account',
|
||||
function (t) {
|
||||
() => {
|
||||
var api = new Client.Api(config.publicUrl)
|
||||
return api.accountStatus('0123456789ABCDEF0123456789ABCDEF')
|
||||
.then(
|
||||
function (response) {
|
||||
t.ok(!response.exists, 'account does not exist')
|
||||
assert.ok(!response.exists, 'account does not exist')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'account status by email with existing account',
|
||||
function (t) {
|
||||
() => {
|
||||
var email = server.uniqueEmail()
|
||||
return Client.create(config.publicUrl, email, 'password')
|
||||
.then(
|
||||
|
@ -108,15 +117,15 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function (response) {
|
||||
t.ok(response.exists, 'account exists')
|
||||
assert.ok(response.exists, 'account exists')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'account status by email with non-existing account',
|
||||
function (t) {
|
||||
() => {
|
||||
var email = server.uniqueEmail()
|
||||
return Client.create(config.publicUrl, email, 'password')
|
||||
.then(
|
||||
|
@ -127,15 +136,15 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function (response) {
|
||||
t.ok(!response.exists, 'account does not exist')
|
||||
assert.ok(!response.exists, 'account does not exist')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'account status by email with an invalid email',
|
||||
function (t) {
|
||||
() => {
|
||||
var email = server.uniqueEmail()
|
||||
return Client.create(config.publicUrl, email, 'password')
|
||||
.then(
|
||||
|
@ -146,20 +155,20 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function () {
|
||||
t.fail('should not have successful request')
|
||||
assert(false, 'should not have successful request')
|
||||
},
|
||||
function (err) {
|
||||
t.equal(err.code, 400)
|
||||
t.equal(err.errno, 107)
|
||||
t.equal(err.message, 'Invalid parameter in request body')
|
||||
assert.equal(err.code, 400)
|
||||
assert.equal(err.errno, 107)
|
||||
assert.equal(err.message, 'Invalid parameter in request body')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'account status by email works with unicode email address',
|
||||
function (t) {
|
||||
() => {
|
||||
var email = server.uniqueUnicodeEmail()
|
||||
return Client.create(config.publicUrl, email, 'password')
|
||||
.then(
|
||||
|
@ -169,17 +178,13 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function (response) {
|
||||
t.ok(response.exists, 'account exists')
|
||||
assert.ok(response.exists, 'account exists')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'teardown',
|
||||
function (t) {
|
||||
server.stop()
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
after(() => {
|
||||
return TestServer.stop(server)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -2,18 +2,27 @@
|
|||
* 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/. */
|
||||
|
||||
var test = require('../ptaptest')
|
||||
'use strict'
|
||||
|
||||
const assert = require('insist')
|
||||
var TestServer = require('../test_server')
|
||||
const Client = require('../client')()
|
||||
|
||||
var config = require('../../config').getProperties()
|
||||
|
||||
TestServer.start(config)
|
||||
.then(function main(server) {
|
||||
describe('remote account unlock', function() {
|
||||
this.timeout(15000)
|
||||
let server
|
||||
before(() => {
|
||||
return TestServer.start(config)
|
||||
.then(s => {
|
||||
server = s
|
||||
})
|
||||
})
|
||||
|
||||
test(
|
||||
it(
|
||||
'/account/lock is no longer supported',
|
||||
function (t) {
|
||||
() => {
|
||||
return Client.create(config.publicUrl, server.uniqueEmail(), 'password')
|
||||
.then(
|
||||
function (c) {
|
||||
|
@ -22,18 +31,18 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function () {
|
||||
t.fail('should get an error')
|
||||
assert(false, 'should get an error')
|
||||
},
|
||||
function (e) {
|
||||
t.equal(e.code, 410, 'correct error status code')
|
||||
assert.equal(e.code, 410, 'correct error status code')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'/account/unlock/resend_code is no longer supported',
|
||||
function (t) {
|
||||
() => {
|
||||
return Client.create(config.publicUrl, server.uniqueEmail(), 'password')
|
||||
.then(
|
||||
function (c) {
|
||||
|
@ -42,18 +51,18 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function () {
|
||||
t.fail('should get an error')
|
||||
assert(false, 'should get an error')
|
||||
},
|
||||
function (e) {
|
||||
t.equal(e.code, 410, 'correct error status code')
|
||||
assert.equal(e.code, 410, 'correct error status code')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'/account/unlock/verify_code is no longer supported',
|
||||
function (t) {
|
||||
() => {
|
||||
return Client.create(config.publicUrl, server.uniqueEmail(), 'password')
|
||||
.then(
|
||||
function (c) {
|
||||
|
@ -62,20 +71,16 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function () {
|
||||
t.fail('should get an error')
|
||||
assert(false, 'should get an error')
|
||||
},
|
||||
function (e) {
|
||||
t.equal(e.code, 410, 'correct error status code')
|
||||
assert.equal(e.code, 410, 'correct error status code')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'teardown',
|
||||
function (t) {
|
||||
server.stop()
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
after(() => {
|
||||
return TestServer.stop(server)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -2,43 +2,48 @@
|
|||
* 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/. */
|
||||
|
||||
process.env.PUBLIC_URL = 'http://127.0.0.1:9000/auth'
|
||||
'use strict'
|
||||
|
||||
var test = require('../ptaptest')
|
||||
|
||||
const assert = require('insist')
|
||||
var TestServer = require('../test_server')
|
||||
const Client = require('../client')()
|
||||
var P = require('../../lib/promise')
|
||||
var request = require('request')
|
||||
var request = P.promisify(require('request'))
|
||||
|
||||
var config = require('../../config').getProperties()
|
||||
|
||||
TestServer.start(config)
|
||||
.then(function main(server) {
|
||||
describe('remote base path', function() {
|
||||
this.timeout(15000)
|
||||
let server, config
|
||||
before(() => {
|
||||
process.env.PUBLIC_URL = 'http://127.0.0.1:9000/auth'
|
||||
config = require('../../config').getProperties()
|
||||
config.publicUrl = process.env.PUBLIC_URL
|
||||
return TestServer.start(config)
|
||||
.then(s => {
|
||||
server = s
|
||||
})
|
||||
})
|
||||
|
||||
function testVersionRoute(path) {
|
||||
return function (t) {
|
||||
var d = P.defer()
|
||||
request(config.publicUrl + path,
|
||||
function (err, res, body) {
|
||||
if (err) { d.reject(err) }
|
||||
t.equal(res.statusCode, 200)
|
||||
return () => {
|
||||
return request(config.publicUrl + path)
|
||||
.spread((res, body) => {
|
||||
assert.equal(res.statusCode, 200)
|
||||
var json = JSON.parse(body)
|
||||
t.deepEqual(Object.keys(json), ['version', 'commit', 'source'])
|
||||
t.equal(json.version, require('../../package.json').version, 'package version')
|
||||
t.ok(json.source && json.source !== 'unknown', 'source repository')
|
||||
assert.deepEqual(Object.keys(json), ['version', 'commit', 'source'])
|
||||
assert.equal(json.version, require('../../package.json').version, 'package version')
|
||||
assert.ok(json.source && json.source !== 'unknown', 'source repository')
|
||||
|
||||
// check that the git hash just looks like a hash
|
||||
t.ok(json.commit.match(/^[0-9a-f]{40}$/), 'The git hash actually looks like one')
|
||||
d.resolve(json)
|
||||
}
|
||||
)
|
||||
return d.promise
|
||||
assert.ok(json.commit.match(/^[0-9a-f]{40}$/), 'The git hash actually looks like one')
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
test(
|
||||
it(
|
||||
'alternate base path',
|
||||
function (t) {
|
||||
() => {
|
||||
var email = Math.random() + '@example.com'
|
||||
var password = 'ok'
|
||||
// if this doesn't crash, we're all good
|
||||
|
@ -46,38 +51,30 @@ TestServer.start(config)
|
|||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'.well-known did not move',
|
||||
function (t) {
|
||||
var d = P.defer()
|
||||
request('http://127.0.0.1:9000/.well-known/browserid',
|
||||
function (err, res, body) {
|
||||
if (err) { d.reject(err) }
|
||||
t.equal(res.statusCode, 200)
|
||||
() => {
|
||||
return request('http://127.0.0.1:9000/.well-known/browserid')
|
||||
.spread((res, body) => {
|
||||
assert.equal(res.statusCode, 200)
|
||||
var json = JSON.parse(body)
|
||||
t.equal(json.authentication, '/.well-known/browserid/sign_in.html')
|
||||
d.resolve(json)
|
||||
}
|
||||
)
|
||||
return d.promise
|
||||
assert.equal(json.authentication, '/.well-known/browserid/sign_in.html')
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'"/" returns valid version information',
|
||||
testVersionRoute('/')
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'"/__version__" returns valid version information',
|
||||
testVersionRoute('/__version__')
|
||||
)
|
||||
|
||||
test(
|
||||
'teardown',
|
||||
function (t) {
|
||||
server.stop()
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
after(() => {
|
||||
delete process.env.PUBLIC_URL
|
||||
return TestServer.stop(server)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -2,7 +2,9 @@
|
|||
* 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/. */
|
||||
|
||||
var test = require('../ptaptest')
|
||||
'use strict'
|
||||
|
||||
const assert = require('insist')
|
||||
var TestServer = require('../test_server')
|
||||
const Client = require('../client')()
|
||||
var jwtool = require('fxa-jwtool')
|
||||
|
@ -16,12 +18,19 @@ var publicKey = {
|
|||
'e': '65537'
|
||||
}
|
||||
|
||||
TestServer.start(config)
|
||||
.then(function main(server) {
|
||||
describe('remote certificate sign', function() {
|
||||
this.timeout(15000)
|
||||
let server
|
||||
before(() => {
|
||||
return TestServer.start(config)
|
||||
.then(s => {
|
||||
server = s
|
||||
})
|
||||
})
|
||||
|
||||
test(
|
||||
it(
|
||||
'certificate sign',
|
||||
function (t) {
|
||||
() => {
|
||||
var email = server.uniqueEmail()
|
||||
var password = 'allyourbasearebelongtous'
|
||||
var client = null
|
||||
|
@ -35,22 +44,22 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function (cert) {
|
||||
t.equal(typeof(cert), 'string', 'cert exists')
|
||||
assert.equal(typeof(cert), 'string', 'cert exists')
|
||||
var payload = jwtool.verify(cert, pubSigKey.pem)
|
||||
t.equal(payload.iss, config.domain, 'issuer is correct')
|
||||
t.equal(payload.principal.email.split('@')[0], client.uid, 'cert has correct uid')
|
||||
t.ok(payload['fxa-generation'] > 0, 'cert has non-zero generation number')
|
||||
t.ok(new Date() - new Date(payload['fxa-lastAuthAt'] * 1000) < 1000 * 60 * 60, 'lastAuthAt is plausible')
|
||||
t.equal(payload['fxa-verifiedEmail'], email, 'verifiedEmail is correct')
|
||||
t.equal(payload['fxa-tokenVerified'], true, 'tokenVerified is correct')
|
||||
assert.equal(payload.iss, config.domain, 'issuer is correct')
|
||||
assert.equal(payload.principal.email.split('@')[0], client.uid, 'cert has correct uid')
|
||||
assert.ok(payload['fxa-generation'] > 0, 'cert has non-zero generation number')
|
||||
assert.ok(new Date() - new Date(payload['fxa-lastAuthAt'] * 1000) < 1000 * 60 * 60, 'lastAuthAt is plausible')
|
||||
assert.equal(payload['fxa-verifiedEmail'], email, 'verifiedEmail is correct')
|
||||
assert.equal(payload['fxa-tokenVerified'], true, 'tokenVerified is correct')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'certificate sign requires a verified account',
|
||||
function (t) {
|
||||
() => {
|
||||
var email = server.uniqueEmail()
|
||||
var password = 'allyourbasearebelongtous'
|
||||
var client = null
|
||||
|
@ -64,18 +73,18 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function (cert) {
|
||||
t.fail('should not be able to sign with unverified account')
|
||||
assert(false, 'should not be able to sign with unverified account')
|
||||
},
|
||||
function (err) {
|
||||
t.equal(err.errno, 104, 'should get an unverifiedAccount error')
|
||||
assert.equal(err.errno, 104, 'should get an unverifiedAccount error')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'/certificate/sign inputs',
|
||||
function (t) {
|
||||
() => {
|
||||
var email = server.uniqueEmail()
|
||||
var password = '123456'
|
||||
var client = null
|
||||
|
@ -88,97 +97,97 @@ TestServer.start(config)
|
|||
}
|
||||
)
|
||||
.then(
|
||||
t.fail,
|
||||
() => assert(false),
|
||||
function (err) {
|
||||
t.equal(err.code, 400, 'string as publicKey')
|
||||
assert.equal(err.code, 400, 'string as publicKey')
|
||||
// empty object as publicKey
|
||||
return client.sign({}, 1000)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
t.fail,
|
||||
() => assert(false),
|
||||
function (err) {
|
||||
t.equal(err.code, 400, 'empty object as publicKey')
|
||||
assert.equal(err.code, 400, 'empty object as publicKey')
|
||||
// invalid publicKey argument
|
||||
return client.sign({ algorithm: 'RS', n: 'x', e: 'y', invalid: true }, 1000)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
t.fail,
|
||||
() => assert(false),
|
||||
function (err) {
|
||||
t.equal(err.code, 400, 'invalid publicKey argument')
|
||||
assert.equal(err.code, 400, 'invalid publicKey argument')
|
||||
// undefined duration
|
||||
return client.sign({ algorithm: 'RS', n: 'x', e: 'y' }, undefined)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
t.fail,
|
||||
() => assert(false),
|
||||
function (err) {
|
||||
t.equal(err.code, 400, 'undefined duration')
|
||||
assert.equal(err.code, 400, 'undefined duration')
|
||||
// missing publicKey arguments (e)
|
||||
return client.sign({ algorithm: 'RS', n: 'x' }, 1000)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
t.fail,
|
||||
() => assert(false),
|
||||
function (err) {
|
||||
t.equal(err.code, 400, 'missing publicKey arguments (e)')
|
||||
assert.equal(err.code, 400, 'missing publicKey arguments (e)')
|
||||
// missing publicKey arguments (n)
|
||||
return client.sign({ algorithm: 'RS', e: 'x' }, 1000)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
t.fail,
|
||||
() => assert(false),
|
||||
function (err) {
|
||||
t.equal(err.code, 400, 'missing publicKey arguments (n)')
|
||||
assert.equal(err.code, 400, 'missing publicKey arguments (n)')
|
||||
// missing publicKey arguments (y)
|
||||
return client.sign({ algorithm: 'DS', p: 'p', q: 'q', g: 'g' }, 1000)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
t.fail,
|
||||
() => assert(false),
|
||||
function (err) {
|
||||
t.equal(err.code, 400, 'missing publicKey arguments (y)')
|
||||
assert.equal(err.code, 400, 'missing publicKey arguments (y)')
|
||||
// missing publicKey arguments (p)
|
||||
return client.sign({ algorithm: 'DS', y: 'y', q: 'q', g: 'g' }, 1000)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
t.fail,
|
||||
() => assert(false),
|
||||
function (err) {
|
||||
t.equal(err.code, 400, 'missing publicKey arguments (p)')
|
||||
assert.equal(err.code, 400, 'missing publicKey arguments (p)')
|
||||
// missing publicKey arguments (q)
|
||||
return client.sign({ algorithm: 'DS', y: 'y', p: 'p', g: 'g' }, 1000)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
t.fail,
|
||||
() => assert(false),
|
||||
function (err) {
|
||||
t.equal(err.code, 400, 'missing publicKey arguments (q)')
|
||||
assert.equal(err.code, 400, 'missing publicKey arguments (q)')
|
||||
// missing publicKey arguments (g)
|
||||
return client.sign({ algorithm: 'DS', y: 'y', p: 'p', q: 'q' }, 1000)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
t.fail,
|
||||
() => assert(false),
|
||||
function (err) {
|
||||
t.equal(err.code, 400, 'missing publicKey arguments (g)')
|
||||
assert.equal(err.code, 400, 'missing publicKey arguments (g)')
|
||||
// invalid algorithm
|
||||
return client.sign({ algorithm: 'NSA' }, 1000)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
t.fail,
|
||||
() => assert(false),
|
||||
function (err) {
|
||||
t.equal(err.code, 400, 'invalid algorithm')
|
||||
assert.equal(err.code, 400, 'invalid algorithm')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'no payload',
|
||||
function (t) {
|
||||
() => {
|
||||
var email = server.uniqueEmail()
|
||||
var password = 'allyourbasearebelongtous'
|
||||
var duration = 1000 * 60 * 60 * 24 // 24 hours
|
||||
|
@ -210,19 +219,15 @@ TestServer.start(config)
|
|||
}
|
||||
)
|
||||
.then(
|
||||
t.fail,
|
||||
() => assert(false),
|
||||
function (err) {
|
||||
t.equal(err.errno, 109, 'Missing payload authentication')
|
||||
assert.equal(err.errno, 109, 'Missing payload authentication')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'teardown',
|
||||
function (t) {
|
||||
server.stop()
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
after(() => {
|
||||
return TestServer.stop(server)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -2,21 +2,30 @@
|
|||
* 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/. */
|
||||
|
||||
var test = require('tap').test
|
||||
'use strict'
|
||||
|
||||
const assert = require('insist')
|
||||
var TestServer = require('../test_server')
|
||||
const Client = require('../client')()
|
||||
var P = require('../../lib/promise')
|
||||
|
||||
var config = require('../../config').getProperties()
|
||||
|
||||
process.env.VERIFIER_VERSION = '1'
|
||||
|
||||
TestServer.start(config)
|
||||
.then(function main(server) {
|
||||
describe('remote concurrect', function() {
|
||||
this.timeout(15000)
|
||||
let server
|
||||
before(() => {
|
||||
process.env.VERIFIER_VERSION = '1'
|
||||
return TestServer.start(config)
|
||||
.then(s => {
|
||||
server = s
|
||||
})
|
||||
})
|
||||
|
||||
test(
|
||||
it(
|
||||
'concurrent create requests',
|
||||
function (t) {
|
||||
() => {
|
||||
var email = server.uniqueEmail()
|
||||
var password = 'abcdef'
|
||||
// Two shall enter, only one shall survive!
|
||||
|
@ -26,9 +35,9 @@ TestServer.start(config)
|
|||
[r1, r2]
|
||||
)
|
||||
.then(
|
||||
t.fail.bind(t, 'created both accounts'),
|
||||
() => assert(false, 'created both accounts'),
|
||||
function (err) {
|
||||
t.equal(err.errno, 101, 'account exists')
|
||||
assert.equal(err.errno, 101, 'account exists')
|
||||
// Note that P.all fails fast when one of the requests fails,
|
||||
// but we have to wait for *both* to complete before tearing
|
||||
// down the test infrastructure. Bleh.
|
||||
|
@ -46,11 +55,8 @@ TestServer.start(config)
|
|||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'teardown',
|
||||
function (t) {
|
||||
server.stop()
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
after(() => {
|
||||
delete process.env.VERIFIER_VERSION
|
||||
return TestServer.stop(server)
|
||||
})
|
||||
})
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -2,7 +2,9 @@
|
|||
* 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/. */
|
||||
|
||||
var test = require('../ptaptest')
|
||||
'use strict'
|
||||
|
||||
const assert = require('insist')
|
||||
var TestServer = require('../test_server')
|
||||
const Client = require('../client')()
|
||||
var config = require('../../config').getProperties()
|
||||
|
@ -10,16 +12,24 @@ var crypto = require('crypto')
|
|||
var base64url = require('base64url')
|
||||
var P = require('../../lib/promise')
|
||||
|
||||
// HACK: Force-enable devices.lastAccessTime in the spawned server process
|
||||
process.env.LASTACCESSTIME_UPDATES_ENABLED = 'true'
|
||||
process.env.LASTACCESSTIME_UPDATES_EMAIL_ADDRESSES = '.*'
|
||||
process.env.LASTACCESSTIME_UPDATES_SAMPLE_RATE = '1'
|
||||
describe('remote device', function() {
|
||||
this.timeout(15000)
|
||||
let server
|
||||
before(() => {
|
||||
// HACK: Force-enable devices.lastAccessTime in the spawned server process
|
||||
process.env.LASTACCESSTIME_UPDATES_ENABLED = 'true'
|
||||
process.env.LASTACCESSTIME_UPDATES_EMAIL_ADDRESSES = '.*'
|
||||
process.env.LASTACCESSTIME_UPDATES_SAMPLE_RATE = '1'
|
||||
|
||||
TestServer.start(config)
|
||||
.then(function main(server) {
|
||||
test(
|
||||
return TestServer.start(config)
|
||||
.then(s => {
|
||||
server = s
|
||||
})
|
||||
})
|
||||
|
||||
it(
|
||||
'device registration after account creation',
|
||||
function (t) {
|
||||
() => {
|
||||
var email = server.uniqueEmail()
|
||||
var password = 'test password'
|
||||
return Client.create(config.publicUrl, email, password)
|
||||
|
@ -35,19 +45,19 @@ TestServer.start(config)
|
|||
return client.devices()
|
||||
.then(
|
||||
function (devices) {
|
||||
t.equal(devices.length, 0, 'devices returned no items')
|
||||
assert.equal(devices.length, 0, 'devices returned no items')
|
||||
return client.updateDevice(deviceInfo)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (device) {
|
||||
t.ok(device.id, 'device.id was set')
|
||||
t.ok(device.createdAt > 0, 'device.createdAt was set')
|
||||
t.equal(device.name, deviceInfo.name, 'device.name is correct')
|
||||
t.equal(device.type, deviceInfo.type, 'device.type is correct')
|
||||
t.equal(device.pushCallback, deviceInfo.pushCallback, 'device.pushCallback is correct')
|
||||
t.equal(device.pushPublicKey, deviceInfo.pushPublicKey, 'device.pushPublicKey is correct')
|
||||
t.equal(device.pushAuthKey, deviceInfo.pushAuthKey, 'device.pushAuthKey is correct')
|
||||
assert.ok(device.id, 'device.id was set')
|
||||
assert.ok(device.createdAt > 0, 'device.createdAt was set')
|
||||
assert.equal(device.name, deviceInfo.name, 'device.name is correct')
|
||||
assert.equal(device.type, deviceInfo.type, 'device.type is correct')
|
||||
assert.equal(device.pushCallback, deviceInfo.pushCallback, 'device.pushCallback is correct')
|
||||
assert.equal(device.pushPublicKey, deviceInfo.pushPublicKey, 'device.pushPublicKey is correct')
|
||||
assert.equal(device.pushAuthKey, deviceInfo.pushAuthKey, 'device.pushAuthKey is correct')
|
||||
}
|
||||
)
|
||||
.then(
|
||||
|
@ -57,12 +67,12 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function (devices) {
|
||||
t.equal(devices.length, 1, 'devices returned one item')
|
||||
t.equal(devices[0].name, deviceInfo.name, 'devices returned correct name')
|
||||
t.equal(devices[0].type, deviceInfo.type, 'devices returned correct type')
|
||||
t.equal(devices[0].pushCallback, '', 'devices returned empty pushCallback')
|
||||
t.equal(devices[0].pushPublicKey, '', 'devices returned correct pushPublicKey')
|
||||
t.equal(devices[0].pushAuthKey, '', 'devices returned correct pushAuthKey')
|
||||
assert.equal(devices.length, 1, 'devices returned one item')
|
||||
assert.equal(devices[0].name, deviceInfo.name, 'devices returned correct name')
|
||||
assert.equal(devices[0].type, deviceInfo.type, 'devices returned correct type')
|
||||
assert.equal(devices[0].pushCallback, '', 'devices returned empty pushCallback')
|
||||
assert.equal(devices[0].pushPublicKey, '', 'devices returned correct pushPublicKey')
|
||||
assert.equal(devices[0].pushAuthKey, '', 'devices returned correct pushAuthKey')
|
||||
return client.destroyDevice(devices[0].id)
|
||||
}
|
||||
)
|
||||
|
@ -71,9 +81,9 @@ TestServer.start(config)
|
|||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'device registration without optional parameters',
|
||||
function (t) {
|
||||
() => {
|
||||
var email = server.uniqueEmail()
|
||||
var password = 'test password'
|
||||
return Client.create(config.publicUrl, email, password)
|
||||
|
@ -86,19 +96,19 @@ TestServer.start(config)
|
|||
return client.devices()
|
||||
.then(
|
||||
function (devices) {
|
||||
t.equal(devices.length, 0, 'devices returned no items')
|
||||
assert.equal(devices.length, 0, 'devices returned no items')
|
||||
return client.updateDevice(deviceInfo)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (device) {
|
||||
t.ok(device.id, 'device.id was set')
|
||||
t.ok(device.createdAt > 0, 'device.createdAt was set')
|
||||
t.equal(device.name, deviceInfo.name, 'device.name is correct')
|
||||
t.equal(device.type, deviceInfo.type, 'device.type is correct')
|
||||
t.equal(device.pushCallback, undefined, 'device.pushCallback is undefined')
|
||||
t.equal(device.pushPublicKey, undefined, 'device.pushPublicKey is undefined')
|
||||
t.equal(device.pushAuthKey, undefined, 'device.pushAuthKey is undefined')
|
||||
assert.ok(device.id, 'device.id was set')
|
||||
assert.ok(device.createdAt > 0, 'device.createdAt was set')
|
||||
assert.equal(device.name, deviceInfo.name, 'device.name is correct')
|
||||
assert.equal(device.type, deviceInfo.type, 'device.type is correct')
|
||||
assert.equal(device.pushCallback, undefined, 'device.pushCallback is undefined')
|
||||
assert.equal(device.pushPublicKey, undefined, 'device.pushPublicKey is undefined')
|
||||
assert.equal(device.pushAuthKey, undefined, 'device.pushAuthKey is undefined')
|
||||
}
|
||||
)
|
||||
.then(
|
||||
|
@ -108,12 +118,12 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function (devices) {
|
||||
t.equal(devices.length, 1, 'devices returned one item')
|
||||
t.equal(devices[0].name, deviceInfo.name, 'devices returned correct name')
|
||||
t.equal(devices[0].type, deviceInfo.type, 'devices returned correct type')
|
||||
t.equal(devices[0].pushCallback, null, 'devices returned undefined pushCallback')
|
||||
t.equal(devices[0].pushPublicKey, null, 'devices returned undefined pushPublicKey')
|
||||
t.equal(devices[0].pushAuthKey, null, 'devices returned undefined pushAuthKey')
|
||||
assert.equal(devices.length, 1, 'devices returned one item')
|
||||
assert.equal(devices[0].name, deviceInfo.name, 'devices returned correct name')
|
||||
assert.equal(devices[0].type, deviceInfo.type, 'devices returned correct type')
|
||||
assert.equal(devices[0].pushCallback, null, 'devices returned undefined pushCallback')
|
||||
assert.equal(devices[0].pushPublicKey, null, 'devices returned undefined pushPublicKey')
|
||||
assert.equal(devices[0].pushAuthKey, null, 'devices returned undefined pushAuthKey')
|
||||
return client.destroyDevice(devices[0].id)
|
||||
}
|
||||
)
|
||||
|
@ -122,9 +132,9 @@ TestServer.start(config)
|
|||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'device registration without required name parameter',
|
||||
function (t) {
|
||||
() => {
|
||||
var email = server.uniqueEmail()
|
||||
var password = 'test password'
|
||||
return Client.create(config.publicUrl, email, password)
|
||||
|
@ -133,13 +143,13 @@ TestServer.start(config)
|
|||
return client.updateDevice({ type: 'mobile' })
|
||||
.then(
|
||||
function (r) {
|
||||
t.fail('request should have failed')
|
||||
assert(false, 'request should have failed')
|
||||
}
|
||||
)
|
||||
.catch(
|
||||
function (err) {
|
||||
t.equal(err.code, 400, 'err.code was 400')
|
||||
t.equal(err.errno, 108, 'err.errno was 108')
|
||||
assert.equal(err.code, 400, 'err.code was 400')
|
||||
assert.equal(err.errno, 108, 'err.errno was 108')
|
||||
}
|
||||
)
|
||||
}
|
||||
|
@ -147,9 +157,9 @@ TestServer.start(config)
|
|||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'device registration without required type parameter',
|
||||
function (t) {
|
||||
() => {
|
||||
var email = server.uniqueEmail()
|
||||
var password = 'test password'
|
||||
return Client.create(config.publicUrl, email, password)
|
||||
|
@ -158,13 +168,13 @@ TestServer.start(config)
|
|||
return client.updateDevice({ name: 'test device' })
|
||||
.then(
|
||||
function () {
|
||||
t.fail('request should have failed')
|
||||
assert(false, 'request should have failed')
|
||||
}
|
||||
)
|
||||
.catch(
|
||||
function (err) {
|
||||
t.equal(err.code, 400, 'err.code was 400')
|
||||
t.equal(err.errno, 108, 'err.errno was 108')
|
||||
assert.equal(err.code, 400, 'err.code was 400')
|
||||
assert.equal(err.errno, 108, 'err.errno was 108')
|
||||
}
|
||||
)
|
||||
}
|
||||
|
@ -172,9 +182,9 @@ TestServer.start(config)
|
|||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'device registration with unsupported characters in the name',
|
||||
function (t) {
|
||||
() => {
|
||||
var email = server.uniqueEmail()
|
||||
var password = 'test password'
|
||||
return Client.create(config.publicUrl, email, password)
|
||||
|
@ -188,14 +198,14 @@ TestServer.start(config)
|
|||
return client.updateDevice(deviceInfo)
|
||||
.then(
|
||||
function () {
|
||||
t.fail('request should have failed')
|
||||
assert(false, 'request should have failed')
|
||||
}
|
||||
)
|
||||
.catch(
|
||||
function (err) {
|
||||
t.equal(err.code, 400, 'err.code was 400')
|
||||
t.equal(err.errno, 107, 'err.errno was 107')
|
||||
t.equal(err.validation.keys[0], 'name', 'name was rejected')
|
||||
assert.equal(err.code, 400, 'err.code was 400')
|
||||
assert.equal(err.errno, 107, 'err.errno was 107')
|
||||
assert.equal(err.validation.keys[0], 'name', 'name was rejected')
|
||||
}
|
||||
)
|
||||
}
|
||||
|
@ -203,9 +213,9 @@ TestServer.start(config)
|
|||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'device registration from a different session',
|
||||
function (t) {
|
||||
() => {
|
||||
var email = server.uniqueEmail()
|
||||
var password = 'test password'
|
||||
var deviceInfo = [
|
||||
|
@ -234,10 +244,10 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function (devices) {
|
||||
t.equal(devices.length, 1, 'devices returned one item')
|
||||
t.equal(devices[0].isCurrentDevice, false, 'devices returned false isCurrentDevice')
|
||||
t.equal(devices[0].name, deviceInfo[0].name, 'devices returned correct name')
|
||||
t.equal(devices[0].type, deviceInfo[0].type, 'devices returned correct type')
|
||||
assert.equal(devices.length, 1, 'devices returned one item')
|
||||
assert.equal(devices[0].isCurrentDevice, false, 'devices returned false isCurrentDevice')
|
||||
assert.equal(devices[0].name, deviceInfo[0].name, 'devices returned correct name')
|
||||
assert.equal(devices[0].type, deviceInfo[0].type, 'devices returned correct type')
|
||||
return client.updateDevice(deviceInfo[1])
|
||||
}
|
||||
)
|
||||
|
@ -248,7 +258,7 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function (devices) {
|
||||
t.equal(devices.length, 2, 'devices returned two items')
|
||||
assert.equal(devices.length, 2, 'devices returned two items')
|
||||
if (devices[0].name === deviceInfo[1].name) {
|
||||
// database results are unordered, swap them if necessary
|
||||
var swap = {}
|
||||
|
@ -258,12 +268,12 @@ TestServer.start(config)
|
|||
devices[1][key] = swap[key]
|
||||
})
|
||||
}
|
||||
t.equal(devices[0].isCurrentDevice, false, 'devices returned false isCurrentDevice for first item')
|
||||
t.equal(devices[0].name, deviceInfo[0].name, 'devices returned correct name for first item')
|
||||
t.equal(devices[0].type, deviceInfo[0].type, 'devices returned correct type for first item')
|
||||
t.equal(devices[1].isCurrentDevice, true, 'devices returned true isCurrentDevice for second item')
|
||||
t.equal(devices[1].name, deviceInfo[1].name, 'devices returned correct name for second item')
|
||||
t.equal(devices[1].type, deviceInfo[1].type, 'devices returned correct type for second item')
|
||||
assert.equal(devices[0].isCurrentDevice, false, 'devices returned false isCurrentDevice for first item')
|
||||
assert.equal(devices[0].name, deviceInfo[0].name, 'devices returned correct name for first item')
|
||||
assert.equal(devices[0].type, deviceInfo[0].type, 'devices returned correct type for first item')
|
||||
assert.equal(devices[1].isCurrentDevice, true, 'devices returned true isCurrentDevice for second item')
|
||||
assert.equal(devices[1].name, deviceInfo[1].name, 'devices returned correct name for second item')
|
||||
assert.equal(devices[1].type, deviceInfo[1].type, 'devices returned correct type for second item')
|
||||
return P.all([
|
||||
client.destroyDevice(devices[0].id),
|
||||
client.destroyDevice(devices[1].id)
|
||||
|
@ -275,9 +285,9 @@ TestServer.start(config)
|
|||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'update device with callbackUrl but without keys resets the keys',
|
||||
function (t) {
|
||||
() => {
|
||||
var email = server.uniqueEmail()
|
||||
var password = 'test password'
|
||||
var deviceInfo = {
|
||||
|
@ -298,9 +308,9 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function (devices) {
|
||||
t.equal(devices[0].pushCallback, deviceInfo.pushCallback, 'devices returned correct pushCallback')
|
||||
t.equal(devices[0].pushPublicKey, deviceInfo.pushPublicKey, 'devices returned correct pushPublicKey')
|
||||
t.equal(devices[0].pushAuthKey, deviceInfo.pushAuthKey, 'devices returned correct pushAuthKey')
|
||||
assert.equal(devices[0].pushCallback, deviceInfo.pushCallback, 'devices returned correct pushCallback')
|
||||
assert.equal(devices[0].pushPublicKey, deviceInfo.pushPublicKey, 'devices returned correct pushPublicKey')
|
||||
assert.equal(devices[0].pushAuthKey, deviceInfo.pushAuthKey, 'devices returned correct pushAuthKey')
|
||||
return client.updateDevice({
|
||||
id: client.device.id,
|
||||
pushCallback: 'https://bar/foo'
|
||||
|
@ -314,9 +324,9 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function (devices) {
|
||||
t.equal(devices[0].pushCallback, 'https://bar/foo', 'devices returned correct pushCallback')
|
||||
t.equal(devices[0].pushPublicKey, '', 'devices returned newly empty pushPublicKey')
|
||||
t.equal(devices[0].pushAuthKey, '', 'devices returned newly empty pushAuthKey')
|
||||
assert.equal(devices[0].pushCallback, 'https://bar/foo', 'devices returned correct pushCallback')
|
||||
assert.equal(devices[0].pushPublicKey, '', 'devices returned newly empty pushPublicKey')
|
||||
assert.equal(devices[0].pushAuthKey, '', 'devices returned newly empty pushAuthKey')
|
||||
}
|
||||
)
|
||||
}
|
||||
|
@ -324,10 +334,10 @@ TestServer.start(config)
|
|||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
// Regression test for https://github.com/mozilla/fxa-auth-server/issues/1197
|
||||
'devices list, sessionToken.lastAccessTime === 0 (regression test for #1197)',
|
||||
function (t) {
|
||||
() => {
|
||||
var email = server.uniqueEmail()
|
||||
var password = 'test password'
|
||||
var deviceInfo = {
|
||||
|
@ -347,12 +357,12 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function (devices) {
|
||||
t.equal(devices.length, 1, 'devices returned one item')
|
||||
t.strictEqual(devices[0].lastAccessTime, 0, 'devices returned correct lastAccessTime')
|
||||
t.strictEqual(devices[0].lastAccessTimeFormatted, '',
|
||||
assert.equal(devices.length, 1, 'devices returned one item')
|
||||
assert.strictEqual(devices[0].lastAccessTime, 0, 'devices returned correct lastAccessTime')
|
||||
assert.strictEqual(devices[0].lastAccessTimeFormatted, '',
|
||||
'devices returned empty lastAccessTimeFormatted because lastAccesstime is 0')
|
||||
t.equal(devices[0].name, deviceInfo.name, 'devices returned correct name')
|
||||
t.equal(devices[0].type, deviceInfo.type, 'devices returned correct type')
|
||||
assert.equal(devices[0].name, deviceInfo.name, 'devices returned correct name')
|
||||
assert.equal(devices[0].type, deviceInfo.type, 'devices returned correct type')
|
||||
return client.destroyDevice(devices[0].id)
|
||||
}
|
||||
)
|
||||
|
@ -361,9 +371,9 @@ TestServer.start(config)
|
|||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'devices list, sessionToken.lastAccessTime === -1',
|
||||
function (t) {
|
||||
() => {
|
||||
var email = server.uniqueEmail()
|
||||
var password = 'test password'
|
||||
var deviceInfo = {
|
||||
|
@ -383,12 +393,12 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function (devices) {
|
||||
t.equal(devices.length, 1, 'devices returned one item')
|
||||
t.ok(devices[0].lastAccessTime > 0, 'devices returned correct lastAccessTime')
|
||||
t.strictEqual(devices[0].lastAccessTimeFormatted, 'a few seconds ago',
|
||||
assert.equal(devices.length, 1, 'devices returned one item')
|
||||
assert.ok(devices[0].lastAccessTime > 0, 'devices returned correct lastAccessTime')
|
||||
assert.strictEqual(devices[0].lastAccessTimeFormatted, 'a few seconds ago',
|
||||
'devices returned correct lastAccessTimeFormatted')
|
||||
t.equal(devices[0].name, deviceInfo.name, 'devices returned correct name')
|
||||
t.equal(devices[0].type, deviceInfo.type, 'devices returned correct type')
|
||||
assert.equal(devices[0].name, deviceInfo.name, 'devices returned correct name')
|
||||
assert.equal(devices[0].type, deviceInfo.type, 'devices returned correct type')
|
||||
return client.destroyDevice(devices[0].id)
|
||||
}
|
||||
)
|
||||
|
@ -397,9 +407,9 @@ TestServer.start(config)
|
|||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'devices list, sessionToken.lastAccessTime === THE FUTURE',
|
||||
function (t) {
|
||||
() => {
|
||||
var email = server.uniqueEmail()
|
||||
var password = 'test password'
|
||||
var deviceInfo = {
|
||||
|
@ -420,13 +430,13 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function (devices) {
|
||||
t.equal(devices.length, 1, 'devices returned one item')
|
||||
t.ok(devices[0].lastAccessTime > 0, 'devices returned correct lastAccessTime')
|
||||
t.ok(devices[0].lastAccessTime < theFuture, 'devices returned correct lastAccessTime')
|
||||
t.strictEqual(devices[0].lastAccessTimeFormatted, 'a few seconds ago',
|
||||
assert.equal(devices.length, 1, 'devices returned one item')
|
||||
assert.ok(devices[0].lastAccessTime > 0, 'devices returned correct lastAccessTime')
|
||||
assert.ok(devices[0].lastAccessTime < theFuture, 'devices returned correct lastAccessTime')
|
||||
assert.strictEqual(devices[0].lastAccessTimeFormatted, 'a few seconds ago',
|
||||
'devices returned correct lastAccessTimeFormatted')
|
||||
t.equal(devices[0].name, deviceInfo.name, 'devices returned correct name')
|
||||
t.equal(devices[0].type, deviceInfo.type, 'devices returned correct type')
|
||||
assert.equal(devices[0].name, deviceInfo.name, 'devices returned correct name')
|
||||
assert.equal(devices[0].type, deviceInfo.type, 'devices returned correct type')
|
||||
return client.destroyDevice(devices[0].id)
|
||||
}
|
||||
)
|
||||
|
@ -435,11 +445,11 @@ TestServer.start(config)
|
|||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'teardown',
|
||||
function (t) {
|
||||
server.stop()
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
after(() => {
|
||||
delete process.env.LASTACCESSTIME_UPDATES_ENABLED
|
||||
delete process.env.LASTACCESSTIME_UPDATES_EMAIL_ADDRESSES
|
||||
delete process.env.LASTACCESSTIME_UPDATES_SAMPLE_RATE
|
||||
|
||||
return TestServer.stop(server)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -2,19 +2,28 @@
|
|||
* 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/. */
|
||||
|
||||
var test = require('../ptaptest')
|
||||
'use strict'
|
||||
|
||||
const assert = require('insist')
|
||||
var TestServer = require('../test_server')
|
||||
const Client = require('../client')()
|
||||
var P = require('../../lib/promise')
|
||||
|
||||
var config = require('../../config').getProperties()
|
||||
|
||||
TestServer.start(config)
|
||||
.then(function main(server) {
|
||||
describe('remote email validity', function() {
|
||||
this.timeout(15000)
|
||||
let server
|
||||
before(() => {
|
||||
return TestServer.start(config)
|
||||
.then(s => {
|
||||
server = s
|
||||
})
|
||||
})
|
||||
|
||||
test(
|
||||
it(
|
||||
'/account/create with a variety of malformed email addresses',
|
||||
function (t) {
|
||||
() => {
|
||||
var pwd = '123456'
|
||||
|
||||
var emails = [
|
||||
|
@ -33,9 +42,9 @@ TestServer.start(config)
|
|||
emails.forEach(function(email, i) {
|
||||
emails[i] = Client.create(config.publicUrl, email, pwd)
|
||||
.then(
|
||||
t.fail,
|
||||
assert.fail,
|
||||
function (err) {
|
||||
t.equal(err.code, 400, 'http 400 : malformed email is rejected')
|
||||
assert.equal(err.code, 400, 'http 400 : malformed email is rejected')
|
||||
}
|
||||
)
|
||||
})
|
||||
|
@ -44,15 +53,15 @@ TestServer.start(config)
|
|||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'/account/create with a variety of unusual but valid email addresses',
|
||||
function (t) {
|
||||
() => {
|
||||
var pwd = '123456'
|
||||
|
||||
var emails = [
|
||||
'tim@tim-example.net',
|
||||
'a+b+c@example.com',
|
||||
'#!?-@t-e-s-t.c-o-m',
|
||||
'#!?-@t-e-s-assert.c-o-m',
|
||||
String.fromCharCode(1234) + '@example.com',
|
||||
'test@' + String.fromCharCode(5678) + '.com'
|
||||
]
|
||||
|
@ -61,11 +70,10 @@ TestServer.start(config)
|
|||
emails[i] = Client.create(config.publicUrl, email, pwd)
|
||||
.then(
|
||||
function(c) {
|
||||
t.pass('Email ' + email + ' is valid')
|
||||
return c.destroyAccount()
|
||||
},
|
||||
function (err) {
|
||||
t.fail('Email address ' + email + " should have been allowed, but it wasn't")
|
||||
assert(false, 'Email address ' + email + " should have been allowed, but it wasn't")
|
||||
}
|
||||
)
|
||||
})
|
||||
|
@ -74,11 +82,7 @@ TestServer.start(config)
|
|||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'teardown',
|
||||
function (t) {
|
||||
server.stop()
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
after(() => {
|
||||
return TestServer.stop(server)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -2,24 +2,34 @@
|
|||
* 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/. */
|
||||
|
||||
var test = require('tap').test
|
||||
'use strict'
|
||||
|
||||
const assert = require('insist')
|
||||
const Client = require('../client')()
|
||||
var TestServer = require('../test_server')
|
||||
var jwtool = require('fxa-jwtool')
|
||||
|
||||
var config = require('../../config').getProperties()
|
||||
process.env.SIGNIN_CONFIRMATION_ENABLED = false
|
||||
|
||||
var pubSigKey = jwtool.JWK.fromFile(config.publicKeyFile)
|
||||
|
||||
TestServer.start(config)
|
||||
.then(function main(server) {
|
||||
describe('remote flow', function() {
|
||||
this.timeout(15000)
|
||||
let server
|
||||
let email1
|
||||
before(() => {
|
||||
process.env.SIGNIN_CONFIRMATION_ENABLED = false
|
||||
return TestServer.start(config)
|
||||
.then(s => {
|
||||
server = s
|
||||
email1 = server.uniqueEmail()
|
||||
})
|
||||
})
|
||||
|
||||
var email1 = server.uniqueEmail()
|
||||
|
||||
test(
|
||||
it(
|
||||
'Create account flow',
|
||||
function (t) {
|
||||
() => {
|
||||
var email = email1
|
||||
var password = 'allyourbasearebelongtous'
|
||||
var client = null
|
||||
|
@ -38,10 +48,10 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function (keys) {
|
||||
t.ok(Buffer.isBuffer(keys.kA), 'kA exists')
|
||||
t.ok(Buffer.isBuffer(keys.wrapKb), 'wrapKb exists')
|
||||
t.ok(Buffer.isBuffer(keys.kB), 'kB exists')
|
||||
t.equal(client.kB.length, 32, 'kB exists, has the right length')
|
||||
assert.ok(Buffer.isBuffer(keys.kA), 'kA exists')
|
||||
assert.ok(Buffer.isBuffer(keys.wrapKb), 'wrapKb exists')
|
||||
assert.ok(Buffer.isBuffer(keys.kB), 'kB exists')
|
||||
assert.equal(client.kB.length, 32, 'kB exists, has the right length')
|
||||
}
|
||||
)
|
||||
.then(
|
||||
|
@ -51,17 +61,17 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function (cert) {
|
||||
t.equal(typeof(cert), 'string', 'cert exists')
|
||||
assert.equal(typeof(cert), 'string', 'cert exists')
|
||||
var payload = jwtool.verify(cert, pubSigKey.pem)
|
||||
t.equal(payload.principal.email.split('@')[0], client.uid, 'cert has correct uid')
|
||||
assert.equal(payload.principal.email.split('@')[0], client.uid, 'cert has correct uid')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'Login flow',
|
||||
function (t) {
|
||||
() => {
|
||||
var email = email1
|
||||
var password = 'allyourbasearebelongtous'
|
||||
var client = null
|
||||
|
@ -75,17 +85,17 @@ TestServer.start(config)
|
|||
.then(
|
||||
function (x) {
|
||||
client = x
|
||||
t.ok(client.authAt, 'authAt was set')
|
||||
t.ok(client.uid, 'got a uid')
|
||||
assert.ok(client.authAt, 'authAt was set')
|
||||
assert.ok(client.uid, 'got a uid')
|
||||
return client.keys()
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (keys) {
|
||||
t.ok(Buffer.isBuffer(keys.kA), 'kA exists')
|
||||
t.ok(Buffer.isBuffer(keys.wrapKb), 'wrapKb exists')
|
||||
t.ok(Buffer.isBuffer(keys.kB), 'kB exists')
|
||||
t.equal(client.kB.length, 32, 'kB exists, has the right length')
|
||||
assert.ok(Buffer.isBuffer(keys.kA), 'kA exists')
|
||||
assert.ok(Buffer.isBuffer(keys.wrapKb), 'wrapKb exists')
|
||||
assert.ok(Buffer.isBuffer(keys.kB), 'kB exists')
|
||||
assert.equal(client.kB.length, 32, 'kB exists, has the right length')
|
||||
}
|
||||
)
|
||||
.then(
|
||||
|
@ -95,17 +105,14 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function (cert) {
|
||||
t.equal(typeof(cert), 'string', 'cert exists')
|
||||
assert.equal(typeof(cert), 'string', 'cert exists')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'teardown',
|
||||
function (t) {
|
||||
server.stop()
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
after(() => {
|
||||
delete process.env.SIGNIN_CONFIRMATION_ENABLED
|
||||
return TestServer.stop(server)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -2,113 +2,119 @@
|
|||
* 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 P = require('bluebird')
|
||||
var test = require('../ptaptest')
|
||||
var TestServer = require('../test_server')
|
||||
var request = P.promisify(require('request'))
|
||||
|
||||
test(
|
||||
'Fails with no sha pins set',
|
||||
function (t) {
|
||||
process.env.HPKP_ENABLE = true
|
||||
process.env.HPKP_PIN_SHA256 = []
|
||||
var Server = require('../../lib/server')
|
||||
var config = require('../../config').getProperties()
|
||||
try{
|
||||
Server.create({},{},config,{})
|
||||
t.fail()
|
||||
t.end()
|
||||
} catch(e){
|
||||
t.equal(e.message, 'ValidationError: child "sha256s" fails because ["sha256s" must contain at least 1 items]', 'assert server error if no sha passed')
|
||||
t.end()
|
||||
describe('remote hpkp', function() {
|
||||
this.timeout(30000)
|
||||
|
||||
it(
|
||||
'Fails with no sha pins set',
|
||||
() => {
|
||||
process.env.HPKP_ENABLE = true
|
||||
process.env.HPKP_PIN_SHA256 = []
|
||||
var Server = require('../../lib/server')
|
||||
var config = require('../../config').getProperties()
|
||||
assert.throws(() => {
|
||||
Server.create({},{},config,{})
|
||||
}, 'ValidationError: child "sha256s" fails because ["sha256s" must contain at least 1 items]', 'assert server error if no sha passed')
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
test(
|
||||
'Does not send HPKP header when disabled',
|
||||
function (t) {
|
||||
process.env.HPKP_ENABLE = false
|
||||
it(
|
||||
'Does not send HPKP header when disabled',
|
||||
() => {
|
||||
process.env.HPKP_ENABLE = false
|
||||
|
||||
var config = require('../../config').getProperties()
|
||||
var server
|
||||
var config = require('../../config').getProperties()
|
||||
var server
|
||||
|
||||
TestServer.start(config)
|
||||
.then(function main(serverObj) {
|
||||
server = serverObj
|
||||
})
|
||||
.then(function () {
|
||||
return request({
|
||||
url: config.publicUrl + '/'
|
||||
return TestServer.start(config)
|
||||
.then(function main(serverObj) {
|
||||
server = serverObj
|
||||
})
|
||||
})
|
||||
.spread(function (res) {
|
||||
t.equal(res.headers['public-key-pins-report-only'], undefined, 'HPKP header not set')
|
||||
})
|
||||
.done(function () {
|
||||
server.stop()
|
||||
t.end()
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'Sends HPKP header',
|
||||
function (t) {
|
||||
process.env.HPKP_ENABLE = true
|
||||
process.env.HPKP_REPORT_ONLY = false
|
||||
process.env.HPKP_PIN_SHA256 = ['sha1=', 'sha2=']
|
||||
|
||||
var config = require('../../config').getProperties()
|
||||
var server
|
||||
|
||||
TestServer.start(config)
|
||||
.then(function main(serverObj) {
|
||||
server = serverObj
|
||||
})
|
||||
.then(function () {
|
||||
return request({
|
||||
url: config.publicUrl + '/'
|
||||
.then(function () {
|
||||
return request({
|
||||
url: config.publicUrl + '/'
|
||||
})
|
||||
})
|
||||
})
|
||||
.spread(function (res) {
|
||||
var headerValue = 'pin-sha256="sha1="; pin-sha256="sha2="; max-age=1; includeSubdomains'
|
||||
t.equal(res.headers['public-key-pins'], headerValue, 'HPKP header was set correctly')
|
||||
})
|
||||
.done(function () {
|
||||
server.stop()
|
||||
t.end()
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'Sends HPKP report header',
|
||||
function (t) {
|
||||
process.env.HPKP_ENABLE = true
|
||||
process.env.HPKP_REPORT_ONLY = true
|
||||
process.env.HPKP_PIN_SHA256 = ['sha1=', 'sha2=']
|
||||
process.env.HPKP_REPORT_URI = 'http://example.com'
|
||||
|
||||
var config = require('../../config').getProperties()
|
||||
var server
|
||||
|
||||
TestServer.start(config)
|
||||
.then(function main(serverObj) {
|
||||
server = serverObj
|
||||
})
|
||||
.then(function () {
|
||||
return request({
|
||||
url: config.publicUrl + '/'
|
||||
.spread(function (res) {
|
||||
assert.equal(res.headers['public-key-pins-report-only'], undefined, 'HPKP header not set')
|
||||
})
|
||||
})
|
||||
.spread(function (res) {
|
||||
var headerValue = 'pin-sha256="sha1="; pin-sha256="sha2="; max-age=1; includeSubdomains; report-uri="http://example.com"'
|
||||
t.equal(res.headers['public-key-pins-report-only'], headerValue, 'HPKP report header was set correctly')
|
||||
})
|
||||
.done(function () {
|
||||
server.stop()
|
||||
t.end()
|
||||
})
|
||||
}
|
||||
)
|
||||
.then(function () {
|
||||
return server.stop()
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
it(
|
||||
'Sends HPKP header',
|
||||
() => {
|
||||
process.env.HPKP_ENABLE = true
|
||||
process.env.HPKP_REPORT_ONLY = false
|
||||
process.env.HPKP_PIN_SHA256 = ['sha1=', 'sha2=']
|
||||
|
||||
var config = require('../../config').getProperties()
|
||||
var server
|
||||
|
||||
return TestServer.start(config)
|
||||
.then(function main(serverObj) {
|
||||
server = serverObj
|
||||
})
|
||||
.then(function () {
|
||||
return request({
|
||||
url: config.publicUrl + '/'
|
||||
})
|
||||
})
|
||||
.spread(function (res) {
|
||||
var headerValue = 'pin-sha256="sha1="; pin-sha256="sha2="; max-age=1; includeSubdomains'
|
||||
assert.equal(res.headers['public-key-pins'], headerValue, 'HPKP header was set correctly')
|
||||
})
|
||||
.then(function () {
|
||||
return server.stop()
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
it(
|
||||
'Sends HPKP report header',
|
||||
() => {
|
||||
process.env.HPKP_ENABLE = true
|
||||
process.env.HPKP_REPORT_ONLY = true
|
||||
process.env.HPKP_PIN_SHA256 = ['sha1=', 'sha2=']
|
||||
process.env.HPKP_REPORT_URI = 'http://example.com'
|
||||
|
||||
var config = require('../../config').getProperties()
|
||||
var server
|
||||
|
||||
return TestServer.start(config)
|
||||
.then(function main(serverObj) {
|
||||
server = serverObj
|
||||
})
|
||||
.then(function () {
|
||||
return request({
|
||||
url: config.publicUrl + '/'
|
||||
})
|
||||
})
|
||||
.spread(function (res) {
|
||||
var headerValue = 'pin-sha256="sha1="; pin-sha256="sha2="; max-age=1; includeSubdomains; report-uri="http://example.com"'
|
||||
assert.equal(res.headers['public-key-pins-report-only'], headerValue, 'HPKP report header was set correctly')
|
||||
})
|
||||
.then(function () {
|
||||
return server.stop()
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
after(() => {
|
||||
delete process.env.HPKP_ENABLE
|
||||
delete process.env.HPKP_REPORT_ONLY
|
||||
delete process.env.HPKP_PIN_SHA256
|
||||
delete process.env.HPKP_REPORT_URI
|
||||
return TestServer.stop()
|
||||
})
|
||||
})
|
||||
|
|
|
@ -2,31 +2,37 @@
|
|||
* 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/. */
|
||||
|
||||
var test = require('../ptaptest')
|
||||
'use strict'
|
||||
|
||||
const assert = require('insist')
|
||||
var TestServer = require('../test_server')
|
||||
const Client = require('../client')()
|
||||
var P = require('../../lib/promise')
|
||||
var hawk = require('hawk')
|
||||
var request = require('request')
|
||||
var request = P.promisify(require('request'))
|
||||
|
||||
var config = require('../../config').getProperties()
|
||||
|
||||
TestServer.start(config)
|
||||
.then(function main(server) {
|
||||
describe('remote misc', function() {
|
||||
this.timeout(15000)
|
||||
let server
|
||||
before(() => {
|
||||
return TestServer.start(config)
|
||||
.then(s => {
|
||||
server = s
|
||||
})
|
||||
})
|
||||
|
||||
function testVersionRoute(route) {
|
||||
return function (t) {
|
||||
request(config.publicUrl + route, function (err, res, body) {
|
||||
t.ok(!err, 'No error fetching ' + route)
|
||||
|
||||
return () => {
|
||||
return request(config.publicUrl + route).spread((res, body) => {
|
||||
var json = JSON.parse(body)
|
||||
t.deepEqual(Object.keys(json), ['version', 'commit', 'source'])
|
||||
t.equal(json.version, require('../../package.json').version, 'package version')
|
||||
t.ok(json.source && json.source !== 'unknown', 'source repository')
|
||||
assert.deepEqual(Object.keys(json), ['version', 'commit', 'source'])
|
||||
assert.equal(json.version, require('../../package.json').version, 'package version')
|
||||
assert.ok(json.source && json.source !== 'unknown', 'source repository')
|
||||
|
||||
// check that the git hash just looks like a hash
|
||||
t.ok(json.commit.match(/^[0-9a-f]{40}$/), 'The git hash actually looks like one')
|
||||
t.end()
|
||||
assert.ok(json.commit.match(/^[0-9a-f]{40}$/), 'The git hash actually looks like one')
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -35,7 +41,7 @@ TestServer.start(config)
|
|||
var randomAllowedOrigin = config.corsOrigin[Math.floor(Math.random() * config.corsOrigin.length)]
|
||||
var expectedOrigin = withAllowedOrigin ? randomAllowedOrigin : undefined
|
||||
|
||||
return function(t) {
|
||||
return () => {
|
||||
var options = {
|
||||
url: config.publicUrl + '/'
|
||||
}
|
||||
|
@ -44,87 +50,81 @@ TestServer.start(config)
|
|||
'Origin': (withAllowedOrigin ? randomAllowedOrigin : 'http://notallowed')
|
||||
}
|
||||
}
|
||||
request(options, function(err, res, body) {
|
||||
t.equal(res.headers['access-control-allow-origin'], expectedOrigin, 'Access-Control-Allow-Origin header was set correctly')
|
||||
t.end()
|
||||
return request(options).spread((res, body) => {
|
||||
assert.equal(res.headers['access-control-allow-origin'], expectedOrigin, 'Access-Control-Allow-Origin header was set correctly')
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
test(
|
||||
it(
|
||||
'unsupported api version',
|
||||
function (t) {
|
||||
request(config.publicUrl + '/v0/account/create', function (err, res) {
|
||||
t.equal(res.statusCode, 410, 'http gone')
|
||||
t.end()
|
||||
() => {
|
||||
return request(config.publicUrl + '/v0/account/create').spread((res) => {
|
||||
assert.equal(res.statusCode, 410, 'http gone')
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'/ returns version, git hash and source repo',
|
||||
testVersionRoute('/')
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'/__version__ returns version, git hash and source repo',
|
||||
testVersionRoute('/__version__')
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'returns no Access-Control-Allow-Origin with no Origin set',
|
||||
testCORSHeader(undefined)
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'returns correct Access-Control-Allow-Origin with whitelisted Origin',
|
||||
testCORSHeader(true)
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'returns no Access-Control-Allow-Origin with not whitelisted Origin',
|
||||
testCORSHeader(false)
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'/verify_email redirects',
|
||||
function (t) {
|
||||
() => {
|
||||
var path = '/v1/verify_email?code=0000&uid=0000'
|
||||
request(
|
||||
return request(
|
||||
{
|
||||
url: config.publicUrl + path,
|
||||
followRedirect: false
|
||||
},
|
||||
function (err, res, body) {
|
||||
t.equal(res.statusCode, 302, 'redirected')
|
||||
//t.equal(res.headers.location, config.contentServer.url + path)
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
})
|
||||
.spread((res, body) => {
|
||||
assert.equal(res.statusCode, 302, 'redirected')
|
||||
//assert.equal(res.headers.location, config.contentServer.url + path)
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'/complete_reset_password redirects',
|
||||
function (t) {
|
||||
() => {
|
||||
var path = '/v1/complete_reset_password?code=0000&email=a@b.c&token=0000'
|
||||
request(
|
||||
return request(
|
||||
{
|
||||
url: config.publicUrl + path,
|
||||
followRedirect: false
|
||||
},
|
||||
function (err, res, body) {
|
||||
t.equal(res.statusCode, 302, 'redirected')
|
||||
//t.equal(res.headers.location, config.contentServer.url + path)
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
})
|
||||
.spread((res, body) => {
|
||||
assert.equal(res.statusCode, 302, 'redirected')
|
||||
//assert.equal(res.headers.location, config.contentServer.url + path)
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'timestamp header',
|
||||
function (t) {
|
||||
() => {
|
||||
var email = server.uniqueEmail()
|
||||
var password = 'allyourbasearebelongtous'
|
||||
var url = null
|
||||
|
@ -144,7 +144,6 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function (token) {
|
||||
var d = P.defer()
|
||||
var method = 'GET'
|
||||
var verify = {
|
||||
credentials: token,
|
||||
|
@ -153,48 +152,39 @@ TestServer.start(config)
|
|||
var headers = {
|
||||
Authorization: hawk.client.header(url, method, verify).field
|
||||
}
|
||||
request(
|
||||
return request(
|
||||
{
|
||||
method: method,
|
||||
url: url,
|
||||
headers: headers,
|
||||
json: true
|
||||
},
|
||||
function (err, res, body) {
|
||||
if (err) {
|
||||
d.reject(err)
|
||||
} else {
|
||||
var now = +new Date() / 1000
|
||||
t.ok(res.headers.timestamp > now - 60, 'has timestamp header')
|
||||
t.ok(res.headers.timestamp < now + 60, 'has timestamp header')
|
||||
d.resolve()
|
||||
}
|
||||
}
|
||||
)
|
||||
return d.promise
|
||||
})
|
||||
.spread((res, body) => {
|
||||
var now = +new Date() / 1000
|
||||
assert.ok(res.headers.timestamp > now - 60, 'has timestamp header')
|
||||
assert.ok(res.headers.timestamp < now + 60, 'has timestamp header')
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'Strict-Transport-Security header',
|
||||
function (t) {
|
||||
request(
|
||||
() => {
|
||||
return request(
|
||||
{
|
||||
url: config.publicUrl + '/'
|
||||
},
|
||||
function (err, res, body) {
|
||||
t.equal(res.headers['strict-transport-security'], 'max-age=15552000; includeSubDomains')
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
})
|
||||
.spread((res, body) => {
|
||||
assert.equal(res.headers['strict-transport-security'], 'max-age=15552000; includeSubDomains')
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'oversized payload',
|
||||
function (t) {
|
||||
() => {
|
||||
var client = new Client(config.publicUrl)
|
||||
return client.api.doRequest(
|
||||
'POST',
|
||||
|
@ -205,37 +195,37 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function (body) {
|
||||
t.fail('request should have failed')
|
||||
assert(false, 'request should have failed')
|
||||
},
|
||||
function (err) {
|
||||
if (err.errno) {
|
||||
t.equal(err.errno, 113, 'payload too large')
|
||||
assert.equal(err.errno, 113, 'payload too large')
|
||||
}
|
||||
else {
|
||||
// nginx returns an html response
|
||||
t.ok(/413 Request Entity Too Large/.test(err), 'payload too large')
|
||||
assert.ok(/413 Request Entity Too Large/.test(err), 'payload too large')
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'random bytes',
|
||||
function (t) {
|
||||
() => {
|
||||
var client = new Client(config.publicUrl)
|
||||
return client.api.getRandomBytes()
|
||||
.then(
|
||||
function (x) {
|
||||
t.equal(x.data.length, 64)
|
||||
assert.equal(x.data.length, 64)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'fetch /.well-known/browserid support document',
|
||||
function (t) {
|
||||
() => {
|
||||
var client = new Client(config.publicUrl)
|
||||
function fetch(url) {
|
||||
return client.api.doRequest('GET', config.publicUrl + url)
|
||||
|
@ -243,12 +233,12 @@ TestServer.start(config)
|
|||
return fetch('/.well-known/browserid')
|
||||
.then(
|
||||
function (doc) {
|
||||
t.ok(doc.hasOwnProperty('public-key'), 'doc has public key')
|
||||
t.ok(/^[0-9]+$/.test(doc['public-key'].n), 'n is base 10')
|
||||
t.ok(/^[0-9]+$/.test(doc['public-key'].e), 'e is base 10')
|
||||
t.ok(doc.hasOwnProperty('authentication'), 'doc has auth page')
|
||||
t.ok(doc.hasOwnProperty('provisioning'), 'doc has provisioning page')
|
||||
t.equal(doc.keys.length, 1)
|
||||
assert.ok(doc.hasOwnProperty('public-key'), 'doc has public key')
|
||||
assert.ok(/^[0-9]+$/.test(doc['public-key'].n), 'n is base 10')
|
||||
assert.ok(/^[0-9]+$/.test(doc['public-key'].e), 'e is base 10')
|
||||
assert.ok(doc.hasOwnProperty('authentication'), 'doc has auth page')
|
||||
assert.ok(doc.hasOwnProperty('provisioning'), 'doc has provisioning page')
|
||||
assert.equal(doc.keys.length, 1)
|
||||
return doc
|
||||
}
|
||||
)
|
||||
|
@ -257,7 +247,7 @@ TestServer.start(config)
|
|||
return fetch(doc.authentication)
|
||||
.then(
|
||||
function (authPage) {
|
||||
t.ok(authPage, 'auth page can be fetched')
|
||||
assert.ok(authPage, 'auth page can be fetched')
|
||||
return doc
|
||||
}
|
||||
)
|
||||
|
@ -268,7 +258,7 @@ TestServer.start(config)
|
|||
return fetch(doc.provisioning)
|
||||
.then(
|
||||
function (provPage) {
|
||||
t.ok(provPage, 'provisioning page can be fetched')
|
||||
assert.ok(provPage, 'provisioning page can be fetched')
|
||||
return doc
|
||||
}
|
||||
)
|
||||
|
@ -277,11 +267,7 @@ TestServer.start(config)
|
|||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'teardown',
|
||||
function (t) {
|
||||
server.stop()
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
after(() => {
|
||||
return TestServer.stop(server)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -2,9 +2,11 @@
|
|||
* 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')
|
||||
const Client = require('../client')()
|
||||
var config = require('../../config').getProperties()
|
||||
var test = require('../ptaptest')
|
||||
var TestServer = require('../test_server')
|
||||
var url = require('url')
|
||||
|
||||
|
@ -18,15 +20,22 @@ function getSessionTokenId(sessionTokenHex) {
|
|||
)
|
||||
}
|
||||
|
||||
process.env.SIGNIN_CONFIRMATION_ENABLED = true
|
||||
process.env.SIGNIN_CONFIRMATION_RATE = 1.0
|
||||
describe('remote password change', function() {
|
||||
this.timeout(15000)
|
||||
let server
|
||||
before(() => {
|
||||
process.env.SIGNIN_CONFIRMATION_ENABLED = true
|
||||
process.env.SIGNIN_CONFIRMATION_RATE = 1.0
|
||||
|
||||
TestServer.start(config)
|
||||
.then(function main(server) {
|
||||
return TestServer.start(config)
|
||||
.then(s => {
|
||||
server = s
|
||||
})
|
||||
})
|
||||
|
||||
test(
|
||||
it(
|
||||
'password change, with unverified session',
|
||||
function (t) {
|
||||
() => {
|
||||
var email = server.uniqueEmail()
|
||||
var password = 'allyourbasearebelongtous'
|
||||
var newPassword = 'foobar'
|
||||
|
@ -54,7 +63,7 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function (status) {
|
||||
t.equal(status.verified, true, 'account is verified')
|
||||
assert.equal(status.verified, true, 'account is verified')
|
||||
}
|
||||
)
|
||||
.then(
|
||||
|
@ -82,9 +91,9 @@ TestServer.start(config)
|
|||
.then(
|
||||
function (status) {
|
||||
// Verify correct status
|
||||
t.equal(status.verified, false, 'account is unverified')
|
||||
t.equal(status.emailVerified, true, 'account email is verified')
|
||||
t.equal(status.sessionVerified, false, 'account session is unverified')
|
||||
assert.equal(status.verified, false, 'account is unverified')
|
||||
assert.equal(status.emailVerified, true, 'account email is verified')
|
||||
assert.equal(status.sessionVerified, false, 'account session is unverified')
|
||||
}
|
||||
)
|
||||
.then(
|
||||
|
@ -100,9 +109,9 @@ TestServer.start(config)
|
|||
.then(
|
||||
function (response) {
|
||||
// Verify correct change password response
|
||||
t.notEqual(response.sessionToken, originalSessionToken, 'session token has changed')
|
||||
t.ok(response.keyFetchToken, 'key fetch token returned')
|
||||
t.notEqual(client.authPW.toString('hex'), firstAuthPW, 'password has changed')
|
||||
assert.notEqual(response.sessionToken, originalSessionToken, 'session token has changed')
|
||||
assert.ok(response.keyFetchToken, 'key fetch token returned')
|
||||
assert.notEqual(client.authPW.toString('hex'), firstAuthPW, 'password has changed')
|
||||
}
|
||||
)
|
||||
.then(
|
||||
|
@ -113,10 +122,10 @@ TestServer.start(config)
|
|||
.then(
|
||||
function (emailData) {
|
||||
var subject = emailData.headers['subject']
|
||||
t.equal(subject, 'Your Firefox Account password has been changed', 'password email subject set correctly')
|
||||
assert.equal(subject, 'Your Firefox Account password has been changed', 'password email subject set correctly')
|
||||
var link = emailData.headers['x-link']
|
||||
var query = url.parse(link, true).query
|
||||
t.ok(query.email, 'email is in the link')
|
||||
assert.ok(query.email, 'email is in the link')
|
||||
}
|
||||
)
|
||||
.then(
|
||||
|
@ -127,9 +136,9 @@ TestServer.start(config)
|
|||
.then(
|
||||
function (status) {
|
||||
// Verify correct status
|
||||
t.equal(status.verified, false, 'account is unverified')
|
||||
t.equal(status.emailVerified, true, 'account email is verified')
|
||||
t.equal(status.sessionVerified, false, 'account session is unverified')
|
||||
assert.equal(status.verified, false, 'account is unverified')
|
||||
assert.equal(status.emailVerified, true, 'account email is verified')
|
||||
assert.equal(status.sessionVerified, false, 'account session is unverified')
|
||||
}
|
||||
)
|
||||
.then(
|
||||
|
@ -145,16 +154,16 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function (keys) {
|
||||
t.deepEqual(keys.kB, kB, 'kB is preserved')
|
||||
t.deepEqual(keys.kA, kA, 'kA is preserved')
|
||||
assert.deepEqual(keys.kB, kB, 'kB is preserved')
|
||||
assert.deepEqual(keys.kA, kA, 'kA is preserved')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'password change, with verified session',
|
||||
function (t) {
|
||||
() => {
|
||||
var email = server.uniqueEmail()
|
||||
var password = 'allyourbasearebelongtous'
|
||||
var newPassword = 'foobar'
|
||||
|
@ -182,7 +191,7 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function (status) {
|
||||
t.equal(status.verified, true, 'account is verified')
|
||||
assert.equal(status.verified, true, 'account is verified')
|
||||
}
|
||||
)
|
||||
.then(
|
||||
|
@ -197,9 +206,9 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function (response) {
|
||||
t.notEqual(response.sessionToken, originalSessionToken, 'session token has changed')
|
||||
t.ok(response.keyFetchToken, 'key fetch token returned')
|
||||
t.notEqual(client.authPW.toString('hex'), firstAuthPW, 'password has changed')
|
||||
assert.notEqual(response.sessionToken, originalSessionToken, 'session token has changed')
|
||||
assert.ok(response.keyFetchToken, 'key fetch token returned')
|
||||
assert.notEqual(client.authPW.toString('hex'), firstAuthPW, 'password has changed')
|
||||
}
|
||||
)
|
||||
.then(
|
||||
|
@ -210,10 +219,10 @@ TestServer.start(config)
|
|||
.then(
|
||||
function (emailData) {
|
||||
var subject = emailData.headers['subject']
|
||||
t.equal(subject, 'Your Firefox Account password has been changed', 'password email subject set correctly')
|
||||
assert.equal(subject, 'Your Firefox Account password has been changed', 'password email subject set correctly')
|
||||
var link = emailData.headers['x-link']
|
||||
var query = url.parse(link, true).query
|
||||
t.ok(query.email, 'email is in the link')
|
||||
assert.ok(query.email, 'email is in the link')
|
||||
}
|
||||
)
|
||||
.then(
|
||||
|
@ -223,7 +232,7 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function (status) {
|
||||
t.equal(status.verified, true, 'account is verified')
|
||||
assert.equal(status.verified, true, 'account is verified')
|
||||
}
|
||||
)
|
||||
.then(
|
||||
|
@ -239,16 +248,16 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function (keys) {
|
||||
t.deepEqual(keys.kB, kB, 'kB is preserved')
|
||||
t.deepEqual(keys.kA, kA, 'kA is preserved')
|
||||
assert.deepEqual(keys.kB, kB, 'kB is preserved')
|
||||
assert.deepEqual(keys.kA, kA, 'kA is preserved')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'password change, with raw session data rather than session token id, return invalid token error',
|
||||
function (t) {
|
||||
() => {
|
||||
var email = server.uniqueEmail()
|
||||
var password = 'allyourbasearebelongtous'
|
||||
var newPassword = 'foobar'
|
||||
|
@ -268,7 +277,7 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function (status) {
|
||||
t.equal(status.verified, true, 'account is verified')
|
||||
assert.equal(status.verified, true, 'account is verified')
|
||||
}
|
||||
)
|
||||
.then(
|
||||
|
@ -278,21 +287,19 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function () {
|
||||
t.fail()
|
||||
}
|
||||
)
|
||||
.catch(
|
||||
assert(false)
|
||||
},
|
||||
function (err) {
|
||||
t.equal(err.errno, 110, 'Invalid token error')
|
||||
t.equal(err.message, 'Invalid authentication token in request signature')
|
||||
assert.equal(err.errno, 110, 'Invalid token error')
|
||||
assert.equal(err.message, 'Invalid authentication token in request signature')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'password change w/o sessionToken',
|
||||
function (t) {
|
||||
() => {
|
||||
var email = server.uniqueEmail()
|
||||
var password = 'allyourbasearebelongtous'
|
||||
var newPassword = 'foobar'
|
||||
|
@ -319,9 +326,9 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function (response) {
|
||||
t.notOk(response.sessionToken, 'no session token returned')
|
||||
t.notOk(response.keyFetchToken, 'no key fetch token returned')
|
||||
t.notEqual(client.authPW.toString('hex'), firstAuthPW, 'password has changed')
|
||||
assert(!response.sessionToken, 'no session token returned')
|
||||
assert(!response.keyFetchToken, 'no key fetch token returned')
|
||||
assert.notEqual(client.authPW.toString('hex'), firstAuthPW, 'password has changed')
|
||||
}
|
||||
)
|
||||
.then(
|
||||
|
@ -332,10 +339,10 @@ TestServer.start(config)
|
|||
.then(
|
||||
function (emailData) {
|
||||
var subject = emailData.headers['subject']
|
||||
t.equal(subject, 'Your Firefox Account password has been changed', 'password email subject set correctly')
|
||||
assert.equal(subject, 'Your Firefox Account password has been changed', 'password email subject set correctly')
|
||||
var link = emailData.headers['x-link']
|
||||
var query = url.parse(link, true).query
|
||||
t.ok(query.email, 'email is in the link')
|
||||
assert.ok(query.email, 'email is in the link')
|
||||
}
|
||||
)
|
||||
.then(
|
||||
|
@ -351,16 +358,16 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function (keys) {
|
||||
t.deepEqual(keys.kB, kB, 'kB is preserved')
|
||||
t.deepEqual(keys.kA, kA, 'kA is preserved')
|
||||
assert.deepEqual(keys.kB, kB, 'kB is preserved')
|
||||
assert.deepEqual(keys.kA, kA, 'kA is preserved')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'wrong password on change start',
|
||||
function (t) {
|
||||
() => {
|
||||
var email = server.uniqueEmail()
|
||||
var password = 'allyourbasearebelongtous'
|
||||
var client = null
|
||||
|
@ -378,19 +385,17 @@ TestServer.start(config)
|
|||
}
|
||||
)
|
||||
.then(
|
||||
t.fail,
|
||||
() => assert(false),
|
||||
function (err) {
|
||||
t.equal(err.errno, 103, 'invalid password')
|
||||
assert.equal(err.errno, 103, 'invalid password')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'teardown',
|
||||
function (t) {
|
||||
server.stop()
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
after(() => {
|
||||
delete process.env.SIGNIN_CONFIRMATION_ENABLED
|
||||
delete process.env.SIGNIN_CONFIRMATION_RATE
|
||||
return TestServer.stop(server)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -2,7 +2,9 @@
|
|||
* 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/. */
|
||||
|
||||
var test = require('tap').test
|
||||
'use strict'
|
||||
|
||||
const assert = require('insist')
|
||||
var url = require('url')
|
||||
const Client = require('../client')()
|
||||
var TestServer = require('../test_server')
|
||||
|
@ -10,14 +12,21 @@ var crypto = require('crypto')
|
|||
var base64url = require('base64url')
|
||||
|
||||
var config = require('../../config').getProperties()
|
||||
process.env.SIGNIN_CONFIRMATION_ENABLED = false
|
||||
|
||||
TestServer.start(config)
|
||||
.then(function main(server) {
|
||||
describe('remote password forgot', function() {
|
||||
this.timeout(15000)
|
||||
let server
|
||||
before(() => {
|
||||
process.env.SIGNIN_CONFIRMATION_ENABLED = false
|
||||
return TestServer.start(config)
|
||||
.then(s => {
|
||||
server = s
|
||||
})
|
||||
})
|
||||
|
||||
test(
|
||||
it(
|
||||
'forgot password',
|
||||
function (t) {
|
||||
() => {
|
||||
var email = server.uniqueEmail()
|
||||
var password = 'allyourbasearebelongtous'
|
||||
var newPassword = 'ez'
|
||||
|
@ -45,7 +54,7 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function (code) {
|
||||
t.throws(function() { client.resetPassword(newPassword) })
|
||||
assert.throws(function() { client.resetPassword(newPassword) })
|
||||
return resetPassword(client, code, newPassword)
|
||||
}
|
||||
)
|
||||
|
@ -58,7 +67,7 @@ TestServer.start(config)
|
|||
function (emailData) {
|
||||
var link = emailData.headers['x-link']
|
||||
var query = url.parse(link, true).query
|
||||
t.ok(query.email, 'email is in the link')
|
||||
assert.ok(query.email, 'email is in the link')
|
||||
}
|
||||
)
|
||||
.then(
|
||||
|
@ -68,10 +77,10 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function (keys) {
|
||||
t.ok(Buffer.isBuffer(keys.wrapKb), 'yep, wrapKb')
|
||||
t.notDeepEqual(wrapKb, keys.wrapKb, 'wrapKb was reset')
|
||||
t.deepEqual(kA, keys.kA, 'kA was not reset')
|
||||
t.equal(client.kB.length, 32, 'kB exists, has the right length')
|
||||
assert.ok(Buffer.isBuffer(keys.wrapKb), 'yep, wrapKb')
|
||||
assert.notDeepEqual(wrapKb, keys.wrapKb, 'wrapKb was reset')
|
||||
assert.deepEqual(kA, keys.kA, 'kA was not reset')
|
||||
assert.equal(client.kB.length, 32, 'kB exists, has the right length')
|
||||
}
|
||||
)
|
||||
.then( // make sure we can still login after password reset
|
||||
|
@ -88,9 +97,9 @@ TestServer.start(config)
|
|||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'forgot password limits verify attempts',
|
||||
function (t) {
|
||||
() => {
|
||||
var code = null
|
||||
var email = server.uniqueEmail()
|
||||
var password = 'hothamburger'
|
||||
|
@ -125,7 +134,7 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function (c) {
|
||||
t.equal(code, c, 'same code as before')
|
||||
assert.equal(code, c, 'same code as before')
|
||||
}
|
||||
)
|
||||
.then(
|
||||
|
@ -135,11 +144,11 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function () {
|
||||
t.fail('reset password with bad code')
|
||||
assert(false, 'reset password with bad code')
|
||||
},
|
||||
function (err) {
|
||||
t.equal(err.tries, 2, 'used a try')
|
||||
t.equal(err.message, 'Invalid verification code', 'bad attempt 1')
|
||||
assert.equal(err.tries, 2, 'used a try')
|
||||
assert.equal(err.message, 'Invalid verification code', 'bad attempt 1')
|
||||
}
|
||||
)
|
||||
.then(
|
||||
|
@ -149,11 +158,11 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function () {
|
||||
t.fail('reset password with bad code')
|
||||
assert(false, 'reset password with bad code')
|
||||
},
|
||||
function (err) {
|
||||
t.equal(err.tries, 1, 'used a try')
|
||||
t.equal(err.message, 'Invalid verification code', 'bad attempt 2')
|
||||
assert.equal(err.tries, 1, 'used a try')
|
||||
assert.equal(err.message, 'Invalid verification code', 'bad attempt 2')
|
||||
}
|
||||
)
|
||||
.then(
|
||||
|
@ -163,11 +172,11 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function () {
|
||||
t.fail('reset password with bad code')
|
||||
assert(false, 'reset password with bad code')
|
||||
},
|
||||
function (err) {
|
||||
t.equal(err.tries, 0, 'used a try')
|
||||
t.equal(err.message, 'Invalid verification code', 'bad attempt 3')
|
||||
assert.equal(err.tries, 0, 'used a try')
|
||||
assert.equal(err.message, 'Invalid verification code', 'bad attempt 3')
|
||||
}
|
||||
)
|
||||
.then(
|
||||
|
@ -177,18 +186,18 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function () {
|
||||
t.fail('reset password with invalid token')
|
||||
assert(false, 'reset password with invalid token')
|
||||
},
|
||||
function (err) {
|
||||
t.equal(err.message, 'Invalid authentication token in request signature', 'token is now invalid')
|
||||
assert.equal(err.message, 'Invalid authentication token in request signature', 'token is now invalid')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'recovery email link',
|
||||
function (t) {
|
||||
() => {
|
||||
var email = server.uniqueEmail()
|
||||
var password = 'something'
|
||||
var client = null
|
||||
|
@ -221,19 +230,19 @@ TestServer.start(config)
|
|||
function (emailData) {
|
||||
var link = emailData.headers['x-link']
|
||||
var query = url.parse(link, true).query
|
||||
t.ok(query.token, 'uid is in link')
|
||||
t.ok(query.code, 'code is in link')
|
||||
t.equal(query.redirectTo, options.redirectTo, 'redirectTo is in link')
|
||||
t.equal(query.service, options.service, 'service is in link')
|
||||
t.equal(query.email, email, 'email is in link')
|
||||
assert.ok(query.token, 'uid is in link')
|
||||
assert.ok(query.code, 'code is in link')
|
||||
assert.equal(query.redirectTo, options.redirectTo, 'redirectTo is in link')
|
||||
assert.equal(query.service, options.service, 'service is in link')
|
||||
assert.equal(query.email, email, 'email is in link')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'password forgot status with valid token',
|
||||
function (t) {
|
||||
() => {
|
||||
var email = server.uniqueEmail()
|
||||
var password = 'something'
|
||||
return Client.create(config.publicUrl, email, password)
|
||||
|
@ -247,8 +256,8 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function (x) {
|
||||
t.equal(x.tries, 3, 'three tries remaining')
|
||||
t.ok(x.ttl > 0 && x.ttl <= (60 * 60), 'ttl is ok')
|
||||
assert.equal(x.tries, 3, 'three tries remaining')
|
||||
assert.ok(x.ttl > 0 && x.ttl <= (60 * 60), 'ttl is ok')
|
||||
}
|
||||
)
|
||||
}
|
||||
|
@ -256,23 +265,23 @@ TestServer.start(config)
|
|||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'password forgot status with invalid token',
|
||||
function (t) {
|
||||
() => {
|
||||
var client = new Client(config.publicUrl)
|
||||
return client.api.passwordForgotStatus('0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF')
|
||||
.then(
|
||||
t.fail,
|
||||
() => assert(false),
|
||||
function (err) {
|
||||
t.equal(err.errno, 110, 'invalid token')
|
||||
assert.equal(err.errno, 110, 'invalid token')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'/password/forgot/verify_code should set an unverified account as verified',
|
||||
function (t) {
|
||||
() => {
|
||||
var email = server.uniqueEmail()
|
||||
var password = 'something'
|
||||
var client = null
|
||||
|
@ -285,7 +294,7 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function (status) {
|
||||
t.equal(status.verified, false, 'email unverified')
|
||||
assert.equal(status.verified, false, 'email unverified')
|
||||
}
|
||||
)
|
||||
.then(
|
||||
|
@ -315,15 +324,15 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function (status) {
|
||||
t.equal(status.verified, true, 'account unverified')
|
||||
assert.equal(status.verified, true, 'account unverified')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'forgot password with service query parameter',
|
||||
function (t) {
|
||||
() => {
|
||||
var email = server.uniqueEmail()
|
||||
var options = {
|
||||
redirectTo: 'https://sync.' + config.smtp.redirectDomain,
|
||||
|
@ -346,14 +355,14 @@ TestServer.start(config)
|
|||
.then(function (emailData) {
|
||||
var link = emailData.headers['x-link']
|
||||
var query = url.parse(link, true).query
|
||||
t.equal(query.service, options.serviceQuery, 'service is in link')
|
||||
assert.equal(query.service, options.serviceQuery, 'service is in link')
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'forgot password, then get device list',
|
||||
function (t) {
|
||||
() => {
|
||||
var email = server.uniqueEmail()
|
||||
var newPassword = 'foo'
|
||||
var client
|
||||
|
@ -377,7 +386,7 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function (devices) {
|
||||
t.equal(devices.length, 1, 'devices list contains 1 item')
|
||||
assert.equal(devices.length, 1, 'devices list contains 1 item')
|
||||
}
|
||||
)
|
||||
.then(
|
||||
|
@ -407,24 +416,22 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function (devices) {
|
||||
t.equal(devices.length, 0, 'devices list is empty')
|
||||
assert.equal(devices.length, 0, 'devices list is empty')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'teardown',
|
||||
function (t) {
|
||||
server.stop()
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
})
|
||||
after(() => {
|
||||
delete process.env.SIGNIN_CONFIRMATION_ENABLED
|
||||
return TestServer.stop(server)
|
||||
})
|
||||
|
||||
function resetPassword(client, code, newPassword, options) {
|
||||
return client.verifyPasswordResetCode(code)
|
||||
.then(function() {
|
||||
return client.resetPassword(newPassword, {}, options)
|
||||
})
|
||||
}
|
||||
function resetPassword(client, code, newPassword, options) {
|
||||
return client.verifyPasswordResetCode(code)
|
||||
.then(function() {
|
||||
return client.resetPassword(newPassword, {}, options)
|
||||
})
|
||||
}
|
||||
|
||||
})
|
||||
|
|
|
@ -2,14 +2,15 @@
|
|||
* 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/. */
|
||||
|
||||
var tap = require('tap')
|
||||
var test = tap.test
|
||||
'use strict'
|
||||
|
||||
const assert = require('insist')
|
||||
var P = require('../../lib/promise')
|
||||
var uuid = require('uuid')
|
||||
var crypto = require('crypto')
|
||||
var base64url = require('base64url')
|
||||
var proxyquire = require('proxyquire')
|
||||
var log = { trace: console.log, info: console.log } // eslint-disable-line no-console
|
||||
var log = { trace() {}, info() {} }
|
||||
|
||||
var config = require('../../config').getProperties()
|
||||
var TestServer = require('../test_server')
|
||||
|
@ -52,115 +53,113 @@ var mockLog = {
|
|||
}
|
||||
}
|
||||
|
||||
var dbServer
|
||||
var dbConn = TestServer.start(config)
|
||||
.then(
|
||||
function (server) {
|
||||
dbServer = server
|
||||
describe('remote push db', function() {
|
||||
this.timeout(15000)
|
||||
|
||||
let dbServer, db
|
||||
before(() => {
|
||||
return TestServer.start(config)
|
||||
.then(s => {
|
||||
dbServer = s
|
||||
return DB.connect(config[config.db.backend])
|
||||
}
|
||||
)
|
||||
})
|
||||
.then(x => {
|
||||
db = x
|
||||
})
|
||||
})
|
||||
|
||||
test(
|
||||
'push db tests',
|
||||
function (t) {
|
||||
var sessionTokenId
|
||||
var deviceInfo = {
|
||||
id: crypto.randomBytes(16),
|
||||
name: 'my push device',
|
||||
type: 'mobile',
|
||||
pushCallback: 'https://foo/bar',
|
||||
pushPublicKey: base64url(Buffer.concat([new Buffer('\x04'), crypto.randomBytes(64)])),
|
||||
pushAuthKey: base64url(crypto.randomBytes(16))
|
||||
}
|
||||
// two tests below, first for unknown 400 level error the device push info will stay the same
|
||||
// second, for a known 400 error we reset the device
|
||||
var mocksKnown400 = {
|
||||
'web-push': {
|
||||
sendNotification: function (endpoint, params) {
|
||||
var err = new Error('Failed 400 level')
|
||||
err.statusCode = 410
|
||||
return P.reject(err)
|
||||
it(
|
||||
'push db tests',
|
||||
() => {
|
||||
var sessionTokenId
|
||||
var deviceInfo = {
|
||||
id: crypto.randomBytes(16),
|
||||
name: 'my push device',
|
||||
type: 'mobile',
|
||||
pushCallback: 'https://foo/bar',
|
||||
pushPublicKey: base64url(Buffer.concat([new Buffer('\x04'), crypto.randomBytes(64)])),
|
||||
pushAuthKey: base64url(crypto.randomBytes(16))
|
||||
}
|
||||
// two tests below, first for unknown 400 level error the device push info will stay the same
|
||||
// second, for a known 400 error we reset the device
|
||||
var mocksKnown400 = {
|
||||
'web-push': {
|
||||
sendNotification: function (endpoint, params) {
|
||||
var err = new Error('Failed 400 level')
|
||||
err.statusCode = 410
|
||||
return P.reject(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
var mocksUnknown400 = {
|
||||
'web-push': {
|
||||
sendNotification: function (endpoint, params) {
|
||||
var err = new Error('Failed 429 level')
|
||||
err.statusCode = 429
|
||||
return P.reject(err)
|
||||
var mocksUnknown400 = {
|
||||
'web-push': {
|
||||
sendNotification: function (endpoint, params) {
|
||||
var err = new Error('Failed 429 level')
|
||||
err.statusCode = 429
|
||||
return P.reject(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dbConn.then(function (db) {
|
||||
return db.createAccount(ACCOUNT)
|
||||
.then(function() {
|
||||
return db.emailRecord(ACCOUNT.email)
|
||||
})
|
||||
.then(function(emailRecord) {
|
||||
emailRecord.createdAt = Date.now()
|
||||
return db.createSessionToken(emailRecord, SESSION_TOKEN_UA)
|
||||
})
|
||||
.then(function() {
|
||||
return db.emailRecord(ACCOUNT.email)
|
||||
})
|
||||
.then(function(emailRecord) {
|
||||
emailRecord.createdAt = Date.now()
|
||||
return db.createSessionToken(emailRecord, SESSION_TOKEN_UA)
|
||||
})
|
||||
|
||||
.then(function (sessionToken) {
|
||||
sessionTokenId = sessionToken.tokenId
|
||||
return db.createDevice(ACCOUNT.uid, sessionTokenId, deviceInfo)
|
||||
})
|
||||
.then(function (device) {
|
||||
t.equal(device.name, deviceInfo.name)
|
||||
t.equal(device.pushCallback, deviceInfo.pushCallback)
|
||||
t.equal(device.pushPublicKey, deviceInfo.pushPublicKey)
|
||||
t.equal(device.pushAuthKey, deviceInfo.pushAuthKey)
|
||||
})
|
||||
.then(function () {
|
||||
return db.devices(ACCOUNT.uid)
|
||||
})
|
||||
.then(function (sessionToken) {
|
||||
sessionTokenId = sessionToken.tokenId
|
||||
return db.createDevice(ACCOUNT.uid, sessionTokenId, deviceInfo)
|
||||
})
|
||||
.then(function (device) {
|
||||
assert.equal(device.name, deviceInfo.name)
|
||||
assert.equal(device.pushCallback, deviceInfo.pushCallback)
|
||||
assert.equal(device.pushPublicKey, deviceInfo.pushPublicKey)
|
||||
assert.equal(device.pushAuthKey, deviceInfo.pushAuthKey)
|
||||
})
|
||||
.then(function () {
|
||||
return db.devices(ACCOUNT.uid)
|
||||
})
|
||||
|
||||
.then(function () {
|
||||
var pushWithUnknown400 = proxyquire('../../lib/push', mocksUnknown400)(mockLog, db, {})
|
||||
return pushWithUnknown400.pushToAllDevices(ACCOUNT.uid, 'accountVerify')
|
||||
})
|
||||
.then(function () {
|
||||
return db.devices(ACCOUNT.uid)
|
||||
})
|
||||
.then(function (devices) {
|
||||
var device = devices[0]
|
||||
t.equal(device.name, deviceInfo.name)
|
||||
t.equal(device.pushCallback, deviceInfo.pushCallback)
|
||||
t.equal(device.pushPublicKey, deviceInfo.pushPublicKey, 'device.pushPublicKey is correct')
|
||||
t.equal(device.pushAuthKey, deviceInfo.pushAuthKey, 'device.pushAuthKey is correct')
|
||||
})
|
||||
.then(function () {
|
||||
var pushWithUnknown400 = proxyquire('../../lib/push', mocksUnknown400)(mockLog, db, {})
|
||||
return pushWithUnknown400.pushToAllDevices(ACCOUNT.uid, 'accountVerify')
|
||||
})
|
||||
.then(function () {
|
||||
return db.devices(ACCOUNT.uid)
|
||||
})
|
||||
.then(function (devices) {
|
||||
var device = devices[0]
|
||||
assert.equal(device.name, deviceInfo.name)
|
||||
assert.equal(device.pushCallback, deviceInfo.pushCallback)
|
||||
assert.equal(device.pushPublicKey, deviceInfo.pushPublicKey, 'device.pushPublicKey is correct')
|
||||
assert.equal(device.pushAuthKey, deviceInfo.pushAuthKey, 'device.pushAuthKey is correct')
|
||||
})
|
||||
|
||||
.then(function () {
|
||||
var pushWithKnown400 = proxyquire('../../lib/push', mocksKnown400)(mockLog, db, {})
|
||||
return pushWithKnown400.pushToAllDevices(ACCOUNT.uid, 'accountVerify')
|
||||
})
|
||||
.then(function () {
|
||||
return db.devices(ACCOUNT.uid)
|
||||
})
|
||||
.then(function (devices) {
|
||||
var device = devices[0]
|
||||
t.equal(device.name, deviceInfo.name)
|
||||
t.equal(device.pushCallback, '')
|
||||
t.equal(device.pushPublicKey, '', 'device.pushPublicKey is correct')
|
||||
t.equal(device.pushAuthKey, '', 'device.pushAuthKey is correct')
|
||||
t.end()
|
||||
})
|
||||
})
|
||||
}
|
||||
)
|
||||
.then(function () {
|
||||
var pushWithKnown400 = proxyquire('../../lib/push', mocksKnown400)(mockLog, db, {})
|
||||
return pushWithKnown400.pushToAllDevices(ACCOUNT.uid, 'accountVerify')
|
||||
})
|
||||
.then(function () {
|
||||
return db.devices(ACCOUNT.uid)
|
||||
})
|
||||
.then(function (devices) {
|
||||
var device = devices[0]
|
||||
assert.equal(device.name, deviceInfo.name)
|
||||
assert.equal(device.pushCallback, '')
|
||||
assert.equal(device.pushPublicKey, '', 'device.pushPublicKey is correct')
|
||||
assert.equal(device.pushAuthKey, '', 'device.pushAuthKey is correct')
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'teardown',
|
||||
function (t) {
|
||||
return dbConn.then(function(db) {
|
||||
return db.close()
|
||||
}).then(function() {
|
||||
return dbServer.stop()
|
||||
}).then(function () {
|
||||
t.end()
|
||||
})
|
||||
}
|
||||
)
|
||||
after(() => {
|
||||
return P.all([
|
||||
TestServer.stop(dbServer),
|
||||
db.close()
|
||||
])
|
||||
})
|
||||
})
|
||||
|
|
|
@ -2,147 +2,154 @@
|
|||
* 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/. */
|
||||
|
||||
var test = require('../ptaptest')
|
||||
'use strict'
|
||||
|
||||
const assert = require('insist')
|
||||
const Client = require('../client')()
|
||||
var TestServer = require('../test_server')
|
||||
|
||||
var config = require('../../config').getProperties()
|
||||
|
||||
process.env.SIGNIN_CONFIRMATION_ENABLED = true
|
||||
process.env.SIGNIN_CONFIRMATION_RATE = 1.0
|
||||
describe('remote recovery email resend code', function() {
|
||||
this.timeout(15000)
|
||||
let server
|
||||
before(() => {
|
||||
process.env.SIGNIN_CONFIRMATION_ENABLED = true
|
||||
process.env.SIGNIN_CONFIRMATION_RATE = 1.0
|
||||
|
||||
TestServer.start(config)
|
||||
.then(function main(server) {
|
||||
|
||||
test(
|
||||
'sign-in verification resend email verify code',
|
||||
function (t) {
|
||||
var email = server.uniqueEmail()
|
||||
var password = 'something'
|
||||
var verifyEmailCode = ''
|
||||
var client = null
|
||||
var options = {
|
||||
redirectTo: 'https://sync.' + config.smtp.redirectDomain,
|
||||
service: 'sync',
|
||||
resume: 'resumeToken',
|
||||
keys: true
|
||||
}
|
||||
return Client.create(config.publicUrl, email, password, server.mailbox, options)
|
||||
.then(
|
||||
function (c) {
|
||||
client = c
|
||||
return Client.login(config.publicUrl, email, password, server.mailbox, options)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
return server.mailbox.waitForCode(email)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (code) {
|
||||
verifyEmailCode = code
|
||||
return client.requestVerifyEmail()
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
return server.mailbox.waitForCode(email)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (code) {
|
||||
t.equal(code, verifyEmailCode, 'code equal to verify email code')
|
||||
return client.verifyEmail(code)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
return client.emailStatus()
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (status) {
|
||||
t.equal(status.verified, true, 'account is verified')
|
||||
t.equal(status.emailVerified, true, 'account email is verified')
|
||||
t.equal(status.sessionVerified, true, 'account session is verified')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'sign-in verification resend login verify code',
|
||||
function (t) {
|
||||
var email = server.uniqueEmail()
|
||||
var password = 'something'
|
||||
var verifyEmailCode = ''
|
||||
var client2 = null
|
||||
var options = {
|
||||
redirectTo: 'https://sync.' + config.smtp.redirectDomain,
|
||||
service: 'sync',
|
||||
resume: 'resumeToken',
|
||||
keys: true
|
||||
}
|
||||
return Client.createAndVerify(config.publicUrl, email, password, server.mailbox, options)
|
||||
.then(
|
||||
function () {
|
||||
// Attempt to login from new location
|
||||
return Client.login(config.publicUrl, email, password, server.mailbox, options)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (c) {
|
||||
client2 = c
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
return client2.login(options)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
return server.mailbox.waitForCode(email)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (code) {
|
||||
verifyEmailCode = code
|
||||
return client2.requestVerifyEmail()
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
return server.mailbox.waitForCode(email)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (code) {
|
||||
t.equal(code, verifyEmailCode, 'code equal to verify email code')
|
||||
return client2.verifyEmail(code)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
return client2.emailStatus()
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (status) {
|
||||
t.equal(status.verified, true, 'account is verified')
|
||||
t.equal(status.emailVerified, true, 'account email is verified')
|
||||
t.equal(status.sessionVerified, true, 'account session is verified')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'teardown',
|
||||
function (t) {
|
||||
server.stop()
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
return TestServer.start(config)
|
||||
.then(s => {
|
||||
server = s
|
||||
})
|
||||
})
|
||||
|
||||
it(
|
||||
'sign-in verification resend email verify code',
|
||||
() => {
|
||||
var email = server.uniqueEmail()
|
||||
var password = 'something'
|
||||
var verifyEmailCode = ''
|
||||
var client = null
|
||||
var options = {
|
||||
redirectTo: 'https://sync.' + config.smtp.redirectDomain,
|
||||
service: 'sync',
|
||||
resume: 'resumeToken',
|
||||
keys: true
|
||||
}
|
||||
return Client.create(config.publicUrl, email, password, server.mailbox, options)
|
||||
.then(
|
||||
function (c) {
|
||||
client = c
|
||||
return Client.login(config.publicUrl, email, password, server.mailbox, options)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
return server.mailbox.waitForCode(email)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (code) {
|
||||
verifyEmailCode = code
|
||||
return client.requestVerifyEmail()
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
return server.mailbox.waitForCode(email)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (code) {
|
||||
assert.equal(code, verifyEmailCode, 'code equal to verify email code')
|
||||
return client.verifyEmail(code)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
return client.emailStatus()
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (status) {
|
||||
assert.equal(status.verified, true, 'account is verified')
|
||||
assert.equal(status.emailVerified, true, 'account email is verified')
|
||||
assert.equal(status.sessionVerified, true, 'account session is verified')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
it(
|
||||
'sign-in verification resend login verify code',
|
||||
() => {
|
||||
var email = server.uniqueEmail()
|
||||
var password = 'something'
|
||||
var verifyEmailCode = ''
|
||||
var client2 = null
|
||||
var options = {
|
||||
redirectTo: 'https://sync.' + config.smtp.redirectDomain,
|
||||
service: 'sync',
|
||||
resume: 'resumeToken',
|
||||
keys: true
|
||||
}
|
||||
return Client.createAndVerify(config.publicUrl, email, password, server.mailbox, options)
|
||||
.then(
|
||||
function () {
|
||||
// Attempt to login from new location
|
||||
return Client.login(config.publicUrl, email, password, server.mailbox, options)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (c) {
|
||||
client2 = c
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
return client2.login(options)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
return server.mailbox.waitForCode(email)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (code) {
|
||||
verifyEmailCode = code
|
||||
return client2.requestVerifyEmail()
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
return server.mailbox.waitForCode(email)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (code) {
|
||||
assert.equal(code, verifyEmailCode, 'code equal to verify email code')
|
||||
return client2.verifyEmail(code)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
return client2.emailStatus()
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (status) {
|
||||
assert.equal(status.verified, true, 'account is verified')
|
||||
assert.equal(status.emailVerified, true, 'account email is verified')
|
||||
assert.equal(status.sessionVerified, true, 'account session is verified')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
after(() => {
|
||||
delete process.env.SIGNIN_CONFIRMATION_ENABLED
|
||||
delete process.env.SIGNIN_CONFIRMATION_RATE
|
||||
return TestServer.stop(server)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -2,19 +2,28 @@
|
|||
* 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/. */
|
||||
|
||||
var test = require('../ptaptest')
|
||||
'use strict'
|
||||
|
||||
const assert = require('insist')
|
||||
var url = require('url')
|
||||
const Client = require('../client')()
|
||||
var TestServer = require('../test_server')
|
||||
|
||||
var config = require('../../config').getProperties()
|
||||
|
||||
TestServer.start(config)
|
||||
.then(function main(server) {
|
||||
describe('remote recovery email verify', function() {
|
||||
this.timeout(15000)
|
||||
let server
|
||||
before(() => {
|
||||
return TestServer.start(config)
|
||||
.then(s => {
|
||||
server = s
|
||||
})
|
||||
})
|
||||
|
||||
test(
|
||||
it(
|
||||
'create account verify with incorrect code',
|
||||
function (t) {
|
||||
() => {
|
||||
var email = server.uniqueEmail()
|
||||
var password = 'allyourbasearebelongtous'
|
||||
var client = null
|
||||
|
@ -31,7 +40,7 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function (status) {
|
||||
t.equal(status.verified, false, 'new account is not verified')
|
||||
assert.equal(status.verified, false, 'new account is not verified')
|
||||
}
|
||||
)
|
||||
.then(
|
||||
|
@ -41,10 +50,10 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function () {
|
||||
t.fail('verified email with bad code')
|
||||
assert(false, 'verified email with bad code')
|
||||
},
|
||||
function (err) {
|
||||
t.equal(err.message.toString(), 'Invalid verification code', 'bad attempt')
|
||||
assert.equal(err.message.toString(), 'Invalid verification code', 'bad attempt')
|
||||
}
|
||||
)
|
||||
.then(
|
||||
|
@ -54,15 +63,15 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function (status) {
|
||||
t.equal(status.verified, false, 'account not verified')
|
||||
assert.equal(status.verified, false, 'account not verified')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'verification email link',
|
||||
function (t) {
|
||||
() => {
|
||||
var email = server.uniqueEmail()
|
||||
var password = 'something'
|
||||
var client = null // eslint-disable-line no-unused-vars
|
||||
|
@ -85,20 +94,16 @@ TestServer.start(config)
|
|||
function (emailData) {
|
||||
var link = emailData.headers['x-link']
|
||||
var query = url.parse(link, true).query
|
||||
t.ok(query.uid, 'uid is in link')
|
||||
t.ok(query.code, 'code is in link')
|
||||
t.equal(query.redirectTo, options.redirectTo, 'redirectTo is in link')
|
||||
t.equal(query.service, options.service, 'service is in link')
|
||||
assert.ok(query.uid, 'uid is in link')
|
||||
assert.ok(query.code, 'code is in link')
|
||||
assert.equal(query.redirectTo, options.redirectTo, 'redirectTo is in link')
|
||||
assert.equal(query.service, options.service, 'service is in link')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'teardown',
|
||||
function (t) {
|
||||
server.stop()
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
after(() => {
|
||||
return TestServer.stop(server)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -2,18 +2,27 @@
|
|||
* 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/. */
|
||||
|
||||
var test = require('tap').test
|
||||
'use strict'
|
||||
|
||||
const assert = require('insist')
|
||||
var TestServer = require('../test_server')
|
||||
const Client = require('../client')()
|
||||
|
||||
var config = require('../../config').getProperties()
|
||||
|
||||
TestServer.start(config)
|
||||
.then(function main(server) {
|
||||
describe('remote session destroy', function() {
|
||||
this.timeout(15000)
|
||||
let server
|
||||
before(() => {
|
||||
return TestServer.start(config)
|
||||
.then(s => {
|
||||
server = s
|
||||
})
|
||||
})
|
||||
|
||||
test(
|
||||
it(
|
||||
'session destroy',
|
||||
function (t) {
|
||||
() => {
|
||||
var email = server.uniqueEmail()
|
||||
var password = 'foobar'
|
||||
var client = null
|
||||
|
@ -33,25 +42,25 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function () {
|
||||
t.equal(client.sessionToken, null, 'session token deleted')
|
||||
assert.equal(client.sessionToken, null, 'session token deleted')
|
||||
client.sessionToken = sessionToken
|
||||
return client.sessionStatus()
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (status) {
|
||||
t.fail('got status with destroyed session')
|
||||
assert(false, 'got status with destroyed session')
|
||||
},
|
||||
function (err) {
|
||||
t.equal(err.errno, 110, 'session is invalid')
|
||||
assert.equal(err.errno, 110, 'session is invalid')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'session status with valid token',
|
||||
function (t) {
|
||||
() => {
|
||||
var email = server.uniqueEmail()
|
||||
var password = 'testx'
|
||||
var uid = null
|
||||
|
@ -69,31 +78,27 @@ TestServer.start(config)
|
|||
)
|
||||
.then(
|
||||
function (x) {
|
||||
t.deepEqual(x, { uid: uid }, 'good status')
|
||||
assert.deepEqual(x, { uid: uid }, 'good status')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
it(
|
||||
'session status with invalid token',
|
||||
function (t) {
|
||||
() => {
|
||||
var client = new Client(config.publicUrl)
|
||||
return client.api.sessionStatus('0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF')
|
||||
.then(
|
||||
t.fail,
|
||||
() => assert(false),
|
||||
function (err) {
|
||||
t.equal(err.errno, 110, 'invalid token')
|
||||
assert.equal(err.errno, 110, 'invalid token')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'teardown',
|
||||
function (t) {
|
||||
server.stop()
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
after(() => {
|
||||
return TestServer.stop(server)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -2,41 +2,41 @@
|
|||
* 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/. */
|
||||
|
||||
var test = require('../ptaptest')
|
||||
'use strict'
|
||||
|
||||
const assert = require('insist')
|
||||
var TestServer = require('../test_server')
|
||||
var P = require('../../lib/promise')
|
||||
var request = require('request')
|
||||
var request = P.promisify(require('request'))
|
||||
var path = require('path')
|
||||
|
||||
process.env.OLD_PUBLIC_KEY_FILE = path.resolve(__dirname, '../../config/public-key.json')
|
||||
var config = require('../../config').getProperties()
|
||||
describe('remote sign key', function() {
|
||||
this.timeout(15000)
|
||||
let server
|
||||
before(() => {
|
||||
process.env.OLD_PUBLIC_KEY_FILE = path.resolve(__dirname, '../../config/public-key.json')
|
||||
var config = require('../../config').getProperties()
|
||||
return TestServer.start(config)
|
||||
.then(s => {
|
||||
server = s
|
||||
})
|
||||
})
|
||||
|
||||
TestServer.start(config)
|
||||
.then(function main(server) {
|
||||
|
||||
test(
|
||||
it(
|
||||
'.well-known/browserid has keys',
|
||||
function (t) {
|
||||
var d = P.defer()
|
||||
request('http://127.0.0.1:9000/.well-known/browserid',
|
||||
function (err, res, body) {
|
||||
if (err) { d.reject(err) }
|
||||
t.equal(res.statusCode, 200)
|
||||
() => {
|
||||
return request('http://127.0.0.1:9000/.well-known/browserid')
|
||||
.spread((res, body) => {
|
||||
assert.equal(res.statusCode, 200)
|
||||
var json = JSON.parse(body)
|
||||
t.equal(json.authentication, '/.well-known/browserid/sign_in.html')
|
||||
t.equal(json.keys.length, 2)
|
||||
d.resolve(json)
|
||||
}
|
||||
)
|
||||
return d.promise
|
||||
assert.equal(json.authentication, '/.well-known/browserid/sign_in.html')
|
||||
assert.equal(json.keys.length, 2)
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'teardown',
|
||||
function (t) {
|
||||
server.stop()
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
after(() => {
|
||||
delete process.env.OLD_PUBLIC_KEY_FILE
|
||||
return TestServer.stop(server)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -2,21 +2,30 @@
|
|||
* 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/. */
|
||||
|
||||
var test = require('../ptaptest')
|
||||
'use strict'
|
||||
|
||||
const assert = require('insist')
|
||||
var TestServer = require('../test_server')
|
||||
const Client = require('../client')()
|
||||
|
||||
process.env.PASSWORD_CHANGE_TOKEN_TTL = '1'
|
||||
var config = require('../../config').getProperties()
|
||||
|
||||
function fail() { throw new Error() }
|
||||
|
||||
TestServer.start(config)
|
||||
.then(function main(server) {
|
||||
describe('remote token expiry', function() {
|
||||
this.timeout(15000)
|
||||
let server, config
|
||||
before(() => {
|
||||
process.env.PASSWORD_CHANGE_TOKEN_TTL = '1'
|
||||
config = require('../../config').getProperties()
|
||||
|
||||
test(
|
||||
return TestServer.start(config)
|
||||
.then(s => {
|
||||
server = s
|
||||
})
|
||||
})
|
||||
|
||||
it(
|
||||
'token expiry',
|
||||
function (t) {
|
||||
() => {
|
||||
// FYI config.tokenLifetimes.passwordChangeToken = 1
|
||||
var email = Math.random() + '@example.com'
|
||||
var password = 'ok'
|
||||
|
@ -29,17 +38,14 @@ TestServer.start(config)
|
|||
.then(
|
||||
fail,
|
||||
function (err) {
|
||||
t.equal(err.errno, 110, 'invalid token')
|
||||
assert.equal(err.errno, 110, 'invalid token')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'teardown',
|
||||
function (t) {
|
||||
server.stop()
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
after(() => {
|
||||
delete process.env.PASSWORD_CHANGE_TOKEN_TTL
|
||||
return TestServer.stop(server)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -2,10 +2,11 @@
|
|||
* 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/. */
|
||||
|
||||
var tap = require('tap')
|
||||
var test = tap.test
|
||||
'use strict'
|
||||
|
||||
const assert = require('insist')
|
||||
var uuid = require('uuid')
|
||||
var log = { trace: console.log, info: console.log } // eslint-disable-line no-console
|
||||
var log = { trace() {}, info() {} }
|
||||
|
||||
var config = require('../../config').getProperties()
|
||||
var TestServer = require('../test_server')
|
||||
|
@ -41,55 +42,51 @@ function createTestAccount() {
|
|||
|
||||
var mockLog = require('../mocks').mockLog
|
||||
|
||||
var dbServer, reminderConfig
|
||||
var dbConn = TestServer.start(config)
|
||||
.then(
|
||||
function (server) {
|
||||
dbServer = server
|
||||
reminderConfig = process.env.VERIFICATION_REMINDER_RATE
|
||||
process.env.VERIFICATION_REMINDER_RATE = 1
|
||||
return DB.connect(config[config.db.backend])
|
||||
}
|
||||
)
|
||||
describe('remote verification reminder db', function() {
|
||||
this.timeout(15000)
|
||||
|
||||
test(
|
||||
'create',
|
||||
function (t) {
|
||||
var thisMockLog = mockLog({
|
||||
increment: function (name) {
|
||||
t.equal(name, 'verification-reminders.created')
|
||||
}
|
||||
})
|
||||
let dbServer, reminderConfig, db
|
||||
before(() => {
|
||||
return TestServer.start(config)
|
||||
.then(s => {
|
||||
dbServer = s
|
||||
reminderConfig = process.env.VERIFICATION_REMINDER_RATE
|
||||
process.env.VERIFICATION_REMINDER_RATE = 1
|
||||
return DB.connect(config[config.db.backend])
|
||||
})
|
||||
.then(x => {
|
||||
db = x
|
||||
})
|
||||
})
|
||||
|
||||
it(
|
||||
'create',
|
||||
() => {
|
||||
var thisMockLog = mockLog({
|
||||
increment: function (name) {
|
||||
assert.equal(name, 'verification-reminders.created')
|
||||
}
|
||||
})
|
||||
|
||||
dbConn.then(function (db) {
|
||||
var account = createTestAccount()
|
||||
var reminder = { uid: account.uid.toString('hex') }
|
||||
|
||||
var verificationReminder = require('../../lib/verification-reminders')(thisMockLog, db)
|
||||
return verificationReminder.create(reminder).then(
|
||||
function () {
|
||||
t.end()
|
||||
},
|
||||
function () {
|
||||
t.fail()
|
||||
return verificationReminder.create(reminder)
|
||||
}
|
||||
)
|
||||
|
||||
it(
|
||||
'delete',
|
||||
() => {
|
||||
var thisMockLog = mockLog({
|
||||
increment: function (name) {
|
||||
if (name === 'verification-reminders.deleted') {
|
||||
assert.ok(true, 'correct log message')
|
||||
}
|
||||
)
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'delete',
|
||||
function (t) {
|
||||
var thisMockLog = mockLog({
|
||||
increment: function (name) {
|
||||
if (name === 'verification-reminders.deleted') {
|
||||
t.ok(true, 'correct log message')
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
dbConn.then(function (db) {
|
||||
var verificationReminder = require('../../lib/verification-reminders')(thisMockLog, db)
|
||||
var account = createTestAccount()
|
||||
var reminder = { uid: account.uid.toString('hex') }
|
||||
|
@ -98,25 +95,16 @@ test(
|
|||
.then(function () {
|
||||
return verificationReminder.delete(reminder)
|
||||
})
|
||||
.then(function () {
|
||||
t.end()
|
||||
}, function (err) {
|
||||
t.notOk(err)
|
||||
})
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'teardown',
|
||||
function (t) {
|
||||
return dbConn.then(function(db) {
|
||||
return db.close()
|
||||
}).then(function() {
|
||||
return dbServer.stop()
|
||||
}).then(function () {
|
||||
process.env.VERIFICATION_REMINDER_RATE = reminderConfig
|
||||
t.end()
|
||||
})
|
||||
}
|
||||
)
|
||||
after(() => {
|
||||
return TestServer.stop(dbServer)
|
||||
.then(() => {
|
||||
return db.close()
|
||||
})
|
||||
.then(function () {
|
||||
process.env.VERIFICATION_REMINDER_RATE = reminderConfig
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
@ -2,17 +2,16 @@
|
|||
* 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/. */
|
||||
|
||||
var test = require('tap').test
|
||||
'use strict'
|
||||
|
||||
const assert = require('insist')
|
||||
var TestServer = require('../test_server')
|
||||
const Client = require('../client')()
|
||||
var createDBServer = require('fxa-auth-db-mysql')
|
||||
var log = { trace: console.log } // eslint-disable-line no-console
|
||||
var log = { trace() {} }
|
||||
|
||||
var config = require('../../config').getProperties()
|
||||
|
||||
process.env.VERIFIER_VERSION = '0'
|
||||
process.env.SIGNIN_CONFIRMATION_ENABLED = false
|
||||
|
||||
var Token = require('../../lib/tokens')(log)
|
||||
var DB = require('../../lib/db')(
|
||||
config,
|
||||
|
@ -25,107 +24,121 @@ var DB = require('../../lib/db')(
|
|||
Token.PasswordChangeToken
|
||||
)
|
||||
|
||||
createDBServer().then(
|
||||
function (db_server) {
|
||||
db_server.listen(config.httpdb.url.split(':')[2])
|
||||
db_server.on('error', function () {})
|
||||
describe('remote verifier upgrade', function() {
|
||||
this.timeout(30000)
|
||||
|
||||
var email = Math.random() + '@example.com'
|
||||
var password = 'ok'
|
||||
var uid = null
|
||||
|
||||
test(
|
||||
'upgrading verifierVersion upgrades the account on password change',
|
||||
function (t) {
|
||||
return TestServer.start(config)
|
||||
.then(
|
||||
function main(server) {
|
||||
return Client.create(config.publicUrl, email, password, { preVerified: true, keys: true })
|
||||
.then(
|
||||
function (c) {
|
||||
uid = Buffer(c.uid, 'hex')
|
||||
return server.stop()
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
return DB.connect(config[config.db.backend])
|
||||
.then(
|
||||
function (db) {
|
||||
return db.account(uid)
|
||||
.then(
|
||||
function (account) {
|
||||
t.equal(account.verifierVersion, 0, 'wrong version')
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
return db.close()
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
process.env.VERIFIER_VERSION = '1'
|
||||
return TestServer.start(config)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (server) {
|
||||
var client
|
||||
return Client.login(config.publicUrl, email, password, server.mailbox)
|
||||
.then(
|
||||
function (x) {
|
||||
client = x
|
||||
return client.keys()
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
return client.changePassword(password)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
return server.stop()
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
return DB.connect(config[config.db.backend])
|
||||
.then(
|
||||
function (db) {
|
||||
return db.account(uid)
|
||||
.then(
|
||||
function (account) {
|
||||
t.equal(account.verifierVersion, 1, 'wrong upgrade version')
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
return db.close()
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
try {
|
||||
db_server.close()
|
||||
} catch (e) {
|
||||
// This connection may already be dead if a real mysql server is
|
||||
// already bound to :8000.
|
||||
}
|
||||
}
|
||||
)
|
||||
})
|
||||
before(() => {
|
||||
process.env.VERIFIER_VERSION = '0'
|
||||
process.env.SIGNIN_CONFIRMATION_ENABLED = false
|
||||
})
|
||||
|
||||
it(
|
||||
'upgrading verifierVersion upgrades the account on password change',
|
||||
() => {
|
||||
return createDBServer().then(function (db_server) {
|
||||
db_server.listen(config.httpdb.url.split(':')[2])
|
||||
db_server.on('error', function () {})
|
||||
|
||||
var email = Math.random() + '@example.com'
|
||||
var password = 'ok'
|
||||
var uid = null
|
||||
|
||||
return TestServer.start(config)
|
||||
.then(
|
||||
function main(server) {
|
||||
return Client.create(config.publicUrl, email, password, { preVerified: true, keys: true })
|
||||
.then(
|
||||
function (c) {
|
||||
uid = Buffer(c.uid, 'hex')
|
||||
return server.stop()
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
return DB.connect(config[config.db.backend])
|
||||
.then(
|
||||
function (db) {
|
||||
return db.account(uid)
|
||||
.then(
|
||||
function (account) {
|
||||
assert.equal(account.verifierVersion, 0, 'wrong version')
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
return db.close()
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
process.env.VERIFIER_VERSION = '1'
|
||||
return TestServer.start(config)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (server) {
|
||||
var client
|
||||
return Client.login(config.publicUrl, email, password, server.mailbox)
|
||||
.then(
|
||||
function (x) {
|
||||
client = x
|
||||
return client.keys()
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
return client.changePassword(password)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
return server.stop()
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
return DB.connect(config[config.db.backend])
|
||||
.then(
|
||||
function (db) {
|
||||
return db.account(uid)
|
||||
.then(
|
||||
function (account) {
|
||||
assert.equal(account.verifierVersion, 1, 'wrong upgrade version')
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
return db.close()
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
try {
|
||||
db_server.close()
|
||||
} catch (e) {
|
||||
// This connection may already be dead if a real mysql server is
|
||||
// already bound to :8000.
|
||||
}
|
||||
}
|
||||
)
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
after(() => {
|
||||
delete process.env.VERIFIER_VERSION
|
||||
delete process.env.SIGNIN_CONFIRMATION_ENABLED
|
||||
})
|
||||
})
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
* 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 cp = require('child_process')
|
||||
var crypto = require('crypto')
|
||||
var P = require('../lib/promise')
|
||||
|
@ -9,14 +11,20 @@ var request = require('request')
|
|||
var mailbox = require('./mailbox')
|
||||
var createDBServer = require('fxa-auth-db-mysql')
|
||||
|
||||
let currentServer
|
||||
|
||||
/* eslint-disable no-console */
|
||||
function TestServer(config, printLogs) {
|
||||
this.printLogs = printLogs === false ? false : true
|
||||
currentServer = this
|
||||
if (printLogs === undefined) {
|
||||
printLogs = (process.env.REMOTE_TEST_LOGS === 'true')
|
||||
}
|
||||
this.printLogs = printLogs
|
||||
this.config = config
|
||||
this.server = null
|
||||
this.mail = null
|
||||
this.oauth = null
|
||||
this.mailbox = mailbox(config.smtp.api.host, config.smtp.api.port)
|
||||
this.mailbox = mailbox(config.smtp.api.host, config.smtp.api.port, this.printLogs)
|
||||
}
|
||||
|
||||
function waitLoop(testServer, url, cb) {
|
||||
|
@ -30,30 +38,49 @@ function waitLoop(testServer, url, cb) {
|
|||
return cb(err)
|
||||
}
|
||||
if (!testServer.server) {
|
||||
console.log('starting...')
|
||||
if (testServer.printLogs) {
|
||||
console.log('starting...')
|
||||
}
|
||||
testServer.start()
|
||||
}
|
||||
console.log('waiting...')
|
||||
if (testServer.printLogs) {
|
||||
console.log('waiting...')
|
||||
}
|
||||
return setTimeout(waitLoop.bind(null, testServer, url, cb), 100)
|
||||
} else if (res.statusCode !== 200) {
|
||||
cb(body)
|
||||
}
|
||||
cb()
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
function processKill(p, kid, signal) {
|
||||
return new P((resolve, reject) => {
|
||||
p.on('exit', (code, sig) => {
|
||||
resolve()
|
||||
})
|
||||
p.kill(signal)
|
||||
})
|
||||
}
|
||||
|
||||
TestServer.start = function (config, printLogs) {
|
||||
var d = P.defer()
|
||||
createDBServer().then(
|
||||
function (db) {
|
||||
db.listen(config.httpdb.url.split(':')[2])
|
||||
db.on('error', function () {})
|
||||
var testServer = new TestServer(config, printLogs)
|
||||
testServer.db = db
|
||||
waitLoop(testServer, config.publicUrl, function (err) {
|
||||
return err ? d.reject(err) : d.resolve(testServer)
|
||||
})
|
||||
}
|
||||
)
|
||||
TestServer.stop().then(() => {
|
||||
return createDBServer().then(
|
||||
function (db) {
|
||||
db.listen(config.httpdb.url.split(':')[2])
|
||||
db.on('error', function () {})
|
||||
var testServer = new TestServer(config, printLogs)
|
||||
testServer.db = db
|
||||
waitLoop(testServer, config.publicUrl, function (err) {
|
||||
return err ? d.reject(err) : d.resolve(testServer)
|
||||
})
|
||||
}
|
||||
)
|
||||
}).done(null, err => {
|
||||
d.reject(err)
|
||||
})
|
||||
return d.promise
|
||||
}
|
||||
|
||||
|
@ -101,14 +128,30 @@ TestServer.prototype.start = function () {
|
|||
}
|
||||
}
|
||||
|
||||
TestServer.stop = function (maybeServer) {
|
||||
if (maybeServer) {
|
||||
return maybeServer.stop()
|
||||
} else if (currentServer) {
|
||||
return currentServer.stop()
|
||||
} else {
|
||||
return P.resolve()
|
||||
}
|
||||
}
|
||||
|
||||
TestServer.prototype.stop = function () {
|
||||
currentServer = undefined
|
||||
try { this.db.close() } catch (e) {}
|
||||
if (this.server) {
|
||||
this.server.kill('SIGINT')
|
||||
this.mail.kill()
|
||||
let doomed = [
|
||||
processKill(this.server, 'server', 'SIGINT'),
|
||||
processKill(this.mail, 'mail')
|
||||
]
|
||||
if (this.oauth) {
|
||||
this.oauth.kill()
|
||||
doomed.push(processKill(this.oauth, 'oauth'))
|
||||
}
|
||||
return P.all(doomed)
|
||||
} else {
|
||||
return P.resolve()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче