fixed tests deleted obsolete ones. need moar token tests

This commit is contained in:
Danny Coates 2013-10-26 22:46:57 -07:00
Родитель 830833f8a1
Коммит f59f012e98
15 изменённых файлов: 79 добавлений и 1229 удалений

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

@ -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(