wip on db api
This commit is contained in:
Родитель
4ba5938818
Коммит
4d89d86f8c
|
@ -29,14 +29,15 @@ function main() {
|
|||
memoryMonitor.start()
|
||||
|
||||
// databases
|
||||
var dbs = require('../kv')(config, log)
|
||||
//var dbs = require('../kv')(config, log)
|
||||
var db = require('../db/heap')(log)
|
||||
|
||||
// TODO: send to the SMTP server directly. In the future this may change
|
||||
// to another process that we send an http request to.
|
||||
var mailer = require('../mailer')(config.smtp, log)
|
||||
|
||||
// stored objects
|
||||
var models = require('../models')(log, config, dbs, mailer)
|
||||
//var models = require('../models')(log, config, dbs, mailer)
|
||||
|
||||
// server public key
|
||||
var serverPublicKey = JSON.parse(fs.readFileSync(config.publicKeyFile))
|
||||
|
@ -45,9 +46,9 @@ function main() {
|
|||
var CC = require('compute-cluster')
|
||||
var signer = new CC({ module: __dirname + '/signer.js' })
|
||||
|
||||
var routes = require('../routes')(log, serverPublicKey, signer, models, config)
|
||||
var routes = require('../routes')(log, serverPublicKey, signer, db, config)
|
||||
var Server = require('../server')
|
||||
var server = Server.create(log, config, routes, models.tokens)
|
||||
var server = Server.create(log, config, routes, db)
|
||||
|
||||
server.start(
|
||||
function () {
|
||||
|
|
|
@ -0,0 +1,313 @@
|
|||
var inherits = require('util').inherits
|
||||
var P = require('p-promise')
|
||||
var Bundle = require('../bundle')
|
||||
|
||||
module.exports = function (log) {
|
||||
|
||||
var Token = require('../models/token')(log, inherits, Bundle)
|
||||
var SessionToken = require('../models/session_token')(log, inherits, Token)
|
||||
var KeyFetchToken = require('../models/key_fetch_token')(log, inherits, Token)
|
||||
var AccountResetToken = require('../models/account_reset_token')(log, inherits, Token)
|
||||
var SrpToken = require('../models.srp_session')(log) // TODO
|
||||
var ForgotPasswordToken = require('../models/forgot_password_token')(log, inherits, Token)
|
||||
|
||||
function Heap() {
|
||||
this.sessionTokens = {}
|
||||
this.keyFetchTokens = {}
|
||||
this.accountResetTokens = {}
|
||||
this.authTokens = {}
|
||||
this.srpTokens = {}
|
||||
this.forgotPasswordTokens = {}
|
||||
this.accounts = {}
|
||||
this.emailRecords = {}
|
||||
}
|
||||
|
||||
function saveTo(collection) {
|
||||
return function (object) {
|
||||
collection[object.id] = object
|
||||
return object
|
||||
}
|
||||
}
|
||||
|
||||
// The lazy way
|
||||
function deleteUid(uid, collection) {
|
||||
var keys = Object.keys(collection)
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
if (collection[keys[i]].uid === uid) {
|
||||
delete collection[keys[i]]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Heap.prototype.ping = function () {
|
||||
return P(true)
|
||||
}
|
||||
|
||||
// CREATE
|
||||
|
||||
Heap.prototype.createAccount = function (data) {
|
||||
this.accounts[data.uid] = data
|
||||
this.emailRecords[data.email] = data.uid
|
||||
return P(data)
|
||||
}
|
||||
|
||||
Heap.prototype.createSessionToken = function (authToken) {
|
||||
return SessionToken.create(authToken)
|
||||
.then(saveTo(this.sessionTokens))
|
||||
.then(
|
||||
function (sessionToken) {
|
||||
var account = this.account[sessionToken.uid]
|
||||
account.devices[sessionToken.id] = sessionToken
|
||||
return sessionToken
|
||||
}.bind(this)
|
||||
)
|
||||
}
|
||||
|
||||
Heap.prototype.createKeyFetchToken = function (authToken) {
|
||||
return KeyFetchToken.create(authToken)
|
||||
.then(saveTo(this.keyFetchTokens))
|
||||
}
|
||||
|
||||
Heap.prototype.createAccountResetToken = function (token /* authToken|forgotPasswordToken */) {
|
||||
return AccountResetToken.create(token)
|
||||
.then(
|
||||
function (accountResetToken) {
|
||||
var account = this.accounts[accountResetToken.uid]
|
||||
if (!account) { return P.reject('Account not found') }
|
||||
account.accountResetToken = accountResetToken.id
|
||||
return accountResetToken
|
||||
}.bind(this)
|
||||
)
|
||||
.then(saveTo(this.accountResetTokens))
|
||||
}
|
||||
|
||||
Heap.prototype.createAuthToken = function (srpToken) {
|
||||
return AuthToken.create(srpToken)
|
||||
.then(saveTo(this.authTokens))
|
||||
}
|
||||
|
||||
Heap.prototype.createSrpToken = function (emailRecord) {
|
||||
return SrpToken.create(emailRecord)
|
||||
.then(saveTo(this.srpTokens))
|
||||
}
|
||||
|
||||
Heap.prototype.createForgotPasswordToken = function (emailRecord) {
|
||||
return ForgotPasswordToken.create(emailRecord)
|
||||
.then(
|
||||
function (forgotPasswordToken) {
|
||||
var account = this.accounts[forgotPasswordToken.uid]
|
||||
if (!account) { return P.reject('Account not found') }
|
||||
account.forgotPasswordToken = forgotPasswordToken.id
|
||||
return forgotPasswordToken
|
||||
}.bind(this)
|
||||
)
|
||||
.then(saveTo(this.forgotPasswordTokens))
|
||||
}
|
||||
|
||||
// READ
|
||||
|
||||
Heap.prototype.accountExists = function (email) {
|
||||
return P(!!this.emailRecords[email])
|
||||
}
|
||||
|
||||
Heap.prototype.accountDevices = function (uid) {
|
||||
return this.account(uid)
|
||||
.then(
|
||||
function (account) {
|
||||
return account.devices
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
Heap.prototype.sessionToken = function (id) {
|
||||
var sessionToken = this.sessionTokens[id]
|
||||
if (!sessionToken) { return P.reject('SessionToken not found') }
|
||||
var account = this.accounts[sessionToken.uid]
|
||||
if (!account) { return P.reject('Account not found') }
|
||||
sessionToken.email = account.email
|
||||
sessionToken.emailCode = account.emailCode
|
||||
sessionToken.verified = account.verified
|
||||
return P(sessionToken)
|
||||
}
|
||||
|
||||
Heap.prototype.keyFetchToken = function (id) {
|
||||
var keyFetchToken = this.keyFetchTokens[id]
|
||||
if (!keyFetchToken) { return P.reject('KeyFetchToken not found') }
|
||||
var account = this.accounts[sessionToken.uid]
|
||||
if (!account) { return P.reject('Account not found') }
|
||||
keyFetchToken.kA = account.kA
|
||||
keyFetchToken.wrapKb = account.wrapKb
|
||||
keyFetchToken.verified = account.verified
|
||||
return P(keyFetchToken)
|
||||
}
|
||||
|
||||
Heap.prototype.accountResetToken = function (id) {
|
||||
var accountResetToken = this.accountResetTokens[id]
|
||||
if (!accountResetToken) { return P.reject('AccountResetToken not found') }
|
||||
return P(accountResetToken)
|
||||
}
|
||||
|
||||
Heap.prototype.authToken = function (id) {
|
||||
var authToken = this.authTokens[id]
|
||||
if (!authToken) { return P.reject('AuthToken not found') }
|
||||
return P(authToken)
|
||||
}
|
||||
|
||||
Heap.prototype.srpToken = function (id) {
|
||||
var srpToken = this.srpTokens[id]
|
||||
if (!srpToken) { return P.reject('SrpToken not found') }
|
||||
return P(srpToken)
|
||||
}
|
||||
|
||||
Heap.prototype.forgotPasswordToken = function (id) {
|
||||
var forgotPasswordToken = this.forgotPasswordTokens[id]
|
||||
if (!forgotPasswordToken) { return P.reject('ForgotPasswordToken not found') }
|
||||
var account = this.accounts[sessionToken.uid]
|
||||
if (!account) { return P.reject('Account not found') }
|
||||
forgotPasswordToken.email = account.email
|
||||
return P(forgotPasswordToken)
|
||||
}
|
||||
|
||||
Heap.prototype.emailRecord = function (email) {
|
||||
var uid = this.emailRecords[email]
|
||||
return this.account(uid)
|
||||
}
|
||||
|
||||
Heap.prototype.account = function (uid) {
|
||||
var account = this.accounts[sessionToken.uid]
|
||||
if (!account) { return P.reject('Account not found') }
|
||||
return P(account)
|
||||
}
|
||||
|
||||
// UPDATE
|
||||
|
||||
Heap.prototype.udateForgotPasswordToken = function (forgotPasswordToken) {
|
||||
return P(true)
|
||||
}
|
||||
|
||||
// DELETE
|
||||
|
||||
Heap.prototype.deleteAccount = function (authToken) {
|
||||
var account = this.accounts[authToken.uid]
|
||||
if (!account) { return P.reject('Account not found') }
|
||||
deleteUid(account.uid, this.sessionTokens)
|
||||
deleteUid(account.uid, this.keyFetchTokens)
|
||||
deleteUid(account.uid, this.authTokens)
|
||||
deleteUid(account.uid, this.srpTokens)
|
||||
deleteUid(account.uid, this.accountResetTokens)
|
||||
deleteUid(account.uid, this.forgotPasswordTokens)
|
||||
delete this.emailRecords[account.email]
|
||||
delete this.accounts[account.uid]
|
||||
return P(true)
|
||||
}
|
||||
|
||||
Heap.prototype.deleteSessionToken = function (sessionToken) {
|
||||
var account = this.accounts[sessionToken.uid]
|
||||
if (!account) { return P.reject('Account not found') }
|
||||
delete account.devices[sessionToken.id]
|
||||
delete this.sessionTokens[sessionToken.id]
|
||||
return P(true)
|
||||
}
|
||||
|
||||
Heap.prototype.deleteKeyFetchToken = function (keyFetchToken) {
|
||||
delete this.keyFetchTokens[keyFetchToken.id]
|
||||
return P(true)
|
||||
}
|
||||
|
||||
Heap.prototype.deleteAccountResetToken = function (accountResetToken) {
|
||||
delete this.accountResetTokens[accountResetToken.id]
|
||||
return P(true)
|
||||
}
|
||||
|
||||
Heap.prototype.deleteAuthToken = function (authToken) {
|
||||
delete this.authTokens[authToken.id]
|
||||
return P(true)
|
||||
}
|
||||
|
||||
Heap.prototype.deleteSrpToken = function (srpToken) {
|
||||
delete this.srpTokens[srpToken.id]
|
||||
return P(true)
|
||||
}
|
||||
|
||||
Heap.prototype.deleteForgotPasswordToken = function (forgotPasswordToken) {
|
||||
delete this.forgotPasswordTokens[forgotPasswordToken.id]
|
||||
return P(true)
|
||||
}
|
||||
|
||||
// BATCH
|
||||
|
||||
Heap.prototype.resetAccount = function (accountResetToken, data) {
|
||||
var account = this.accounts[accountResetToken.uid]
|
||||
if (!account) { return P.reject('Account not found') }
|
||||
account.srp = data.srp
|
||||
account.wrapKb = data.wrapKb
|
||||
account.passwordStretching = data.passwordStretching
|
||||
account.devices = {}
|
||||
account.accountResetToken = null
|
||||
account.forgotPasswordToken = null
|
||||
deleteUid(account.uid, this.sessionTokens)
|
||||
deleteUid(account.uid, this.keyFetchTokens)
|
||||
deleteUid(account.uid, this.authTokens)
|
||||
deleteUid(account.uid, this.srpTokens)
|
||||
deleteUid(account.uid, this.accountResetTokens)
|
||||
deleteUid(account.uid, this.forgotPasswordTokens)
|
||||
return P(true)
|
||||
}
|
||||
|
||||
Heap.prototype.authFinish = function (srpToken) {
|
||||
return this.deleteSrpToken(srpToken)
|
||||
.then(this.createAuthToken.bind(this, srpToken))
|
||||
}
|
||||
|
||||
Heap.prototype.createSession = function (authToken) {
|
||||
return this.deleteAuthToken(authToken)
|
||||
.then(
|
||||
function () {
|
||||
return P.all([
|
||||
this.createKeyFetchToken(authToken),
|
||||
this.createSessionToken(authToken)
|
||||
])
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (tokens) {
|
||||
return {
|
||||
keyFetchToken: tokens[0],
|
||||
sessionToken: tokens[1]
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
Heap.prototype.verifyEmail = function (account) {
|
||||
account.verified = true
|
||||
return P(true)
|
||||
}
|
||||
|
||||
Heap.prototype.createPasswordChange = function (authToken) {
|
||||
return this.deleteAuthToken(authToken)
|
||||
.then(
|
||||
function () {
|
||||
return P.all([
|
||||
this.createKeyFetchToken(authToken),
|
||||
this.createAccountResetToken(authToken)
|
||||
])
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (tokens) {
|
||||
return {
|
||||
keyFetchToken: tokens[0],
|
||||
accountResetToken: tokens[1]
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
Heap.prototype.forgotPasswordVerified = function (forgotPasswordToken) {
|
||||
return this.deleteForgotPasswordToken(forgotPasswordToken)
|
||||
.then(this.createAccountResetToken.bind(this, forgotPasswordToken))
|
||||
}
|
||||
|
||||
return Heap
|
||||
}
|
|
@ -0,0 +1,430 @@
|
|||
## /account/create
|
||||
|
||||
* input
|
||||
* email
|
||||
* srp
|
||||
* passwordStretching
|
||||
* reads
|
||||
* email
|
||||
* writes
|
||||
* uid
|
||||
* email
|
||||
* emailCode
|
||||
* verified
|
||||
* kA
|
||||
* wrapKb
|
||||
* srp
|
||||
* passwordStretching
|
||||
* sessionTokenList
|
||||
* keyFetchTokenList
|
||||
* forgotPasswordTokenList
|
||||
* srpTokenList
|
||||
* authTokenList
|
||||
* accountResetTokenList
|
||||
* output
|
||||
* uid
|
||||
* db-read
|
||||
* Emails
|
||||
* db-write
|
||||
* Emails
|
||||
* Accounts
|
||||
|
||||
## /account/devices
|
||||
|
||||
* input
|
||||
* sessionToken.id
|
||||
* reads
|
||||
* uid
|
||||
* sessionTokenList
|
||||
* writes
|
||||
* (none)
|
||||
* output
|
||||
* sessionTokenList (x)
|
||||
* db-read
|
||||
* SessionTokens
|
||||
* Accounts
|
||||
* db-write
|
||||
* (none)
|
||||
|
||||
## /account/keys
|
||||
|
||||
* input
|
||||
* keyFetchToken.id
|
||||
* reads
|
||||
* uid
|
||||
* kA
|
||||
* wrapKb
|
||||
* verified
|
||||
* writes
|
||||
* delete
|
||||
* keyFetchToken
|
||||
* keyFetchTokenList
|
||||
* output
|
||||
* kA
|
||||
* wrapKb
|
||||
* db-read
|
||||
* KeyFetchTokens
|
||||
* db-write
|
||||
* KeyFetchTokens
|
||||
* Accounts
|
||||
|
||||
## /account/reset
|
||||
|
||||
* input
|
||||
* accountResetToken.id
|
||||
* srp
|
||||
* passwordStretching
|
||||
* wrapKb
|
||||
* reads
|
||||
* uid
|
||||
* sessionTokenList
|
||||
* keyFetchTokenList
|
||||
* forgotPasswordTokenList
|
||||
* srpTokenList
|
||||
* authTokenList
|
||||
* accountResetTokenList
|
||||
* writes
|
||||
* delete
|
||||
* all tokens
|
||||
* srp
|
||||
* passwordStretching
|
||||
* wrapKb
|
||||
* sessionTokenList
|
||||
* keyFetchTokenList
|
||||
* forgotPasswordTokenList
|
||||
* srpTokenList
|
||||
* authTokenList
|
||||
* accountResetTokenList
|
||||
* output
|
||||
* (none)
|
||||
* db-read
|
||||
* AccountResetTokens
|
||||
* Accounts
|
||||
* db-write
|
||||
* SessionTokens
|
||||
* KeyFetchTokens
|
||||
* AccountResetTokens
|
||||
* AuthTokens
|
||||
* SrpTokens
|
||||
* ForgotPasswordTokens
|
||||
* Emails
|
||||
* Accounts
|
||||
|
||||
## /account/destroy
|
||||
|
||||
* input
|
||||
* authToken.id
|
||||
* reads
|
||||
* uid
|
||||
* sessionTokenList
|
||||
* keyFetchTokenList
|
||||
* forgotPasswordTokenList
|
||||
* srpTokenList
|
||||
* authTokenList
|
||||
* accountResetTokenList
|
||||
* writes
|
||||
* delete
|
||||
* all
|
||||
* output
|
||||
* (none)
|
||||
* db-read
|
||||
* AuthTokens
|
||||
* Accounts
|
||||
* db-write
|
||||
* SessionTokens
|
||||
* KeyFetchTokens
|
||||
* AccountResetTokens
|
||||
* AuthTokens
|
||||
* SrpTokens
|
||||
* ForgotPasswordTokens
|
||||
* Emails
|
||||
* Accounts
|
||||
|
||||
## /auth/start
|
||||
|
||||
* input
|
||||
* email
|
||||
* reads
|
||||
* uid
|
||||
* srp
|
||||
* passwordStretching
|
||||
* srpToken data
|
||||
* email
|
||||
* emailCode
|
||||
* kA
|
||||
* wrapKb
|
||||
* verified
|
||||
* writes
|
||||
* srpToken
|
||||
* srpTokenList
|
||||
* output
|
||||
* srpToken.id
|
||||
* passwordStretching
|
||||
* srp.B
|
||||
* srp.salt
|
||||
* db-read
|
||||
* Emails
|
||||
* db-write
|
||||
* SrpTokens
|
||||
* Accounts
|
||||
|
||||
## /auth/finish
|
||||
|
||||
* input
|
||||
* srpToken.id
|
||||
* A
|
||||
* M
|
||||
* reads
|
||||
* uid
|
||||
* srpToken
|
||||
* N, g, s, v, b, B
|
||||
* passwordStretching
|
||||
* authToken data
|
||||
* email
|
||||
* emailCode
|
||||
* kA
|
||||
* wrapKb
|
||||
* verified
|
||||
* writes
|
||||
* delete
|
||||
* srpToken
|
||||
* authToken
|
||||
* srpTokenList
|
||||
* authTokenList
|
||||
* output
|
||||
* authToken.id
|
||||
* db-read
|
||||
* SrpTokens
|
||||
* db-write
|
||||
* SrpTokens
|
||||
* AuthTokens
|
||||
* Accounts
|
||||
|
||||
## /session/create
|
||||
|
||||
* input
|
||||
* authToken.id
|
||||
* reads
|
||||
* uid
|
||||
* verified
|
||||
* sessionToken data
|
||||
* email
|
||||
* emailCode
|
||||
* keyFetchToken data
|
||||
* kA
|
||||
* wrapKb
|
||||
* writes
|
||||
* delete
|
||||
* authToken
|
||||
* sessionToken
|
||||
* keyFetchToken
|
||||
* sessionTokenList
|
||||
* keyFetchTokenList
|
||||
* output
|
||||
* keyFetchToken.id
|
||||
* sessionToken.id
|
||||
* db-read
|
||||
* AuthTokens
|
||||
* db-write
|
||||
* AuthTokens
|
||||
* SessionTokens
|
||||
* KeyFetchTokens
|
||||
* Accounts
|
||||
|
||||
## /session/destroy
|
||||
|
||||
* input
|
||||
* sessionToken.id
|
||||
* reads
|
||||
* uid
|
||||
* writes
|
||||
* delete
|
||||
* sessionToken
|
||||
* sessionTokenList
|
||||
* output
|
||||
* (none)
|
||||
* db-read
|
||||
* SessionTokens
|
||||
* db-write
|
||||
* SessionTokens
|
||||
* Accounts
|
||||
|
||||
## /recovery_email/status
|
||||
|
||||
* input
|
||||
* sessionToken.id
|
||||
* reads
|
||||
* email
|
||||
* verified
|
||||
* writes
|
||||
* (none)
|
||||
* output
|
||||
* email
|
||||
* verified
|
||||
* db-read
|
||||
* SessionTokens
|
||||
* db-write
|
||||
* (none)
|
||||
|
||||
## /recovery_email/resend_code
|
||||
|
||||
* input
|
||||
* sessionToken.id
|
||||
* reads
|
||||
* uid
|
||||
* email
|
||||
* emailCode
|
||||
* writes
|
||||
* (none)
|
||||
* output
|
||||
* (none)
|
||||
* db-read
|
||||
* SessionTokens
|
||||
* db-write
|
||||
* (none)
|
||||
|
||||
## /recovery_email/verify_code
|
||||
|
||||
* input
|
||||
* uid
|
||||
* code
|
||||
* reads
|
||||
* emailCode
|
||||
* srpTokenList
|
||||
* authTokenList
|
||||
* keyFetchTokenList
|
||||
* sessionTokenList
|
||||
* writes
|
||||
* verified
|
||||
* output
|
||||
* (none)
|
||||
* db-read
|
||||
* Accounts
|
||||
* db-write
|
||||
* Emails
|
||||
* SrpTokens
|
||||
* AuthTokens
|
||||
* KeyFetchTokens
|
||||
* SessionTokens
|
||||
|
||||
## /certificate/sign
|
||||
|
||||
* input
|
||||
* sessionToken.id
|
||||
* publicKey
|
||||
* duration
|
||||
* reads
|
||||
* uid
|
||||
* verified
|
||||
* writes
|
||||
* (none)
|
||||
* output
|
||||
* signedKey
|
||||
* db-read
|
||||
* SessionTokens
|
||||
* db-write
|
||||
* (none)
|
||||
|
||||
## /password/change/start
|
||||
|
||||
* input
|
||||
* authToken.id
|
||||
* reads
|
||||
* uid
|
||||
* keyFetchToken data
|
||||
* kA
|
||||
* wrapKb
|
||||
* verified
|
||||
* accountResetToken data
|
||||
* (none)
|
||||
* writes
|
||||
* delete
|
||||
* authToken
|
||||
* keyFetchToken
|
||||
* accountResetToken
|
||||
* keyFetchTokenList
|
||||
* accountResetTokenList
|
||||
* output
|
||||
* keyFetchToken
|
||||
* accountResetToken
|
||||
* db-read
|
||||
* AuthTokens
|
||||
* db-write
|
||||
* AuthTokens
|
||||
* KeyFetchTokens
|
||||
* AccountResetTokens
|
||||
* Accounts
|
||||
|
||||
## /password/forgot/send_code
|
||||
|
||||
* input
|
||||
* email
|
||||
* reads
|
||||
* uid
|
||||
* forgotPasswordToken data
|
||||
* (none)
|
||||
* writes
|
||||
* forgotPasswordToken
|
||||
* forgotPasswordTokenList
|
||||
* output
|
||||
* forgotPasswordToken.id
|
||||
* ttl
|
||||
* codeLength
|
||||
* tries
|
||||
* db-read
|
||||
* Emails
|
||||
* db-write
|
||||
* ForgotPasswordTokens
|
||||
* Accounts
|
||||
|
||||
## /password/forgot/resend_code
|
||||
|
||||
* input
|
||||
* forgotPasswordToken.id
|
||||
* reads
|
||||
* uid
|
||||
* email
|
||||
* passcode
|
||||
* ttl
|
||||
* codeLength
|
||||
* tries
|
||||
* writes
|
||||
* (none)
|
||||
* output
|
||||
* forgotPasswordToken.id
|
||||
* ttl
|
||||
* codeLength
|
||||
* tries
|
||||
* db-read
|
||||
* ForgotPasswordTokens
|
||||
* db-write
|
||||
* (none)
|
||||
|
||||
## /password/forgot/verify_code
|
||||
|
||||
* input
|
||||
* forgotPasswordToken.id
|
||||
* code
|
||||
* reads
|
||||
* uid
|
||||
* passcode
|
||||
* ttl
|
||||
* accountResetToken data
|
||||
* (none)
|
||||
* writes
|
||||
* delete
|
||||
* forgotPasswordToken
|
||||
* tries
|
||||
* accountResetToken
|
||||
* forgotPasswordTokenList
|
||||
* accountResetTokenList
|
||||
* output
|
||||
* accountResetToken.id
|
||||
* ttl
|
||||
* tries
|
||||
* db-read
|
||||
* ForgotPasswordTokens
|
||||
* db-write
|
||||
* ForgotPasswordTokens
|
||||
* AccountResetTokens
|
||||
* Accounts
|
|
@ -0,0 +1,86 @@
|
|||
|
||||
## SessionTokens
|
||||
|
||||
* id
|
||||
* uid
|
||||
* email
|
||||
* emailCode
|
||||
* verified
|
||||
|
||||
## KeyFetchTokens
|
||||
|
||||
* id
|
||||
* uid
|
||||
* kA
|
||||
* wrapKb
|
||||
* verified
|
||||
|
||||
## AccountResetTokens
|
||||
|
||||
* id
|
||||
* uid
|
||||
|
||||
## AuthTokens
|
||||
|
||||
* id
|
||||
* uid
|
||||
* (for sessionToken)
|
||||
* email
|
||||
* emailCode
|
||||
* (for keyFetchToken)
|
||||
* kA
|
||||
* wrapKb
|
||||
* (for both)
|
||||
* verified
|
||||
|
||||
## SrpTokens
|
||||
|
||||
* id
|
||||
* uid
|
||||
* N
|
||||
* g
|
||||
* s
|
||||
* v
|
||||
* b
|
||||
* B
|
||||
* passwordStretching
|
||||
* (for authToken)
|
||||
* email
|
||||
* emailCode
|
||||
* kA
|
||||
* wrapKb
|
||||
* verified
|
||||
|
||||
## ForgotPasswordTokens
|
||||
|
||||
* id
|
||||
* uid
|
||||
* email
|
||||
* passcode
|
||||
* ttl
|
||||
* codeLength
|
||||
* tries
|
||||
|
||||
## Emails
|
||||
|
||||
* email
|
||||
* uid
|
||||
* srp
|
||||
* passwordStretching
|
||||
* (for srpToken)
|
||||
* emailCode
|
||||
* kA
|
||||
* wrapKb
|
||||
* verified
|
||||
|
||||
## Accounts
|
||||
|
||||
* uid
|
||||
* email
|
||||
* emailCode
|
||||
* sessionTokens
|
||||
* keyFetchTokens
|
||||
* srpTokens
|
||||
* authTokens
|
||||
* accountResetToken
|
||||
* forgotPasswordToken
|
|
@ -11,10 +11,6 @@ module.exports = function (log, inherits, Token, crypto, db) {
|
|||
}
|
||||
inherits(AccountResetToken, Token)
|
||||
|
||||
AccountResetToken.hydrate = function (object) {
|
||||
return Token.fill(new AccountResetToken(), object)
|
||||
}
|
||||
|
||||
AccountResetToken.create = function (uid) {
|
||||
log.trace({ op: 'AccountResetToken.create', uid: uid })
|
||||
return Token
|
||||
|
@ -28,7 +24,7 @@ module.exports = function (log, inherits, Token, crypto, db) {
|
|||
t.id = key.slice(0, 32).toString('hex')
|
||||
t._key = key.slice(32, 64).toString('hex')
|
||||
t.xorKey = key.slice(64, 352).toString('hex')
|
||||
return t.save()
|
||||
return t
|
||||
}
|
||||
)
|
||||
}
|
||||
|
@ -54,39 +50,6 @@ module.exports = function (log, inherits, Token, crypto, db) {
|
|||
)
|
||||
}
|
||||
|
||||
AccountResetToken.getCredentials = function (id, cb) {
|
||||
log.trace({ op: 'AccountResetToken.getCredentials', id: id })
|
||||
AccountResetToken.get(id)
|
||||
.done(
|
||||
function (token) {
|
||||
cb(null, token)
|
||||
},
|
||||
cb
|
||||
)
|
||||
}
|
||||
|
||||
AccountResetToken.get = function (id) {
|
||||
log.trace({ op: 'AccountResetToken.get', id: id })
|
||||
return db
|
||||
.get(id + '/reset')
|
||||
.then(AccountResetToken.hydrate)
|
||||
}
|
||||
|
||||
AccountResetToken.del = function (id) {
|
||||
log.trace({ op: 'AccountResetToken.del', id: id })
|
||||
return db.delete(id + '/reset')
|
||||
}
|
||||
|
||||
AccountResetToken.prototype.save = function () {
|
||||
log.trace({ op: 'accountResetToken.save', id: this.id })
|
||||
var self = this
|
||||
return db.set(this.id + '/reset', this).then(function () { return self })
|
||||
}
|
||||
|
||||
AccountResetToken.prototype.del = function () {
|
||||
return AccountResetToken.del(this.id)
|
||||
}
|
||||
|
||||
AccountResetToken.prototype.bundle = function (wrapKb, verifier) {
|
||||
log.trace({ op: 'accountResetToken.bundle', id: this.id })
|
||||
return this.xor(
|
||||
|
|
|
@ -9,11 +9,8 @@ module.exports = function (log, inherits, Token, db, error) {
|
|||
}
|
||||
inherits(KeyFetchToken, Token)
|
||||
|
||||
KeyFetchToken.hydrate = function (object) {
|
||||
return Token.fill(new KeyFetchToken(), object)
|
||||
}
|
||||
|
||||
KeyFetchToken.create = function (uid) {
|
||||
KeyFetchToken.create = function (authToken) {
|
||||
var uid = authToken && authToken.uid
|
||||
log.trace({ op: 'KeyFetchToken.create', uid: uid })
|
||||
return Token
|
||||
.randomTokenData('account/keys', 3 * 32 + 2 * 32)
|
||||
|
@ -27,22 +24,11 @@ module.exports = function (log, inherits, Token, db, error) {
|
|||
t._key = key.slice(32, 64).toString('hex')
|
||||
t.hmacKey = key.slice(64, 96).toString('hex')
|
||||
t.xorKey = key.slice(96, 160).toString('hex')
|
||||
return t.save()
|
||||
return t
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
KeyFetchToken.getCredentials = function (id, cb) {
|
||||
log.trace({ op: 'KeyFetchToken.getCredentials', id: id })
|
||||
KeyFetchToken.get(id)
|
||||
.done(
|
||||
function (token) {
|
||||
cb(null, token)
|
||||
},
|
||||
cb
|
||||
)
|
||||
}
|
||||
|
||||
KeyFetchToken.fromHex = function (string) {
|
||||
log.trace({ op: 'KeyFetchToken.fromHex' })
|
||||
return Token.
|
||||
|
@ -65,28 +51,6 @@ module.exports = function (log, inherits, Token, db, error) {
|
|||
)
|
||||
}
|
||||
|
||||
KeyFetchToken.get = function (id) {
|
||||
log.trace({ op: 'KeyFetchToken.get', id: id })
|
||||
return db
|
||||
.get(id + '/fetch')
|
||||
.then(KeyFetchToken.hydrate)
|
||||
}
|
||||
|
||||
KeyFetchToken.del = function (id) {
|
||||
log.trace({ op: 'KeyFetchToken.del', id: id })
|
||||
return db.delete(id + '/fetch')
|
||||
}
|
||||
|
||||
KeyFetchToken.prototype.save = function () {
|
||||
log.trace({ op: 'keyFetchToken.save', id: this.id })
|
||||
var self = this
|
||||
return db.set(this.id + '/fetch', this).then(function () { return self })
|
||||
}
|
||||
|
||||
KeyFetchToken.prototype.del = function () {
|
||||
return KeyFetchToken.del(this.id)
|
||||
}
|
||||
|
||||
KeyFetchToken.prototype.bundle = function (kA, wrapKb) {
|
||||
log.trace({ op: 'keyFetchToken.bundle', id: this.id })
|
||||
return this.bundleHexStrings([kA, wrapKb])
|
||||
|
|
|
@ -2,18 +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/. */
|
||||
|
||||
module.exports = function (log, inherits, Token, db) {
|
||||
module.exports = function (log, inherits, Token) {
|
||||
|
||||
function SessionToken() {
|
||||
Token.call(this)
|
||||
}
|
||||
inherits(SessionToken, Token)
|
||||
|
||||
SessionToken.hydrate = function (object) {
|
||||
return Token.fill(new SessionToken(), object)
|
||||
}
|
||||
|
||||
SessionToken.create = function (uid) {
|
||||
SessionToken.create = function (authToken) {
|
||||
var uid = authToken && authToken.uid
|
||||
log.trace({ op: 'SessionToken.create', uid: uid })
|
||||
return Token
|
||||
.randomTokenData('session', 2 * 32)
|
||||
|
@ -25,7 +22,7 @@ module.exports = function (log, inherits, Token, db) {
|
|||
t.data = data[0].toString('hex')
|
||||
t.id = key.slice(0, 32).toString('hex')
|
||||
t._key = key.slice(32, 64).toString('hex')
|
||||
return t.save()
|
||||
return t
|
||||
}
|
||||
)
|
||||
}
|
||||
|
@ -50,38 +47,5 @@ module.exports = function (log, inherits, Token, db) {
|
|||
)
|
||||
}
|
||||
|
||||
SessionToken.getCredentials = function (id, cb) {
|
||||
log.trace({ op: 'SessionToken.getCredentials', id: id })
|
||||
SessionToken.get(id)
|
||||
.done(
|
||||
function (token) {
|
||||
cb(null, token)
|
||||
},
|
||||
cb
|
||||
)
|
||||
}
|
||||
|
||||
SessionToken.get = function (id) {
|
||||
log.trace({ op: 'SessionToken.get', id: id })
|
||||
return db
|
||||
.get(id + '/session')
|
||||
.then(SessionToken.hydrate)
|
||||
}
|
||||
|
||||
SessionToken.del = function (id) {
|
||||
log.trace({ op: 'SessionToken.del', id: id })
|
||||
return db.delete(id + '/session')
|
||||
}
|
||||
|
||||
SessionToken.prototype.save = function () {
|
||||
log.trace({ op: 'sessionToken.save', id: this.id })
|
||||
var self = this
|
||||
return db.set(this.id + '/session', this).then(function () { return self })
|
||||
}
|
||||
|
||||
SessionToken.prototype.del = function () {
|
||||
return SessionToken.del(this.id)
|
||||
}
|
||||
|
||||
return SessionToken
|
||||
}
|
||||
|
|
|
@ -6,6 +6,18 @@ module.exports = function (log, crypto, uuid, isA, error, Account, RecoveryEmail
|
|||
|
||||
const HEX_STRING = /^(?:[a-fA-F0-9]{2})+$/
|
||||
|
||||
function sendVerifyCode(email, emailCode) {
|
||||
//TODO
|
||||
}
|
||||
|
||||
function bundleKeys(keyFetchToken, kA, wrapKb) {
|
||||
|
||||
}
|
||||
|
||||
function unbundleReset(bundle) {
|
||||
|
||||
}
|
||||
|
||||
var routes = [
|
||||
{
|
||||
method: 'POST',
|
||||
|
@ -36,15 +48,35 @@ module.exports = function (log, crypto, uuid, isA, error, Account, RecoveryEmail
|
|||
handler: function accountCreate(request) {
|
||||
log.begin('Account.create', request)
|
||||
var form = request.payload
|
||||
Account
|
||||
.create(
|
||||
{
|
||||
uid: uuid.v4(),
|
||||
email: form.email,
|
||||
srp: form.srp,
|
||||
kA: crypto.randomBytes(32).toString('hex'),
|
||||
wrapKb: crypto.randomBytes(32).toString('hex'),
|
||||
passwordStretching: form.passwordStretching
|
||||
db.accountExists(form.email)
|
||||
.then(
|
||||
function (exists) {
|
||||
if (exists) {
|
||||
throw error.accountExists(form.email)
|
||||
}
|
||||
}
|
||||
)
|
||||
.then(
|
||||
db.createAccount.bind(
|
||||
db,
|
||||
{
|
||||
uid: uuid.v4(),
|
||||
email: form.email,
|
||||
emailCode: crypto.randomBytes(4).toString('hex'),
|
||||
verified: false,
|
||||
srp: form.srp,
|
||||
kA: crypto.randomBytes(32).toString('hex'),
|
||||
wrapKb: crypto.randomBytes(32).toString('hex'),
|
||||
passwordStretching: form.passwordStretching,
|
||||
devices: {},
|
||||
accountResetToken: null,
|
||||
forgotPasswordToken: null
|
||||
}
|
||||
)
|
||||
)
|
||||
.then(
|
||||
function (account) {
|
||||
return sendVerifyCode(account.email, account.emailCode)
|
||||
}
|
||||
)
|
||||
.done(
|
||||
|
@ -73,13 +105,12 @@ module.exports = function (log, crypto, uuid, isA, error, Account, RecoveryEmail
|
|||
handler: function (request) {
|
||||
log.begin('Account.devices', request)
|
||||
var sessionToken = request.auth.credentials
|
||||
Account
|
||||
.get(sessionToken.uid)
|
||||
db.accountDevices(sessionToken.uid)
|
||||
.done(
|
||||
function (account) {
|
||||
function (devices) {
|
||||
request.reply(
|
||||
{
|
||||
devices: Object.keys(account.sessionTokenIds)
|
||||
devices: Object.keys(devices)
|
||||
}
|
||||
)
|
||||
},
|
||||
|
@ -118,20 +149,18 @@ module.exports = function (log, crypto, uuid, isA, error, Account, RecoveryEmail
|
|||
log.begin('Account.keys', request)
|
||||
var reply = request.reply.bind(request)
|
||||
var keyFetchToken = request.auth.credentials
|
||||
|
||||
keyFetchToken
|
||||
.del()
|
||||
.then(Account.get.bind(null, keyFetchToken.uid))
|
||||
db.deleteKeyFetchToken(keyFetchToken)
|
||||
.then(
|
||||
function (account) {
|
||||
if (!account) {
|
||||
throw error.unknownAccount()
|
||||
}
|
||||
if (!account.verified) {
|
||||
function () {
|
||||
if (!keyFetchToken.verified) {
|
||||
throw error.unverifiedAccount()
|
||||
}
|
||||
return {
|
||||
bundle: keyFetchToken.bundle(account.kA, account.wrapKb)
|
||||
bundle: bundleKeys(
|
||||
keyFetchToken,
|
||||
keyFetchToken.kA,
|
||||
keyFetchToken.wrapKb
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
@ -152,21 +181,12 @@ module.exports = function (log, crypto, uuid, isA, error, Account, RecoveryEmail
|
|||
handler: function (request) {
|
||||
log.begin('Account.RecoveryEmailStatus', request)
|
||||
var sessionToken = request.auth.credentials
|
||||
Account
|
||||
.get(sessionToken.uid)
|
||||
.done(
|
||||
function (account) {
|
||||
request.reply(
|
||||
{
|
||||
email: account.email,
|
||||
verified: account.verified
|
||||
}
|
||||
)
|
||||
},
|
||||
function (err) {
|
||||
request.reply(err)
|
||||
}
|
||||
)
|
||||
request.reply(
|
||||
{
|
||||
email: sessionToken.email,
|
||||
verified: sessionToken.verified
|
||||
}
|
||||
)
|
||||
},
|
||||
validate: {
|
||||
response: {
|
||||
|
@ -192,24 +212,13 @@ module.exports = function (log, crypto, uuid, isA, error, Account, RecoveryEmail
|
|||
handler: function (request) {
|
||||
log.begin('Account.RecoveryEmailResend', request)
|
||||
var sessionToken = request.auth.credentials
|
||||
Account
|
||||
.get(sessionToken.uid)
|
||||
sendVerifyCode(sessionToken.email, sessionToken.emailCode)
|
||||
.done(
|
||||
function (account) {
|
||||
return account.primaryRecoveryEmail()
|
||||
.then(
|
||||
function (rm) {
|
||||
return rm.sendVerifyCode()
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
request.reply({})
|
||||
},
|
||||
function (err) {
|
||||
request.reply(err)
|
||||
}
|
||||
)
|
||||
function () {
|
||||
request.reply({})
|
||||
},
|
||||
function (err) {
|
||||
request.reply(err)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
@ -226,24 +235,13 @@ module.exports = function (log, crypto, uuid, isA, error, Account, RecoveryEmail
|
|||
log.begin('Account.RecoveryEmailVerify', request)
|
||||
var uid = request.payload.uid
|
||||
var code = request.payload.code
|
||||
RecoveryEmail
|
||||
.get(uid, code)
|
||||
db.account(uid)
|
||||
.then(
|
||||
function (rm) {
|
||||
if (! rm) {
|
||||
function (account) {
|
||||
if (code !== account.code) {
|
||||
throw error.invalidVerificationCode()
|
||||
}
|
||||
return rm
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (rm) {
|
||||
return rm.verify(code)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (rm) {
|
||||
return Account.verify(rm)
|
||||
return db.verifyEmail(account)
|
||||
}
|
||||
)
|
||||
.done(
|
||||
|
@ -287,18 +285,11 @@ module.exports = function (log, crypto, uuid, isA, error, Account, RecoveryEmail
|
|||
var reply = request.reply.bind(request)
|
||||
var accountResetToken = request.auth.credentials
|
||||
var payload = request.payload
|
||||
var unbundle = accountResetToken.unbundle(payload.bundle)
|
||||
var unbundle = unbundleReset(payload.bundle)
|
||||
payload.wrapKb = unbundle.wrapKb
|
||||
payload.srp.verifier = unbundle.verifier
|
||||
|
||||
accountResetToken
|
||||
.del()
|
||||
.then(Account.get.bind(null, accountResetToken.uid))
|
||||
.then(
|
||||
function (account) {
|
||||
return account.reset(payload)
|
||||
}
|
||||
)
|
||||
db.resetAccount(accountResetToken, payload)
|
||||
.then(function () { return {} })
|
||||
.done(reply, reply)
|
||||
},
|
||||
|
@ -316,13 +307,8 @@ module.exports = function (log, crypto, uuid, isA, error, Account, RecoveryEmail
|
|||
log.begin('Account.destroy', request)
|
||||
var reply = request.reply.bind(request)
|
||||
var authToken = request.auth.credentials
|
||||
|
||||
authToken.del()
|
||||
.then(
|
||||
function () {
|
||||
return Account.del(authToken.uid)
|
||||
}
|
||||
)
|
||||
db.deleteAccount(authToken)
|
||||
.then(function () { return {} })
|
||||
.done(reply, reply)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,14 @@ module.exports = function (log, isA, error, Account, SrpSession, AuthBundle) {
|
|||
|
||||
const HEX_STRING = /^(?:[a-fA-F0-9]{2})+$/
|
||||
|
||||
function clientData(srpToken) {
|
||||
|
||||
}
|
||||
|
||||
function bundleAuth(k, authToken) {
|
||||
|
||||
}
|
||||
|
||||
var routes = [
|
||||
{
|
||||
method: 'POST',
|
||||
|
@ -19,8 +27,17 @@ module.exports = function (log, isA, error, Account, SrpSession, AuthBundle) {
|
|||
handler: function (request) {
|
||||
log.begin('Auth.start', request)
|
||||
var reply = request.reply.bind(request)
|
||||
Account.getByEmail(request.payload.email)
|
||||
.then(SrpSession.start.bind(null))
|
||||
db.emailRecord(request.payload.email)
|
||||
.then(
|
||||
function (emailRecord) {
|
||||
return db.createSrpToken(emailRecord)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (srpToken) {
|
||||
return clientData(srpToken)
|
||||
}
|
||||
)
|
||||
.done(reply, reply)
|
||||
},
|
||||
validate: {
|
||||
|
@ -53,11 +70,21 @@ module.exports = function (log, isA, error, Account, SrpSession, AuthBundle) {
|
|||
handler: function (request) {
|
||||
log.begin('Auth.finish', request)
|
||||
var reply = request.reply.bind(request)
|
||||
SrpSession
|
||||
.finish(request.payload.srpToken, request.payload.A, request.payload.M)
|
||||
|
||||
db.srpToken(request.payload.srpToken)
|
||||
.then(
|
||||
function (srpSession) {
|
||||
return AuthBundle.login(srpSession.K, srpSession.uid)
|
||||
function (srpToken) {
|
||||
return srpFinish(srpToken, request.payload.A, request.payload.M)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (srpToken) {
|
||||
return db.authFinish(srpToken)
|
||||
.then(
|
||||
function (authToken) {
|
||||
return bundleAuth(srpToken.K, authToken)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
.done(reply, reply)
|
||||
|
|
|
@ -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, P, kv) {
|
||||
module.exports = function (log, P, db) {
|
||||
|
||||
var routes = [
|
||||
{
|
||||
|
@ -21,7 +21,7 @@ module.exports = function (log, P, kv) {
|
|||
config: {
|
||||
handler: function heartbeat(request) {
|
||||
log.begin('Defaults.heartbeat', request)
|
||||
P.all([kv.store.ping(), kv.cache.ping()])
|
||||
db.ping()
|
||||
.then(
|
||||
function () {
|
||||
request.reply({})
|
||||
|
|
|
@ -15,16 +15,16 @@ module.exports = function (
|
|||
log,
|
||||
serverPublicKey,
|
||||
signer,
|
||||
models,
|
||||
db,
|
||||
config
|
||||
) {
|
||||
var auth = require('./auth')(log, isA, error, models.Account, models.SrpSession, models.AuthBundle)
|
||||
var defaults = require('./defaults')(log, P, models.dbs)
|
||||
var defaults = require('./defaults')(log, P, db)
|
||||
var idp = require('./idp')(log, crypto, error, isA, serverPublicKey, config.bridge)
|
||||
var account = require('./account')(log, crypto, uuid, isA, error, models.Account, models.RecoveryEmail)
|
||||
var password = require('./password')(log, isA, error, models.Account, models.tokens)
|
||||
var session = require('./session')(log, isA, error, models.Account, models.tokens)
|
||||
var sign = require('./sign')(log, isA, error, signer, models.Account)
|
||||
var sign = require('./sign')(log, isA, error, signer, config.domain)
|
||||
var util = require('./util')(log, crypto, error, isA, serverPublicKey, config.bridge)
|
||||
var raw = require('./rawpassword')(log, isA, error, config, Client)
|
||||
|
||||
|
|
|
@ -2,10 +2,26 @@
|
|||
* 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, isA, error, Account, tokens) {
|
||||
module.exports = function (log, isA, error, db) {
|
||||
|
||||
const HEX_STRING = /^(?:[a-fA-F0-9]{2})+$/
|
||||
|
||||
function bundleAccountReset(authToken, keyFetchToken, accountResetToken) {
|
||||
//TODO
|
||||
}
|
||||
|
||||
function sendRecoveryCode(forgotPasswordToken) {
|
||||
//TODO
|
||||
}
|
||||
|
||||
function ttl(forgotPasswordToken) {
|
||||
|
||||
}
|
||||
|
||||
function failAttempt(forgotPasswordToken) {
|
||||
|
||||
}
|
||||
|
||||
var routes = [
|
||||
{
|
||||
method: 'POST',
|
||||
|
@ -20,26 +36,11 @@ module.exports = function (log, isA, error, Account, tokens) {
|
|||
log.begin('Password.changeStart', request)
|
||||
var reply = request.reply.bind(request)
|
||||
var authToken = request.auth.credentials
|
||||
var keyFetchToken = null
|
||||
var accountResetToken = null
|
||||
authToken.del()
|
||||
db.createPasswordChange(authToken)
|
||||
.then(
|
||||
function () {
|
||||
return tokens.KeyFetchToken.create(authToken.uid)
|
||||
}
|
||||
)
|
||||
.then(function (t) { keyFetchToken = t })
|
||||
.then(tokens.AccountResetToken.create.bind(null, authToken.uid))
|
||||
.then(function (t) { accountResetToken = t })
|
||||
.then(Account.get.bind(null, authToken.uid))
|
||||
.then(
|
||||
function (account) {
|
||||
return account.setResetToken(accountResetToken)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
return authToken.bundleAccountReset(
|
||||
return bundleAccountReset(
|
||||
authToken,
|
||||
keyFetchToken,
|
||||
accountResetToken
|
||||
)
|
||||
|
@ -66,22 +67,15 @@ module.exports = function (log, isA, error, Account, tokens) {
|
|||
handler: function (request) {
|
||||
log.begin('Password.forgotSend', request)
|
||||
var email = request.payload.email
|
||||
var forgotPasswordToken = null
|
||||
Account.getByEmail(email)
|
||||
db.emailRecord(email)
|
||||
.then(
|
||||
function (account) {
|
||||
return tokens.ForgotPasswordToken.create(account.uid, account.email)
|
||||
.then(
|
||||
function (token) {
|
||||
forgotPasswordToken = token
|
||||
return account.setForgotPasswordToken(token)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
return forgotPasswordToken.sendRecoveryCode()
|
||||
}
|
||||
)
|
||||
function (emailRecord) {
|
||||
return db.createForgotPasswordToken(emailRecord)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (forgotPasswordToken) {
|
||||
return sendRecoveryCode(forgotPasswordToken)
|
||||
}
|
||||
)
|
||||
.done(
|
||||
|
@ -89,8 +83,8 @@ module.exports = function (log, isA, error, Account, tokens) {
|
|||
request.reply(
|
||||
{
|
||||
forgotPasswordToken: forgotPasswordToken.data,
|
||||
ttl: forgotPasswordToken.ttl(),
|
||||
codeLength: 8,
|
||||
ttl: ttl(forgotPasswordToken),
|
||||
codeLength: forgotPasswordToken.passcode.length,
|
||||
tries: forgotPasswordToken.tries
|
||||
}
|
||||
)
|
||||
|
@ -128,14 +122,14 @@ module.exports = function (log, isA, error, Account, tokens) {
|
|||
handler: function (request) {
|
||||
log.begin('Password.forgotResend', request)
|
||||
var forgotPasswordToken = request.auth.credentials
|
||||
forgotPasswordToken.sendRecoveryCode()
|
||||
sendRecoveryCode(forgotPasswordToken)
|
||||
.done(
|
||||
function () {
|
||||
request.reply(
|
||||
{
|
||||
forgotPasswordToken: forgotPasswordToken.data,
|
||||
ttl: forgotPasswordToken.ttl(),
|
||||
codeLength: 8,
|
||||
ttl: forgotPasswordToken.ttl(forgotPasswordToken),
|
||||
codeLength: ttl(forgotPasswordToken),
|
||||
tries: forgotPasswordToken.tries
|
||||
}
|
||||
)
|
||||
|
@ -174,19 +168,10 @@ module.exports = function (log, isA, error, Account, tokens) {
|
|||
log.begin('Password.forgotVerify', request)
|
||||
var forgotPasswordToken = request.auth.credentials
|
||||
var code = +(request.payload.code)
|
||||
var accountResetToken = null
|
||||
if (forgotPasswordToken.code === code && forgotPasswordToken.ttl() > 0) {
|
||||
forgotPasswordToken.del()
|
||||
.then(tokens.AccountResetToken.create.bind(null, forgotPasswordToken.uid))
|
||||
.then(function (t) { accountResetToken = t })
|
||||
.then(Account.get.bind(null, forgotPasswordToken.uid))
|
||||
.then(
|
||||
function (account) {
|
||||
return account.setResetToken(accountResetToken)
|
||||
}
|
||||
)
|
||||
if (forgotPasswordToken.code === code && ttl(forgotPasswordToken) > 0) {
|
||||
db.forgotPasswordVerified(forgotPasswordToken)
|
||||
.done(
|
||||
function () {
|
||||
function (accountResetToken) {
|
||||
request.reply(
|
||||
{
|
||||
accountResetToken: accountResetToken.data
|
||||
|
@ -199,7 +184,7 @@ module.exports = function (log, isA, error, Account, tokens) {
|
|||
)
|
||||
}
|
||||
else {
|
||||
forgotPasswordToken.failAttempt()
|
||||
failAttempt(forgotPasswordToken)
|
||||
.done(
|
||||
function (t) {
|
||||
request.reply(
|
||||
|
|
|
@ -2,10 +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/. */
|
||||
|
||||
module.exports = function (log, isA, error, Account, tokens) {
|
||||
module.exports = function (log, isA, error, db) {
|
||||
|
||||
const HEX_STRING = /^(?:[a-fA-F0-9]{2})+$/
|
||||
|
||||
function bundleSession(authToken, keyFetchToken, sessionToken) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
var routes = [
|
||||
{
|
||||
method: 'POST',
|
||||
|
@ -20,26 +24,14 @@ module.exports = function (log, isA, error, Account, tokens) {
|
|||
log.begin('Session.create', request)
|
||||
var reply = request.reply.bind(request)
|
||||
var authToken = request.auth.credentials
|
||||
var keyFetchToken = null
|
||||
var sessionToken = null
|
||||
authToken.del()
|
||||
db.createSession(authToken)
|
||||
.then(
|
||||
function () {
|
||||
return tokens.KeyFetchToken.create(authToken.uid)
|
||||
}
|
||||
)
|
||||
.then(function (t) { keyFetchToken = t })
|
||||
.then(tokens.SessionToken.create.bind(null, authToken.uid))
|
||||
.then(function (t) { sessionToken = t })
|
||||
.then(Account.get.bind(null, authToken.uid))
|
||||
.then(
|
||||
function (account) {
|
||||
return account.addSessionToken(sessionToken)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function () {
|
||||
return authToken.bundleSession(keyFetchToken, sessionToken)
|
||||
function (tokens) {
|
||||
return bundleSession(
|
||||
authToken,
|
||||
tokens.keyFetchToken,
|
||||
tokens.sessionToken
|
||||
)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
|
@ -65,17 +57,7 @@ module.exports = function (log, isA, error, Account, tokens) {
|
|||
handler: function (request) {
|
||||
log.begin('Session.destroy', request)
|
||||
var sessionToken = request.auth.credentials
|
||||
sessionToken.del()
|
||||
.then(
|
||||
function () {
|
||||
return Account.get(sessionToken.uid)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (account) {
|
||||
return account.deleteSessionToken(sessionToken.id)
|
||||
}
|
||||
)
|
||||
db.deleteSessionToken(sessionToken)
|
||||
.done(
|
||||
function () {
|
||||
request.reply({})
|
||||
|
|
|
@ -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, isA, error, signer, Account) {
|
||||
module.exports = function (log, isA, error, signer, domain) {
|
||||
|
||||
const HOUR = 1000 * 60 * 60
|
||||
|
||||
|
@ -32,38 +32,32 @@ module.exports = function (log, isA, error, signer, Account) {
|
|||
},
|
||||
handler: function certificateSign(request) {
|
||||
log.begin('Sign.cert', request)
|
||||
var uid = request.auth.credentials.uid
|
||||
Account
|
||||
.get(uid)
|
||||
.done(
|
||||
function (account) {
|
||||
if (!account.verified) {
|
||||
return request.reply(error.unverifiedAccount())
|
||||
}
|
||||
signer.enqueue(
|
||||
{
|
||||
email: Account.principal(uid),
|
||||
publicKey: JSON.stringify(request.payload.publicKey),
|
||||
duration: request.payload.duration
|
||||
},
|
||||
function (err, result) {
|
||||
if (err || result.err) {
|
||||
request.reply(
|
||||
// XXX TODO: differentiate backlog overflow (503)
|
||||
// from a generic server-side failure (500)
|
||||
error.serviceUnavailable(
|
||||
'Unable to sign certificate',
|
||||
err || result.err
|
||||
)
|
||||
)
|
||||
}
|
||||
else {
|
||||
request.reply(result)
|
||||
}
|
||||
}
|
||||
var sessionToken = request.auth.credentials
|
||||
if (!sessionToken.verified) {
|
||||
return request.reply(error.unverifiedAccount())
|
||||
}
|
||||
signer.enqueue(
|
||||
{
|
||||
email: uid + '@' + domain,
|
||||
publicKey: JSON.stringify(request.payload.publicKey),
|
||||
duration: request.payload.duration
|
||||
},
|
||||
function (err, result) {
|
||||
if (err || result.err) {
|
||||
request.reply(
|
||||
// XXX TODO: differentiate backlog overflow (503)
|
||||
// from a generic server-side failure (500)
|
||||
error.serviceUnavailable(
|
||||
'Unable to sign certificate',
|
||||
err || result.err
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
else {
|
||||
request.reply(result)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
module.exports = function (path, url, Hapi, toobusy, error) {
|
||||
|
||||
function create(log, config, routes, tokens) {
|
||||
function create(log, config, routes, db) {
|
||||
|
||||
// Hawk needs to calculate request signatures based on public URL,
|
||||
// not the local URL to which it is bound.
|
||||
|
@ -18,6 +18,17 @@ module.exports = function (path, url, Hapi, toobusy, error) {
|
|||
port: publicURL.port ? publicURL.port : defaultPorts[publicURL.protocol]
|
||||
}
|
||||
|
||||
function makeCredentialFn(dbGetFn) {
|
||||
return function (id, cb) {
|
||||
log.trace({ op: 'db.' + dbGetFn.name, id: id })
|
||||
dbGetFn(id)
|
||||
.done(
|
||||
cb.bind(null, null),
|
||||
cb
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
var server = Hapi.createServer(
|
||||
config.bind_to.host,
|
||||
config.bind_to.port,
|
||||
|
@ -26,27 +37,27 @@ module.exports = function (path, url, Hapi, toobusy, error) {
|
|||
sessionToken: {
|
||||
scheme: 'hawk',
|
||||
hawk: hawkOptions,
|
||||
getCredentialsFunc: tokens.SessionToken.getCredentials
|
||||
getCredentialsFunc: makeCredentialFn(db.sessionToken)
|
||||
},
|
||||
keyFetchToken: {
|
||||
scheme: 'hawk',
|
||||
hawk: hawkOptions,
|
||||
getCredentialsFunc: tokens.KeyFetchToken.getCredentials
|
||||
getCredentialsFunc: makeCredentialFn(db.keyFetchToken)
|
||||
},
|
||||
accountResetToken: {
|
||||
scheme: 'hawk',
|
||||
hawk: hawkOptions,
|
||||
getCredentialsFunc: tokens.AccountResetToken.getCredentials
|
||||
getCredentialsFunc: makeCredentialFn(db.accountResetToken)
|
||||
},
|
||||
authToken: {
|
||||
scheme: 'hawk',
|
||||
hawk: hawkOptions,
|
||||
getCredentialsFunc: tokens.AuthToken.getCredentials
|
||||
getCredentialsFunc: makeCredentialFn(db.authToken)
|
||||
},
|
||||
forgotPasswordToken: {
|
||||
scheme: 'hawk',
|
||||
hawk: hawkOptions,
|
||||
getCredentialsFunc: tokens.ForgotPasswordToken.getCredentials
|
||||
getCredentialsFunc: makeCredentialFn(db.forgotPasswordToken)
|
||||
}
|
||||
},
|
||||
cors: true,
|
||||
|
|
Загрузка…
Ссылка в новой задаче