updated /account/create to next api

This commit is contained in:
Danny Coates 2013-08-05 17:48:02 -07:00
Родитель 970023966f
Коммит df0ac8e8e9
8 изменённых файлов: 95 добавлений и 83 удалений

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

@ -64,16 +64,19 @@ function doRequest(method, url, token, payload) {
* {}
*
*/
ClientApi.prototype.accountCreate = function (email, verifier, salt, params) {
ClientApi.prototype.accountCreate = function (email, verifier, salt, passwordStretching) {
return doRequest(
'POST',
this.origin + '/account/create',
null,
{
email: email,
verifier: verifier,
salt: salt,
params: params
srp: {
type: 'SRP-6a/SHA256/2048/v1',
verifier: verifier,
salt: salt
},
passwordStretching: passwordStretching
}
)
}

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

@ -14,7 +14,8 @@ var AuthBundle = models.AuthBundle
function Client(origin) {
this.api = new ClientApi(origin)
this.algorithm = 'sha256'
this.salt = null
this.srpSalt = null
this.passwordSalt = null
this.email = null
this.verifier = null
this.sessionToken = null
@ -67,10 +68,12 @@ function verifier(salt, email, password, algorithm) {
Client.create = function (origin, email, password, callback) {
var c = new Client(origin)
// TODO: password stretching
c.email = email
c.password = password
c.salt = crypto.randomBytes(32).toString('hex')
c.verifier = verifier(c.salt, c.email, c.password, c.algorithm)
c.srpSalt = crypto.randomBytes(32).toString('hex')
c.verifier = verifier(c.srpSalt, c.email, c.password, c.algorithm)
c.passwordSalt = crypto.randomBytes(32).toString('hex')
var p = c.create()
if (callback) {
p.done(callback.bind(null, null), callback)
@ -83,11 +86,11 @@ Client.create = function (origin, email, password, callback) {
Client.parse = function (string) {
var object = JSON.parse(string)
var client = new Client(object.api.origin)
client.salt = object.salt
client.email = object.email
client.password = object.password
client.salt = object.salt
client.verifier = object.verifier
client.srp = object.srp
c.passwordSalt = object.passwordSalt
client.passwordStretching = object.passwordStretching
client.sessionToken = object.sessionToken
client.accountResetToken = object.accountResetToken
client.keyFetchToken = object.keyFetchToken
@ -101,16 +104,15 @@ Client.prototype.create = function (callback) {
var p = this.api.accountCreate(
this.email,
this.verifier,
this.salt,
this.srpSalt,
{
srp: {
alg: this.algorithm,
N_bits: 2048
},
stretch: {
salt: 'DEAD',
rounds: 0
}
type: 'PBKDF2/scrypt/PBKDF2/v1',
PBKDF2_rounds_1: 20000,
scrypt_N: 65536,
scrypt_r: 8,
scrypt_p: 1,
PBKDF2_rounds_2: 20000,
salt: this.passwordSalt
}
)
.then(
@ -232,9 +234,9 @@ Client.prototype.changePassword = function (newPassword, callback) {
)
.then(
function (token) {
this.salt = crypto.randomBytes(32).toString('hex')
this.srpSalt = crypto.randomBytes(32).toString('hex')
this.password = newPassword
this.verifier = verifier(this.salt, this.email, newPassword, this.algorithm)
this.verifier = verifier(this.srpSalt, this.email, newPassword, this.algorithm)
var bundle = token.bundle(this.wrapKb, this.verifier)
var params = this.params
return this.api.accountReset(

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

@ -78,18 +78,17 @@ Creates a user account. The client provides the email address with which this ac
___Parameters___
* email - the primary email for this account
* mainKDFSalt - salt for main-KDF
* srpSalt - SRP salt
* srpVerifier - the derived SRP verifier
* params
* srpParametersVersion: "1" (meaning SRP-6a, SHA256, with a specific 2048-bit group)
* stretch
* keyStretchingVersion: "1" (meaning PBKDF2/scrypt/PBKDF2)
* PBKDF2_rounds_1: 20000
* scrypt_N: 65536
* scrypt_r: 8
* scrypt_p: 1
* PBKDF2_rounds_2: 20000
* srp
* type - "SRP-6a/SHA256/2048/v1"
* verifer - the derived SRP verifier
* salt - SRP salt
* passwordStretching
* type: "PBKDF2/scrypt/PBKDF2/v1"
* PBKDF2_rounds_1: 20000
* scrypt_N: 65536
* scrypt_r: 8
* scrypt_p: 1
* PBKDF2_rounds_2: 20000
### Request
```sh
@ -99,19 +98,19 @@ curl -v \
http://idp.profileinthecloud.net/account/create \
-d '{
"email": "me2@example.com",
"mainKDFSalt: "996bc6b1aa63cd69856a2ec81cbf19d5c8a604713362df9ee15c2bf07128efab",
"srpSalt: "f9fae9253549b2428a403d6fa51e6fb43d2f8a302e132cf902ffade52c02e6a4",
"srpVerifier": "7597c55064c73bf1b2735878cb8711c289fc8f1cfb3d633a4593b36a8c51dbd68b27f649949de27d1dcccf7ece1e1a42c5c6bdc3d209cf13a3813d333bfcadd2641a9a3e2eb4289788ed8510cc8f2f1061789d58aef38b9d21b81831413f55473f9fae9253549b2428a403d6fa51e6fb43d2f8a302e132cf902ffade52c02e6a4e0bda74fcaa2347be4664f553d332df8166278c0e2f8663aa9238a2429631f7afd11622e193747b57975c51bbb69bb11f60c1a5ba449d3119e70d1ec580212151f79b26e73a57dba313376f0ba7a2afc232146a3b1d68b2d0afc35ebb8699cb10b3a3f8e0d51cefc7ac29212b238fb7a87f2f61edc9cbff103e386f778925fe",
"params": {
"srpParametersVersion": "1",
"stretch": {
"keyStretchingVersion": "1",
"PBKDF2_rounds_1": 20000,
"scrypt_N": 65536,
"scrypt_r": 8,
"scrypt_p": 1,
"PBKDF2_rounds_2": 20000
}
"srp": {
"type": "SRP-6a/SHA256/2048/v1",
"verifier": "7597c55064c73bf1b2735878cb8711c289fc8f1cfb3d633a4593b36a8c51dbd68b27f649949de27d1dcccf7ece1e1a42c5c6bdc3d209cf13a3813d333bfcadd2641a9a3e2eb4289788ed8510cc8f2f1061789d58aef38b9d21b81831413f55473f9fae9253549b2428a403d6fa51e6fb43d2f8a302e132cf902ffade52c02e6a4e0bda74fcaa2347be4664f553d332df8166278c0e2f8663aa9238a2429631f7afd11622e193747b57975c51bbb69bb11f60c1a5ba449d3119e70d1ec580212151f79b26e73a57dba313376f0ba7a2afc232146a3b1d68b2d0afc35ebb8699cb10b3a3f8e0d51cefc7ac29212b238fb7a87f2f61edc9cbff103e386f778925fe",
salt: "f9fae9253549b2428a403d6fa51e6fb43d2f8a302e132cf902ffade52c02e6a4"
},
"passwordStretching": {
"type": "PBKDF2/scrypt/PBKDF2/v1",
"PBKDF2_rounds_1": 20000,
"scrypt_N": 65536,
"scrypt_r": 8,
"scrypt_p": 1,
"PBKDF2_rounds_2": 20000,
"salt": "996bc6b1aa63cd69856a2ec81cbf19d5c8a604713362df9ee15c2bf07128efab"
}
}'
```

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

@ -12,11 +12,10 @@ module.exports = function (P, tokens, RecoveryMethod, db, config, error) {
this.uid = null
this.email = null
this.verified = false
this.verifier = null
this.salt = null
this.kA = null
this.wrapKb = null
this.params = null
this.srp = null
this.passwordStretching = null
// references
this.resetTokenId = null
this.sessionTokenIds = null
@ -30,11 +29,10 @@ module.exports = function (P, tokens, RecoveryMethod, db, config, error) {
a.uid = object.uid
a.email = object.email
a.verified = !!object.verified
a.verifier = object.verifier
a.salt = object.salt
a.srp = object.srp
a.kA = object.kA
a.wrapKb = object.wrapKb
a.params = object.params
a.passwordStretching = object.passwordStretching
a.resetTokenId = object.resetTokenId
a.sessionTokenIds = object.sessionTokenIds || {}
a.recoveryMethodIds = object.recoveryMethodIds || {}
@ -232,8 +230,8 @@ module.exports = function (P, tokens, RecoveryMethod, db, config, error) {
Account.prototype.reset = function (form) {
//this.kA = null // TODO
this.wrapKb = form.wrapKb
this.verifier = form.verifier
this.params = form.params
this.srp = form.srp
this.passwordStretching = form.passwordStretching
return this.deleteAllTokens()
.then(this.save.bind(this))
}

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

@ -40,8 +40,8 @@ module.exports = function (P, uuid, srp, db, error) {
session.uid = account.uid
session.N = srp.params[2048].N
session.g = srp.params[2048].g
session.s = account.salt
session.v = Buffer(account.verifier, 'hex')
session.s = account.srp.salt
session.v = Buffer(account.srp.verifier, 'hex')
session.b = b
session.B = srp.getB(session.v, session.g, b, session.N, alg)
session.type = type

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

@ -19,18 +19,17 @@ module.exports = function (crypto, uuid, isA, error, Account, RecoveryMethod) {
validate: {
payload: {
email: isA.String().email().required(),
verifier: isA.String().regex(HEX_STRING).required(),
salt: isA.String().regex(HEX_STRING).required(),
params: isA.Object({
srp: isA.Object({
alg: isA.String().valid('sha256').required(),
N_bits: isA.Number().valid(2048).required()
}).required(),
stretch: isA.Object({
salt: isA.String().regex(HEX_STRING).required(),
rounds: isA.Number().required()
})
})
srp: isA.Object({
type: isA.String().required(), // TODO valid()
verifier: isA.String().regex(HEX_STRING).required(),
salt: isA.String().regex(HEX_STRING).required(),
}).required(),
passwordStretching: isA.Object(
// {
// type: isA.String().required(),
// salt: isA.String().regex(HEX_STRING).required()
// }
)
}
},
handler: function accountCreate(request) {
@ -40,11 +39,10 @@ module.exports = function (crypto, uuid, isA, error, Account, RecoveryMethod) {
{
uid: uuid.v4(),
email: form.email,
verifier: form.verifier,
salt: form.salt,
srp: form.srp,
kA: crypto.randomBytes(32).toString('hex'),
wrapKb: crypto.randomBytes(32).toString('hex'),
params: form.params
passwordStretching: form.passwordStretching
}
)
.done(

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

@ -17,8 +17,10 @@ var AccountResetToken = models.tokens.AccountResetToken
var a = {
uid: 'xxx',
email: 'somebody@example.com',
verifier: 'BAD1',
salt: 'BAD2',
srp: {
verifier: 'BAD1',
salt: 'BAD2'
},
kA: 'BAD3',
wrapKb: 'BAD4'
}
@ -412,8 +414,12 @@ test(
function (t) {
var form = {
wrapKb: 'DEADBEEF',
verifier: 'FEEDFACE',
params: {
srp: {
type: 'SRP-6a/SHA256/2048/v1',
verifier: 'FEEDFACE',
salt: '12345678'
},
passwordStretching: {
stuff: true
}
}
@ -426,7 +432,7 @@ test(
.then(
function (account) {
t.equal(account.wrapKb, form.wrapKb)
t.equal(account.verifier, form.verifier)
t.equal(account.srp.verifier, form.srp.verifier)
}
)
.then(Account.del.bind(null, a.uid))
@ -445,8 +451,12 @@ test(
var reset = null
var form = {
wrapKb: 'DEADBEEF',
verifier: 'FEEDFACE',
params: {
srp: {
type: 'SRP-6a/SHA256/2048/v1',
verifier: 'FEEDFACE',
salt: '12345678'
},
passwordStretching: {
stuff: true
}
}

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

@ -17,14 +17,16 @@ var alice = {
uid: 'xxx',
email: 'somebody@example.com',
password: 'awesomeSauce',
verifier: null,
salt: 'BAD1',
srp: {
verifier: null,
salt: 'BAD1'
},
kA: 'BAD3',
wrapKb: 'BAD4'
}
alice.verifier = srp.getv(
Buffer(alice.salt, 'hex'),
alice.srp.verifier = srp.getv(
Buffer(alice.srp.salt, 'hex'),
Buffer(alice.email),
Buffer(alice.password),
srp.params[2048].N,
@ -44,7 +46,7 @@ Account.create(alice)
.done(
function (s) {
t.equal(s.uid, a.uid)
t.equal(s.s, a.salt)
t.equal(s.s, a.srp.salt)
t.equal(s.type, 'login')
t.end()