fixed tests deleted obsolete ones. need moar token tests
This commit is contained in:
Родитель
830833f8a1
Коммит
f59f012e98
|
@ -105,7 +105,7 @@ module.exports = function (
|
|||
|
||||
Heap.prototype.createForgotPasswordToken = function (emailRecord) {
|
||||
log.trace({ op: 'Heap.createForgotPasswordToken', uid: emailRecord && emailRecord.uid })
|
||||
return ForgotPasswordToken.create(emailRecord.uid)
|
||||
return ForgotPasswordToken.create(emailRecord.uid, emailRecord.email)
|
||||
.then(
|
||||
function (forgotPasswordToken) {
|
||||
var account = this.accounts[forgotPasswordToken.uid]
|
||||
|
@ -183,7 +183,7 @@ module.exports = function (
|
|||
log.trace({ op: 'Heap.forgotPasswordToken', id: id })
|
||||
var forgotPasswordToken = this.forgotPasswordTokens[id]
|
||||
if (!forgotPasswordToken) { return P.reject(error.invalidToken()) }
|
||||
var account = this.accounts[sessionToken.uid]
|
||||
var account = this.accounts[forgotPasswordToken.uid]
|
||||
if (!account) { return P.reject(error.unknownAccount()) }
|
||||
forgotPasswordToken.email = account.email
|
||||
return P(forgotPasswordToken)
|
||||
|
@ -205,7 +205,7 @@ module.exports = function (
|
|||
|
||||
// UPDATE
|
||||
|
||||
Heap.prototype.udateForgotPasswordToken = function (forgotPasswordToken) {
|
||||
Heap.prototype.updateForgotPasswordToken = function (forgotPasswordToken) {
|
||||
log.trace({ op: 'Heap.udateForgotPasswordToken', uid: forgotPasswordToken && forgotPasswordToken.uid })
|
||||
return P(true)
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
module.exports = function (log, crypto, uuid, isA, error, db, mailer, config) {
|
||||
module.exports = function (log, crypto, P, uuid, isA, error, db, mailer, config) {
|
||||
|
||||
const HEX_STRING = /^(?:[a-fA-F0-9]{2})+$/
|
||||
|
||||
|
@ -78,16 +78,19 @@ module.exports = function (log, crypto, uuid, isA, error, db, mailer, config) {
|
|||
}
|
||||
)
|
||||
)
|
||||
// .then(
|
||||
// function (account) {
|
||||
// return sendVerifyCode(
|
||||
// account.email,
|
||||
// account.emailCode,
|
||||
// account.uid
|
||||
// )
|
||||
// .then(function () { return account })
|
||||
// }
|
||||
// )
|
||||
.then(
|
||||
function (account) {
|
||||
if (account.verified) {
|
||||
return P(account)
|
||||
}
|
||||
return sendVerifyCode(
|
||||
account.email,
|
||||
account.emailCode,
|
||||
account.uid
|
||||
)
|
||||
.then(function () { return account })
|
||||
}
|
||||
)
|
||||
.done(
|
||||
function (account) {
|
||||
request.reply(
|
||||
|
@ -247,7 +250,7 @@ module.exports = function (log, crypto, uuid, isA, error, db, mailer, config) {
|
|||
db.account(uid)
|
||||
.then(
|
||||
function (account) {
|
||||
if (code !== account.code) {
|
||||
if (code !== account.emailCode) {
|
||||
throw error.invalidVerificationCode()
|
||||
}
|
||||
return db.verifyEmail(account)
|
||||
|
|
|
@ -7,15 +7,7 @@ module.exports = function (log, isA, error, db, Token) {
|
|||
const HEX_STRING = /^(?:[a-fA-F0-9]{2})+$/
|
||||
|
||||
function clientData(srpToken) {
|
||||
return {
|
||||
srpToken: srpToken.id,
|
||||
passwordStretching: srpToken.passwordStretching,
|
||||
srp: {
|
||||
type: 'SRP-6a/SHA256/2048/v1',
|
||||
salt: srpToken.s,
|
||||
B: srpToken.B.toString('hex')
|
||||
}
|
||||
}
|
||||
return srpToken.clientData()
|
||||
}
|
||||
|
||||
function bundleAuth(K, authToken) {
|
||||
|
|
|
@ -23,7 +23,7 @@ module.exports = function (
|
|||
var auth = require('./auth')(log, isA, error, db, Token)
|
||||
var defaults = require('./defaults')(log, P, db)
|
||||
var idp = require('./idp')(log, serverPublicKey)
|
||||
var account = require('./account')(log, crypto, uuid, isA, error, db, mailer, config)
|
||||
var account = require('./account')(log, crypto, P, uuid, isA, error, db, mailer, config)
|
||||
var password = require('./password')(log, isA, error, db, mailer)
|
||||
var session = require('./session')(log, isA, error, db)
|
||||
var sign = require('./sign')(log, isA, error, signer, config.domain)
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
module.exports = function (log, isA, error, db, mailer) {
|
||||
|
||||
const HEX_STRING = /^(?:[a-fA-F0-9]{2})+$/
|
||||
const FPT_LIFETIME = 1000 * 60 * 15
|
||||
|
||||
function bundleAccountReset(authToken, keyFetchToken, accountResetToken) {
|
||||
return authToken.bundleKeys('password/change', keyFetchToken, accountResetToken)
|
||||
|
@ -14,21 +13,18 @@ module.exports = function (log, isA, error, db, mailer) {
|
|||
function sendRecoveryCode(forgotPasswordToken) {
|
||||
log.trace({ op: 'sendRecoveryCode', id: forgotPasswordToken.id })
|
||||
return mailer.sendRecoveryCode(
|
||||
Buffer(forgotPasswordToken.email, 'hex').toString(),
|
||||
Buffer(forgotPasswordToken.email, 'hex').toString('utf8'),
|
||||
forgotPasswordToken.passcode
|
||||
)
|
||||
.then(function () { return forgotPasswordToken })
|
||||
}
|
||||
|
||||
function ttl(forgotPasswordToken) {
|
||||
return Math.max(
|
||||
Math.ceil((FPT_LIFETIME - (Date.now() - forgotPasswordToken.created)) / 1000),
|
||||
0
|
||||
)
|
||||
return forgotPasswordToken.ttl()
|
||||
}
|
||||
|
||||
function failVerifyAttempt(forgotPasswordToken) {
|
||||
forgotPasswordToken.tries--
|
||||
return (forgotPasswordToken.tries < 1) ?
|
||||
return (forgotPasswordToken.failAttempt()) ?
|
||||
db.deleteForgotPasswordToken(forgotPasswordToken) :
|
||||
db.updateForgotPasswordToken(forgotPasswordToken)
|
||||
}
|
||||
|
@ -90,7 +86,7 @@ module.exports = function (log, isA, error, db, mailer) {
|
|||
}
|
||||
)
|
||||
.done(
|
||||
function () {
|
||||
function (forgotPasswordToken) {
|
||||
request.reply(
|
||||
{
|
||||
forgotPasswordToken: forgotPasswordToken.data,
|
||||
|
@ -179,7 +175,7 @@ module.exports = function (log, isA, error, db, mailer) {
|
|||
log.begin('Password.forgotVerify', request)
|
||||
var forgotPasswordToken = request.auth.credentials
|
||||
var code = +(request.payload.code)
|
||||
if (forgotPasswordToken.code === code && ttl(forgotPasswordToken) > 0) {
|
||||
if (forgotPasswordToken.passcode === code && ttl(forgotPasswordToken) > 0) {
|
||||
db.forgotPasswordVerified(forgotPasswordToken)
|
||||
.done(
|
||||
function (accountResetToken) {
|
||||
|
|
|
@ -1,15 +1,9 @@
|
|||
var test = require('tap').test
|
||||
var crypto = require('crypto')
|
||||
var P = require('p-promise')
|
||||
var config = require('../../config').root()
|
||||
var log = { trace: function() {} }
|
||||
|
||||
var dbs = require('../../kv')(config, log)
|
||||
|
||||
var mailer = {}
|
||||
|
||||
var models = require('../../models')(log, config, dbs, mailer)
|
||||
var AccountResetToken = models.tokens.AccountResetToken
|
||||
var tokens = require('../../tokens')(log)
|
||||
var AccountResetToken = tokens.AccountResetToken
|
||||
|
||||
test(
|
||||
'bundle / unbundle works',
|
||||
|
@ -35,12 +29,3 @@ test(
|
|||
.done(end, end)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'teardown',
|
||||
function (t) {
|
||||
dbs.cache.close()
|
||||
dbs.store.close()
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
|
|
|
@ -1,540 +0,0 @@
|
|||
var test = require('tap').test
|
||||
var P = require('p-promise')
|
||||
var config = require('../../config').root()
|
||||
var log = { trace: function() {} }
|
||||
|
||||
var dbs = require('../../kv')(config, log)
|
||||
|
||||
var mailer = {
|
||||
sendVerifyCode: function () { return P(null) }
|
||||
}
|
||||
|
||||
var models = require('../../models')(log, config, dbs, mailer)
|
||||
var Account = models.Account
|
||||
var RecoveryEmail = models.RecoveryEmail
|
||||
var SessionToken = models.tokens.SessionToken
|
||||
var AccountResetToken = models.tokens.AccountResetToken
|
||||
|
||||
var a = {
|
||||
uid: 'xxx',
|
||||
email: Buffer('somebody@example.com').toString('hex'),
|
||||
srp: {
|
||||
verifier: 'BAD1',
|
||||
salt: 'BAD2'
|
||||
},
|
||||
kA: 'BAD3',
|
||||
wrapKb: 'BAD4'
|
||||
}
|
||||
|
||||
test(
|
||||
'Account.principal uses the given uid and adds the domain',
|
||||
function (t) {
|
||||
t.equal(Account.principal('xyz'), 'xyz@' + config.domain)
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'Account.create adds a new account',
|
||||
function (t) {
|
||||
Account.create(a)
|
||||
.then(Account.get.bind(null, a.uid))
|
||||
.then(
|
||||
function (account) {
|
||||
t.equal(account.email, a.email)
|
||||
}
|
||||
)
|
||||
.then(Account.del.bind(null, a.uid))
|
||||
.done(
|
||||
function () { t.end() },
|
||||
function (err) { t.fail(err); t.end() })
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'Account.create adds a primary recovery method',
|
||||
function (t) {
|
||||
var code = null
|
||||
Account.create(a)
|
||||
.then(Account.get.bind(null, a.uid))
|
||||
.then(
|
||||
function (account) {
|
||||
code = Object.keys(account.recoveryEmailCodes)[0]
|
||||
t.ok(code)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
return RecoveryEmail.get(a.uid, code)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (rm) {
|
||||
t.equal(rm.uid, a.uid)
|
||||
}
|
||||
)
|
||||
.then(Account.del.bind(null, a.uid))
|
||||
.done(
|
||||
function () { t.end() },
|
||||
function (err) { t.fail(err); t.end() })
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'Account.create returns an error if the account exists',
|
||||
function (t) {
|
||||
Account.create(a)
|
||||
.then(Account.create.bind(null, a))
|
||||
.then(
|
||||
function () {
|
||||
t.fail('should not have created an account')
|
||||
},
|
||||
function (err) {
|
||||
t.equal(err.errno, 101)
|
||||
t.equal(err.message, 'Account already exists')
|
||||
}
|
||||
)
|
||||
.then(Account.del.bind(null, a.uid))
|
||||
.done(
|
||||
function () { t.end() },
|
||||
function (err) { t.fail(err); t.end() })
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'Account.get of an invalid uid returns null',
|
||||
function (t) {
|
||||
Account.get('foobar')
|
||||
.done(
|
||||
function (x) {
|
||||
t.equal(x, null)
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'Account.getId returns the uid given an email',
|
||||
function (t) {
|
||||
Account.create(a)
|
||||
.then(Account.getId.bind(null, a.email))
|
||||
.then(
|
||||
function (id) {
|
||||
t.equal(id, a.uid)
|
||||
}
|
||||
)
|
||||
.then(Account.del.bind(null, a.uid))
|
||||
.done(
|
||||
function () { t.end() },
|
||||
function (err) { t.fail(err); t.end() })
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'Account.exists returns false if the email is not in use',
|
||||
function (t) {
|
||||
Account.exists(Buffer('nobody@example.com').toString('hex')).done(
|
||||
function (exists) {
|
||||
t.equal(exists, false)
|
||||
t.end()
|
||||
},
|
||||
function (err) { t.fail(err); t.end() }
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'Account.exists returns true if the email is in use',
|
||||
function (t) {
|
||||
Account.create(a)
|
||||
.then(Account.exists.bind(null, a.email))
|
||||
.then(
|
||||
function (exists) {
|
||||
t.equal(exists, true)
|
||||
}
|
||||
)
|
||||
.then(Account.del.bind(null, a.uid))
|
||||
.done(
|
||||
function () { t.end() },
|
||||
function (err) { t.fail(err); t.end() }
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'Account.del deletes the account with the given uid',
|
||||
function (t) {
|
||||
Account.create(a)
|
||||
.then(Account.exists.bind(null, a.email))
|
||||
.then(
|
||||
function (exists) {
|
||||
t.equal(exists, true)
|
||||
}
|
||||
)
|
||||
.then(Account.del.bind(null, a.uid))
|
||||
.then(Account.get.bind(null, a.uid))
|
||||
.done(
|
||||
function (account) {
|
||||
t.equal(account, null)
|
||||
t.end()
|
||||
},
|
||||
function (err) {
|
||||
t.fail(err)
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'Account.del deletes all data related to the account',
|
||||
function (t) {
|
||||
var account = null
|
||||
var session = null
|
||||
var reset = null
|
||||
// This test is only valid for memory db
|
||||
if (!dbs.store.kv.data) {
|
||||
return t.end()
|
||||
}
|
||||
t.equal(Object.keys(dbs.store.kv.data).length, 0)
|
||||
Account.create(a)
|
||||
.then(
|
||||
function (a) {
|
||||
account = a
|
||||
}
|
||||
)
|
||||
.then(SessionToken.create.bind(null, a.uid))
|
||||
.then(
|
||||
function (t) {
|
||||
session = t
|
||||
return account.addSessionToken(session)
|
||||
}
|
||||
)
|
||||
.then(AccountResetToken.create.bind(null, a.uid))
|
||||
.then(
|
||||
function (t) {
|
||||
reset = t
|
||||
return account.setResetToken(reset)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
// 5: uid, user, recovery, reset, session
|
||||
t.equal(Object.keys(dbs.store.kv.data).length, 5)
|
||||
}
|
||||
)
|
||||
.then(Account.del.bind(null, a.uid))
|
||||
.done(
|
||||
function () {
|
||||
t.equal(Object.keys(dbs.store.kv.data).length, 0)
|
||||
t.end()
|
||||
},
|
||||
function (err) {
|
||||
t.fail(err)
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'Account.del of an invalid uid returns null',
|
||||
function (t) {
|
||||
Account.del('foobar')
|
||||
.done(
|
||||
function (x) {
|
||||
t.equal(x, null)
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'Account.verify sets verified to true when the recovery method is primary',
|
||||
function (t) {
|
||||
Account.create(a)
|
||||
.then(
|
||||
function (account) {
|
||||
var code = Object.keys(account.recoveryEmailCodes)[0]
|
||||
return RecoveryEmail.get(account.uid, code)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (x) {
|
||||
x.verified = true
|
||||
return Account.verify(x)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (account) {
|
||||
t.equal(account.verified, true)
|
||||
}
|
||||
)
|
||||
.then(Account.del.bind(null, a.uid))
|
||||
.done(
|
||||
function () { t.end() },
|
||||
function (err) { t.fail(err); t.end() }
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'Account.verify does not set verified true if recovery method is not verified',
|
||||
function (t) {
|
||||
Account.create(a)
|
||||
.then(
|
||||
function (account) {
|
||||
var code = Object.keys(account.recoveryEmailCodes)[0]
|
||||
return RecoveryEmail.get(account.uid, code)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (x) {
|
||||
return Account.verify(x)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (account) {
|
||||
t.equal(account.verified, false)
|
||||
}
|
||||
)
|
||||
.then(Account.del.bind(null, a.uid))
|
||||
.done(
|
||||
function () { t.end() },
|
||||
function (err) { t.fail(err); t.end() }
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'account.setResetToken deletes existing token',
|
||||
function (t) {
|
||||
var account = null
|
||||
var token1 = null
|
||||
var token2 = null
|
||||
AccountResetToken.create(a.uid)
|
||||
.then(
|
||||
function (x) {
|
||||
token1 = x
|
||||
}
|
||||
)
|
||||
.then(Account.create.bind(null, a))
|
||||
.then(
|
||||
function (x) {
|
||||
account = x
|
||||
return account.setResetToken(token1)
|
||||
}
|
||||
)
|
||||
.then(AccountResetToken.create.bind(null, a.uid))
|
||||
.then(
|
||||
function (x) {
|
||||
t.equal(account.resetTokenId, token1.id)
|
||||
token2 = x
|
||||
return account.setResetToken(token2)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
t.equal(account.resetTokenId, token2.id)
|
||||
return AccountResetToken.get(token1.id)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (x) {
|
||||
t.equal(x, null)
|
||||
}
|
||||
)
|
||||
.then(Account.del.bind(null, a.uid))
|
||||
.done(
|
||||
function () { t.end() },
|
||||
function (err) { t.fail(err); t.end() }
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'Account.getByEmail works',
|
||||
function (t) {
|
||||
Account.create(a)
|
||||
.then(Account.getByEmail.bind(null, a.email))
|
||||
.then(
|
||||
function (account) {
|
||||
t.equal(account.email, a.email)
|
||||
}
|
||||
)
|
||||
.then(Account.del.bind(null, a.uid))
|
||||
.done(
|
||||
function () { t.end() },
|
||||
function (err) { t.fail(err); t.end() }
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'account.addSessionToken works',
|
||||
function (t) {
|
||||
var account = null
|
||||
var token = null
|
||||
Account.create(a)
|
||||
.then(
|
||||
function (x) {
|
||||
account = x
|
||||
return SessionToken.create(x.uid)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (t) {
|
||||
token = t
|
||||
return account.addSessionToken(t)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (x) {
|
||||
t.equal(x.sessionTokenIds[token.id], true)
|
||||
}
|
||||
)
|
||||
.then(Account.del.bind(null, a.uid))
|
||||
.done(
|
||||
function () { t.end() },
|
||||
function (err) { t.fail(err); t.end() }
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'account.recoveryEmails returns an array of RecoveryEmail objects',
|
||||
function (t) {
|
||||
Account.create(a)
|
||||
.then(
|
||||
function (account) {
|
||||
return account.recoveryEmails()
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (rms) {
|
||||
t.equal(rms.length, 1)
|
||||
t.equal(rms[0] instanceof RecoveryEmail, true)
|
||||
}
|
||||
)
|
||||
.then(Account.del.bind(null, a.uid))
|
||||
.done(
|
||||
function () { t.end() },
|
||||
function (err) { t.fail(err); t.end() }
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'account.reset changes wrapKb and verifier',
|
||||
function (t) {
|
||||
var form = {
|
||||
wrapKb: 'DEADBEEF',
|
||||
srp: {
|
||||
type: 'SRP-6a/SHA256/2048/v1',
|
||||
verifier: 'FEEDFACE',
|
||||
salt: '12345678'
|
||||
},
|
||||
passwordStretching: {
|
||||
stuff: true
|
||||
}
|
||||
}
|
||||
Account.create(a)
|
||||
.then(
|
||||
function (account) {
|
||||
return account.reset(form)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (account) {
|
||||
t.equal(account.wrapKb, form.wrapKb)
|
||||
t.equal(account.srp.verifier, form.srp.verifier)
|
||||
}
|
||||
)
|
||||
.then(Account.del.bind(null, a.uid))
|
||||
.done(
|
||||
function () { t.end() },
|
||||
function (err) { t.fail(err); t.end() }
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'account.reset deletes all tokens',
|
||||
function (t) {
|
||||
var account = null
|
||||
var session = null
|
||||
var reset = null
|
||||
var form = {
|
||||
wrapKb: 'DEADBEEF',
|
||||
srp: {
|
||||
type: 'SRP-6a/SHA256/2048/v1',
|
||||
verifier: 'FEEDFACE',
|
||||
salt: '12345678'
|
||||
},
|
||||
passwordStretching: {
|
||||
stuff: true
|
||||
}
|
||||
}
|
||||
Account.create(a)
|
||||
.then(
|
||||
function (a) {
|
||||
account = a
|
||||
}
|
||||
)
|
||||
.then(SessionToken.create.bind(null, a.uid))
|
||||
.then(
|
||||
function (x) {
|
||||
session = x
|
||||
return account.addSessionToken(session)
|
||||
}
|
||||
)
|
||||
.then(AccountResetToken.create.bind(null, a.uid))
|
||||
.then(
|
||||
function (x) {
|
||||
reset = x
|
||||
return account.setResetToken(reset)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
return account.reset(form)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
return AccountResetToken.get(reset.id)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (x) {
|
||||
t.equal(x, null)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
return SessionToken.get(session.id)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (x) {
|
||||
t.equal(x, null)
|
||||
}
|
||||
)
|
||||
.then(Account.del.bind(null, a.uid))
|
||||
.done(
|
||||
function () { t.end() },
|
||||
function (err) { t.fail(err); t.end() }
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'teardown',
|
||||
function (t) {
|
||||
dbs.cache.close()
|
||||
dbs.store.close()
|
||||
t.end()
|
||||
}
|
||||
)
|
|
@ -1,16 +1,9 @@
|
|||
var test = require('tap').test
|
||||
var crypto = require('crypto')
|
||||
var P = require('p-promise')
|
||||
var config = require('../../config').root()
|
||||
var log = { trace: function() {} }
|
||||
var dbs = require('../../kv')(config, log)
|
||||
|
||||
var mailer = {
|
||||
sendVerifyCode: function () { return P(null) }
|
||||
}
|
||||
|
||||
var models = require('../../models')(log, config, dbs, mailer)
|
||||
var AuthToken = models.tokens.AuthToken
|
||||
var tokens = require('../../tokens')(log)
|
||||
var AuthToken = tokens.AuthToken
|
||||
|
||||
test(
|
||||
'bundle / unbundle works',
|
||||
|
@ -36,12 +29,3 @@ test(
|
|||
.done(end, end)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'teardown',
|
||||
function (t) {
|
||||
dbs.cache.close()
|
||||
dbs.store.close()
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
|
|
|
@ -1,347 +0,0 @@
|
|||
var test = require('tap').test
|
||||
var inherits = require('util').inherits
|
||||
var crypto = require('crypto')
|
||||
var P = require('p-promise')
|
||||
var hkdf = require('../../hkdf')
|
||||
var config = require('../../config').root()
|
||||
var log = { trace: function() {} }
|
||||
var dbs = require('../../kv')(config, log)
|
||||
|
||||
function fakeCrypto(bytes) {
|
||||
return {
|
||||
randomBytes: function (size, cb) {
|
||||
cb(null, bytes)
|
||||
},
|
||||
createHmac: crypto.createHmac
|
||||
}
|
||||
}
|
||||
|
||||
// Test vectors
|
||||
// https://wiki.mozilla.org/Identity/AttachedServices/KeyServerProtocol#Test_Vectors
|
||||
|
||||
var useSession = {
|
||||
sessionToken: Buffer(
|
||||
'8081828384858687' +
|
||||
'88898a8b8c8d8e8f' +
|
||||
'9091929394959697' +
|
||||
'98999a9b9c9d9e9f',
|
||||
'hex'),
|
||||
tokenId:
|
||||
'31217a79ba0d62e9' +
|
||||
'c6e33cee374f0879' +
|
||||
'3171b2a39d14cc8f' +
|
||||
'f680540b5028d069',
|
||||
key:
|
||||
'6c87cfeba3a216d4' +
|
||||
'b1829e62478500ac' +
|
||||
'd2953158130cae0b' +
|
||||
'2c92ef8a2ea6089a'
|
||||
}
|
||||
|
||||
var accountKeys = {
|
||||
keyFetchToken: Buffer(
|
||||
'6061626364656667' +
|
||||
'68696a6b6c6d6e6f' +
|
||||
'7071727374757677' +
|
||||
'78797a7b7c7d7e7f',
|
||||
'hex'),
|
||||
tokenId:
|
||||
'7f784ba2bd89097f' +
|
||||
'743632d21316d987' +
|
||||
'38e146a9e7123a98' +
|
||||
'39a87c96b3bb99cb',
|
||||
key:
|
||||
'6dedf96237deb067' +
|
||||
'f4232af00b3c7148' +
|
||||
'e815635c147a7215' +
|
||||
'a64906bdb2823471',
|
||||
hmacKey:
|
||||
'ca24f43285899356' +
|
||||
'5d698251dbe6c7f7' +
|
||||
'da5f9ad003835a41' +
|
||||
'edf7c813124c5499',
|
||||
xorKey:
|
||||
'9dff4835ffdbacd6' +
|
||||
'5e27f5dde15a1f18' +
|
||||
'994ff75f70bab7db' +
|
||||
'b5c4c9771e657704' +
|
||||
'4666cf97273e2a96' +
|
||||
'02993f5b1e258d8f' +
|
||||
'3b4d837e505f8458' +
|
||||
'41a986882ef36631',
|
||||
kA:
|
||||
'2021222324252627' +
|
||||
'28292a2b2c2d2e2f' +
|
||||
'3031323334353637' +
|
||||
'38393a3b3c3d3e3f',
|
||||
wrapKb:
|
||||
'4041424344454647' +
|
||||
'48494a4b4c4d4e4f' +
|
||||
'5051525354555657' +
|
||||
'58595a5b5c5d5e5f',
|
||||
ciphertext:
|
||||
'bdde6a16dbfe8af1' +
|
||||
'760edff6cd773137' +
|
||||
'a97ec56c448f81ec' +
|
||||
'8dfdf34c2258493b' +
|
||||
'06278dd4637b6cd1' +
|
||||
'4ad075105268c3c0' +
|
||||
'6b1cd12d040ad20f' +
|
||||
'19f0dcd372ae386e',
|
||||
hmac:
|
||||
'6f7972302f00dfe8' +
|
||||
'2d5a8ce0553b0ffe' +
|
||||
'80e073078d4f30f9' +
|
||||
'0c48537f8ca92222'
|
||||
}
|
||||
|
||||
var sessionAuth = {
|
||||
K: Buffer(
|
||||
'e68fd0112bfa31dc' +
|
||||
'ffc8e9c96a1cbadb' +
|
||||
'4c3145978ff35c73' +
|
||||
'e5bf8d30bbc7499a',
|
||||
'hex'),
|
||||
hmacKey:
|
||||
'e252adb2c217c2a1' +
|
||||
'02b4bd3f71294430' +
|
||||
'e367145b107d1e8d' +
|
||||
'e35684bbdf13f1e9',
|
||||
xorKey:
|
||||
'75a6ff483b6afe43' +
|
||||
'f80f95b5e2061ce3' +
|
||||
'961996ec4c2eeb9c' +
|
||||
'350ebfabdd766549' +
|
||||
'342a0b2d910c9f5b' +
|
||||
'b2dee20f2af61849' +
|
||||
'a4a20ff16ee4a25f' +
|
||||
'cb6e832effa77f59',
|
||||
keyFetchToken:
|
||||
'6061626364656667' +
|
||||
'68696a6b6c6d6e6f' +
|
||||
'7071727374757677' +
|
||||
'78797a7b7c7d7e7f',
|
||||
sessionToken:
|
||||
'8081828384858687' +
|
||||
'88898a8b8c8d8e8f' +
|
||||
'9091929394959697' +
|
||||
'98999a9b9c9d9e9f',
|
||||
ciphertext:
|
||||
'15c79d2b5f0f9824' +
|
||||
'9066ffde8e6b728c' +
|
||||
'e668e49f385b9deb' +
|
||||
'4d77c5d0a10b1b36' +
|
||||
'b4ab89ae158919dc' +
|
||||
'3a576884a67b96c6' +
|
||||
'34339d62fa7134c8' +
|
||||
'53f719b5633ae1c6',
|
||||
hmac:
|
||||
'b27381d49ca93e61' +
|
||||
'3247c49a0cd0c901' +
|
||||
'0332f186bb07c23f' +
|
||||
'33ad176916d607c4'
|
||||
}
|
||||
|
||||
var passwordChange = {
|
||||
xorKey:
|
||||
'aaf041fd5f2c23e9' +
|
||||
'0c3636f93a170ef0' +
|
||||
'60456d7edf7678df' +
|
||||
'2d5297797626a07d' +
|
||||
'a96803cfe941a0c8' +
|
||||
'ea140e371871ea20' +
|
||||
'1ec38ad41a233b8e' +
|
||||
'39ff1bedf6ce0aec',
|
||||
hmacKey:
|
||||
'81a03345184a09fd' +
|
||||
'9aef6ec1a1ddf80f' +
|
||||
'c4e3d354bf8af42f' +
|
||||
'a4b32696384cb9b9',
|
||||
ciphertext:
|
||||
'ca91239e3b49458e' +
|
||||
'645f5c92567a609f' +
|
||||
'10341f0dab030ea8' +
|
||||
'552bed020a5bde02' +
|
||||
'09c9a16c4de4066f' +
|
||||
'42bda49cb4dc448f' +
|
||||
'ae723867ae968d39' +
|
||||
'8146a1564a73b453',
|
||||
hmac:
|
||||
'442223ac3a149d00' +
|
||||
'cc319a73189b8572' +
|
||||
'e323084b662f74a5' +
|
||||
'b5d1f32925ea50de'
|
||||
}
|
||||
|
||||
var accountReset = {
|
||||
accountResetToken: Buffer(
|
||||
'a0a1a2a3a4a5a6a7' +
|
||||
'a8a9aaabacadaeaf' +
|
||||
'b0b1b2b3b4b5b6b7' +
|
||||
'b8b9babbbcbdbebf',
|
||||
'hex'),
|
||||
tokenId:
|
||||
'b421fa511242b33f' +
|
||||
'feebdef63089242f' +
|
||||
'fde11c811fd5474d' +
|
||||
'b888ade257861e23',
|
||||
key:
|
||||
'da5fb4a8e1a7fc77' +
|
||||
'dfcf43be71455f69' +
|
||||
'f6776e24f369e253' +
|
||||
'ff1f541fbb5e9bc3',
|
||||
xorKey:
|
||||
'def723a6ece08e37' + 'd5b598a25a031eda' +
|
||||
'acad44ef5186fef0' + '2a76417dc245379b' +
|
||||
'1c5825ac741dd558' + '632d933cc9455875' +
|
||||
'f099cbe46d926ace' + '201616119d47f115' +
|
||||
'ab7623e63c29c518' + '187a6139570f8457' +
|
||||
'03c84be42720bbb6' + '6097f90172a7ebf4' +
|
||||
'0a44f140828f0cd4' + '16028e67e0ef3b4c' +
|
||||
'f6e0b43055bd008a' + '1305b2b5f579b0f0' +
|
||||
'ca91d70e28265713' + 'b4d2dc5197e64dec' +
|
||||
'f0e6ee2b8acdef73' + 'ea1951f7dea374cf' +
|
||||
'2f56ac2a76f5f1e1' + '2ba46852bf6d315e' +
|
||||
'2e9419c8d4d43676' + '168044e45862c3e4' +
|
||||
'3e4a390b00950870' + '953f36112d697b43' +
|
||||
'6fd661567ca29c7e' + '68fea229b016cdad' +
|
||||
'c19bf3430a0b52c7' + 'cdd232e774c10882' +
|
||||
'507bd85a3b0c14fe' + '795367422374d774' +
|
||||
'dfa43df9f91d723d' + '4480e2d2f0776794' +
|
||||
'67481cab9c835602' + '69fa7f3086efc88e',
|
||||
plaintext:
|
||||
'4041424344454647' + '48494a4b4c4d4e4f' +
|
||||
'5051525354555657' + '58595a5b5c5d5e5f' +
|
||||
'1111111111111111' + '1111111111111111' +
|
||||
'1111111111111111' + '1111111111111111' +
|
||||
'1111111111111111' + '1111111111111111' +
|
||||
'1111111111111111' + '1111111111111111' +
|
||||
'1111111111111111' + '1111111111111111' +
|
||||
'1111111111111111' + '1111111111111111' +
|
||||
'1111111111111111' + '1111111111111111' +
|
||||
'1111111111111111' + '1111111111111111' +
|
||||
'1111111111111111' + '1111111111111111' +
|
||||
'1111111111111111' + '1111111111111111' +
|
||||
'1111111111111111' + '1111111111111111' +
|
||||
'1111111111111111' + '1111111111111111' +
|
||||
'1111111111111111' + '1111111111111111' +
|
||||
'1111111111111111' + '1111111111111111' +
|
||||
'1111111111111111' + '1111111111111111' +
|
||||
'1111111111111111' + '1111111111111111',
|
||||
ciphertext:
|
||||
'9eb661e5a8a5c870' + '9dfcd2e9164e5095' +
|
||||
'fcfc16bc05d3a8a7' + '722f1b269e1869c4' +
|
||||
'0d4934bd650cc449' + '723c822dd8544964' +
|
||||
'e188daf57c837bdf' + '310707008c56e004' +
|
||||
'ba6732f72d38d409' + '096b7028461e9546' +
|
||||
'12d95af53631aaa7' + '7186e81063b6fae5' +
|
||||
'1b55e051939e1dc5' + '07139f76f1fe2a5d' +
|
||||
'e7f1a52144ac119b' + '0214a3a4e468a1e1' +
|
||||
'db80c61f39374602' + 'a5c3cd4086f75cfd' +
|
||||
'e1f7ff3a9bdcfe62' + 'fb0840e6cfb265de' +
|
||||
'3e47bd3b67e4e0f0' + '3ab57943ae7c204f' +
|
||||
'3f8508d9c5c52767' + '079155f54973d2f5' +
|
||||
'2f5b281a11841961' + '842e27003c786a52' +
|
||||
'7ec770476db38d6f' + '79efb338a107dcbc' +
|
||||
'd08ae2521b1a43d6' + 'dcc323f665d01993' +
|
||||
'416ac94b2a1d05ef' + '684276533265c665' +
|
||||
'ceb52ce8e80c632c' + '5591f3c3e1667685' +
|
||||
'76590dba8d924713' + '78eb6e2197fed99f'
|
||||
}
|
||||
|
||||
var KBundle = require('../../bundle/bundle')(fakeCrypto(accountKeys.keyFetchToken), P, hkdf)
|
||||
var KToken = require('../../models/token')(log, inherits, KBundle)
|
||||
|
||||
var SBundle = require('../../bundle/bundle')(fakeCrypto(useSession.sessionToken), P, hkdf)
|
||||
var SToken = require('../../models/token')(log, inherits, SBundle)
|
||||
|
||||
var RBundle = require('../../bundle/bundle')(fakeCrypto(accountReset.accountResetToken), P, hkdf)
|
||||
var RToken = require('../../models/token')(log, inherits, RBundle)
|
||||
|
||||
var KeyFetchToken = require('../../models/key_fetch_token')(log, inherits, KToken, dbs.store)
|
||||
var AccountResetToken = require('../../models/account_reset_token')(log, inherits, RToken, crypto, dbs.store)
|
||||
var SessionToken = require('../../models/session_token')(log, inherits, SToken, dbs.store)
|
||||
|
||||
var AuthToken = require('../../models/auth_token')(log, inherits, SToken, dbs.store)
|
||||
var tokens = {
|
||||
AuthToken: AuthToken,
|
||||
KeyFetchToken: KeyFetchToken,
|
||||
AccountResetToken: AccountResetToken,
|
||||
SessionToken: SessionToken
|
||||
}
|
||||
|
||||
function FakeAccount() {
|
||||
this.sessionTokenIds = {}
|
||||
this.resetTokenId = null
|
||||
}
|
||||
var account = new FakeAccount()
|
||||
FakeAccount.get = function () { return P(account) }
|
||||
FakeAccount.prototype.addSessionToken = function (t) {
|
||||
this.sessionTokenIds[t.id] = true
|
||||
return P(null)
|
||||
}
|
||||
FakeAccount.prototype.setAuthToken = function (t) {
|
||||
this.authTokenId = t.id
|
||||
return P(null)
|
||||
}
|
||||
|
||||
var AuthBundle = require('../../models/auth_bundle')(log, inherits, require('../../bundle'), FakeAccount, tokens)
|
||||
|
||||
test(
|
||||
'create / get',
|
||||
function (t) {
|
||||
KeyFetchToken.create('xxx')
|
||||
.then(
|
||||
function () {
|
||||
return KeyFetchToken.get(accountKeys.tokenId)
|
||||
}
|
||||
)
|
||||
.done(
|
||||
function (token) {
|
||||
t.equal(token.uid, 'xxx')
|
||||
t.equal(token.id.toString('hex'), accountKeys.tokenId)
|
||||
t.equal(token.key.toString('hex'), accountKeys.key)
|
||||
t.equal(token.hmacKey.toString('hex'), accountKeys.hmacKey)
|
||||
t.equal(token.xorKey.toString('hex'), accountKeys.xorKey)
|
||||
t.end()
|
||||
},
|
||||
function (err) {
|
||||
t.fail(err)
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'/account/keys',
|
||||
function (t) {
|
||||
KeyFetchToken.create('xxx')
|
||||
.done(
|
||||
function (token) {
|
||||
t.equal(token.uid, 'xxx')
|
||||
t.equal(token.id.toString('hex'), accountKeys.tokenId)
|
||||
t.equal(token.key.toString('hex'), accountKeys.key)
|
||||
t.equal(token.hmacKey.toString('hex'), accountKeys.hmacKey)
|
||||
t.equal(token.xorKey.toString('hex'), accountKeys.xorKey)
|
||||
|
||||
var b = token.bundle(accountKeys.kA, accountKeys.wrapKb)
|
||||
t.equal(b.toString('hex'), accountKeys.ciphertext + accountKeys.hmac)
|
||||
t.end()
|
||||
},
|
||||
function (err) {
|
||||
t.fail(err)
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'teardown',
|
||||
function (t) {
|
||||
dbs.cache.close()
|
||||
dbs.store.close()
|
||||
t.end()
|
||||
}
|
||||
)
|
|
@ -1,17 +1,11 @@
|
|||
var test = require('tap').test
|
||||
var crypto = require('crypto')
|
||||
var P = require('p-promise')
|
||||
var config = require('../../config').root()
|
||||
var log = { trace: function() {} }
|
||||
var dbs = require('../../kv')(config, log)
|
||||
|
||||
var sends = 0
|
||||
var mailer = {
|
||||
sendRecoveryCode: function () { sends++; return P(null) }
|
||||
}
|
||||
|
||||
var models = require('../../models')(log, config, dbs, mailer)
|
||||
var ForgotPasswordToken = models.tokens.ForgotPasswordToken
|
||||
var tokens = require('../../tokens')(log)
|
||||
var ForgotPasswordToken = tokens.ForgotPasswordToken
|
||||
|
||||
var email = Buffer('test@example.com').toString('hex')
|
||||
|
||||
|
@ -35,74 +29,20 @@ test(
|
|||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'sendRecoveryCode calls the mailer',
|
||||
function (t) {
|
||||
ForgotPasswordToken.create('xxx', email)
|
||||
.then(
|
||||
function (x) {
|
||||
return x.sendRecoveryCode()
|
||||
}
|
||||
)
|
||||
.done(
|
||||
function () {
|
||||
t.equal(sends, 1, 'mail sent')
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'failAttempt decrements `tries`',
|
||||
function (t) {
|
||||
ForgotPasswordToken.create('xxx', email)
|
||||
.then(
|
||||
.done(
|
||||
function (x) {
|
||||
t.equal(x.tries, 3)
|
||||
return x.failAttempt()
|
||||
}
|
||||
)
|
||||
.done(
|
||||
function (x) {
|
||||
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)
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'failAttempt deletes the token if out of tries',
|
||||
function (t) {
|
||||
var tokenId = null
|
||||
ForgotPasswordToken.create('xxx', email)
|
||||
.then(
|
||||
function (x) {
|
||||
tokenId = x.id
|
||||
x.tries = 1
|
||||
return x.failAttempt()
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
return ForgotPasswordToken.get(tokenId)
|
||||
}
|
||||
)
|
||||
.done(
|
||||
function (x) {
|
||||
t.equal(x, null)
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'teardown',
|
||||
function (t) {
|
||||
dbs.cache.close()
|
||||
dbs.store.close()
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
|
|
|
@ -1,47 +0,0 @@
|
|||
var test = require('tap').test
|
||||
var crypto = require('crypto')
|
||||
var P = require('p-promise')
|
||||
var config = require('../../config').root()
|
||||
var log = { trace: function() {} }
|
||||
var dbs = require('../../kv')(config, log)
|
||||
|
||||
var mailer = {
|
||||
sendVerifyCode: function () { return P(null) }
|
||||
}
|
||||
|
||||
var models = require('../../models')(log, config, dbs, mailer)
|
||||
var KeyFetchToken = models.tokens.KeyFetchToken
|
||||
|
||||
test(
|
||||
'bundle / unbundle works',
|
||||
function (t) {
|
||||
function end() { t.end() }
|
||||
KeyFetchToken.create('xxx')
|
||||
.then(
|
||||
function (x) {
|
||||
var kA = crypto.randomBytes(32).toString('hex')
|
||||
var wrapKb = crypto.randomBytes(32).toString('hex')
|
||||
var b = x.bundle(kA, wrapKb)
|
||||
var ub = x.unbundle(b)
|
||||
t.equal(ub.kA, kA)
|
||||
t.equal(ub.wrapKb, wrapKb)
|
||||
return x
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (x) {
|
||||
return x.del()
|
||||
}
|
||||
)
|
||||
.done(end, end)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'teardown',
|
||||
function (t) {
|
||||
dbs.cache.close()
|
||||
dbs.store.close()
|
||||
t.end()
|
||||
}
|
||||
)
|
|
@ -1,137 +0,0 @@
|
|||
var test = require('tap').test
|
||||
var crypto = require('crypto')
|
||||
var P = require('p-promise')
|
||||
var config = require('../../config').root()
|
||||
var log = { trace: function() {} }
|
||||
var dbs = require('../../kv')(config, log)
|
||||
|
||||
const HEX_STRING = /^(?:[a-fA-F0-9]{2})+$/
|
||||
|
||||
var sends = 0
|
||||
var mailer = {
|
||||
sendVerifyCode: function () { sends++; return P(null) }
|
||||
}
|
||||
|
||||
var models = require('../../models')(log, config, dbs, mailer)
|
||||
var RecoveryEmail = models.RecoveryEmail
|
||||
|
||||
var email = Buffer('me@example.com').toString('hex')
|
||||
|
||||
test(
|
||||
'RecoveryEmail.create generates a random 32 byte code as a hex string',
|
||||
function (t) {
|
||||
function end() { t.end() }
|
||||
RecoveryEmail.create('xxx', email, true)
|
||||
.then(
|
||||
function (x) {
|
||||
t.equal(x.code.length, 8)
|
||||
t.equal(HEX_STRING.test(x.code), true)
|
||||
return x
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (x) {
|
||||
return x.del()
|
||||
}
|
||||
)
|
||||
.done(end, end)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'RecoveryEmail.create calls mailer.sendVerifyCode',
|
||||
function (t) {
|
||||
sends = 0
|
||||
function end() { t.end() }
|
||||
RecoveryEmail.create('xxx', email, true)
|
||||
.then(
|
||||
function (x) {
|
||||
t.equal(sends, 1)
|
||||
sends = 0
|
||||
return x.del()
|
||||
}
|
||||
)
|
||||
.done(end, end)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'recoveryEmail.verify sets verified to true if the codes match',
|
||||
function (t) {
|
||||
function end() { t.end() }
|
||||
RecoveryEmail.create('xxx', email, true)
|
||||
.then(
|
||||
function (x) {
|
||||
t.equal(x.verified, false)
|
||||
var c = x.code
|
||||
return x.verify(c)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (x) {
|
||||
t.equal(x.verified, true)
|
||||
return x.del()
|
||||
}
|
||||
)
|
||||
.done(end, end)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'recoveryEmail.verify does not set verified if codes do not match',
|
||||
function (t) {
|
||||
function end() { t.end() }
|
||||
RecoveryEmail.create('xxx', email, true)
|
||||
.then(
|
||||
function (x) {
|
||||
t.equal(x.verified, false)
|
||||
var c = crypto.randomBytes(32).toString('hex')
|
||||
return x.verify(c)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (x) {
|
||||
t.equal(x.verified, false)
|
||||
return x.del()
|
||||
}
|
||||
)
|
||||
.done(end, end)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'recoveryEmail.verify will not unset the verified flag from true to false',
|
||||
function (t) {
|
||||
function end() { t.end() }
|
||||
RecoveryEmail.create('xxx', email, true)
|
||||
.then(
|
||||
function (x) {
|
||||
t.equal(x.verified, false)
|
||||
var c = x.code
|
||||
return x.verify(c)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (x) {
|
||||
t.equal(x.verified, true)
|
||||
return x.verify('bad1')
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (x) {
|
||||
t.equal(x.verified, true)
|
||||
return x.del()
|
||||
}
|
||||
)
|
||||
.done(end, end)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'teardown',
|
||||
function (t) {
|
||||
dbs.cache.close()
|
||||
dbs.store.close()
|
||||
t.end()
|
||||
}
|
||||
)
|
|
@ -3,15 +3,21 @@ var P = require('p-promise')
|
|||
var srp = require('srp')
|
||||
var config = require('../../config').root()
|
||||
var log = { trace: function() {} }
|
||||
var dbs = require('../../kv')(config, log)
|
||||
|
||||
var mailer = {
|
||||
sendVerifyCode: function () { return P(null) }
|
||||
}
|
||||
var Token = require('../../tokens')(log)
|
||||
var DB = require('../../db/heap')(
|
||||
log,
|
||||
Token.error,
|
||||
Token.AuthToken,
|
||||
Token.SessionToken,
|
||||
Token.KeyFetchToken,
|
||||
Token.AccountResetToken,
|
||||
Token.SrpToken,
|
||||
Token.ForgotPasswordToken
|
||||
)
|
||||
var db = new DB()
|
||||
|
||||
var models = require('../../models')(log, config, dbs, mailer)
|
||||
var Account = models.Account
|
||||
var SrpSession = models.SrpSession
|
||||
var SrpToken = Token.SrpToken
|
||||
|
||||
var alice = {
|
||||
uid: 'xxx',
|
||||
|
@ -34,14 +40,14 @@ alice.srp.verifier = srp.getv(
|
|||
'sha256'
|
||||
).toString('hex')
|
||||
|
||||
Account.create(alice)
|
||||
db.createAccount(alice)
|
||||
.done(
|
||||
function (a) {
|
||||
|
||||
test(
|
||||
'create login session works',
|
||||
function (t) {
|
||||
SrpSession.create(a)
|
||||
SrpToken.create(a)
|
||||
.done(
|
||||
function (s) {
|
||||
t.equal(s.uid, a.uid)
|
||||
|
@ -57,17 +63,17 @@ Account.create(alice)
|
|||
function (t) {
|
||||
var session = null
|
||||
var K = null
|
||||
SrpSession.create(a)
|
||||
SrpToken.create(a)
|
||||
.then(
|
||||
function (s) {
|
||||
session = s
|
||||
return SrpSession.client2(s.clientData(), alice.email, alice.password)
|
||||
return SrpToken.client2(s.clientData(), alice.email, alice.password)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (x) {
|
||||
K = x.K
|
||||
return SrpSession.finish(session.id, x.A, x.M)
|
||||
return session.finish(x.A, x.M)
|
||||
}
|
||||
)
|
||||
.done(
|
||||
|
@ -78,14 +84,5 @@ Account.create(alice)
|
|||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'teardown',
|
||||
function (t) {
|
||||
dbs.cache.close()
|
||||
dbs.store.close()
|
||||
t.end()
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
|
|
@ -56,5 +56,17 @@ module.exports = function (log, inherits, Token, crypto) {
|
|||
)
|
||||
}
|
||||
|
||||
ForgotPasswordToken.prototype.ttl = function () {
|
||||
return Math.max(
|
||||
Math.ceil((LIFETIME - (Date.now() - this.created)) / 1000),
|
||||
0
|
||||
)
|
||||
}
|
||||
|
||||
ForgotPasswordToken.prototype.failAttempt = function () {
|
||||
this.tries--
|
||||
return this.tries < 1
|
||||
}
|
||||
|
||||
return ForgotPasswordToken
|
||||
}
|
||||
|
|
|
@ -81,6 +81,18 @@ module.exports = function (log, P, uuid, srp, error) {
|
|||
return this
|
||||
}
|
||||
|
||||
SrpToken.prototype.clientData = function () {
|
||||
return {
|
||||
srpToken: this.id,
|
||||
passwordStretching: this.passwordStretching,
|
||||
srp: {
|
||||
type: 'SRP-6a/SHA256/2048/v1',
|
||||
salt: this.s,
|
||||
B: this.B.toString('hex')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SrpToken.client2 = function (session, email, password) {
|
||||
return srpGenKey()
|
||||
.then(
|
||||
|
|
Загрузка…
Ссылка в новой задаче