diff --git a/bin/key_server.js b/bin/key_server.js index 602ba2a3..63b804b3 100644 --- a/bin/key_server.js +++ b/bin/key_server.js @@ -40,10 +40,6 @@ function main() { var signer = new CC({ module: __dirname + '/signer.js' }) signer.on('error', function () {}) // don't die - // client_heklper compute-cluster - var clientHelper = new CC({ module: __dirname + '/client_helper.js' }) - clientHelper.on('error', function () {}) // don't die - var Server = require('../server') var server = null // TODO: send to the SMTP server directly. In the future this may change @@ -58,11 +54,9 @@ function main() { config.db.backend, log, Token.error, - Token.AuthToken, Token.SessionToken, Token.KeyFetchToken, Token.AccountResetToken, - Token.SrpToken, Token.PasswordForgotToken, Token.PasswordChangeToken ) @@ -86,7 +80,7 @@ function main() { function (backends) { var db = backends[0] var noncedb = backends[1] - var routes = require('../routes')(log, error, serverPublicKey, signer, clientHelper, db, mailer, Token, config) + var routes = require('../routes')(log, error, serverPublicKey, signer, db, mailer, config) server = Server.create(log, error, config, routes, db, noncedb, i18n) server.start( diff --git a/db/heap.js b/db/heap.js index 7335b494..008ac834 100644 --- a/db/heap.js +++ b/db/heap.js @@ -7,11 +7,9 @@ var P = require('p-promise') module.exports = function ( log, error, - AuthToken, SessionToken, KeyFetchToken, AccountResetToken, - SrpToken, PasswordForgotToken, PasswordChangeToken ) { @@ -20,8 +18,6 @@ module.exports = function ( this.sessionTokens = {} this.keyFetchTokens = {} this.accountResetTokens = {} - this.authTokens = {} - this.srpTokens = {} this.passwordForgotTokens = {} this.passwordChangeTokens = {} this.accounts = {} @@ -106,18 +102,6 @@ module.exports = function ( .then(saveTo(this.accountResetTokens)) } - Heap.prototype.createAuthToken = function (srpToken) { - log.trace({ op: 'Heap.createAuthToken', uid: srpToken && srpToken.uid }) - return AuthToken.create(srpToken) - .then(saveTo(this.authTokens)) - } - - Heap.prototype.createSrpToken = function (emailRecord) { - log.trace({ op: 'Heap.createSrpToken', uid: emailRecord && emailRecord.uid }) - return SrpToken.create(emailRecord) - .then(saveTo(this.srpTokens)) - } - Heap.prototype.createPasswordForgotToken = function (emailRecord) { log.trace({ op: 'Heap.createPasswordForgotToken', uid: emailRecord && emailRecord.uid }) return PasswordForgotToken.create(emailRecord) @@ -198,23 +182,6 @@ module.exports = function ( return P(accountResetToken) } - Heap.prototype.authToken = function (id) { - log.trace({ op: 'Heap.authToken', id: id }) - var authToken = this.authTokens[id.toString('hex')] - if (!authToken) { return P.reject(error.invalidToken()) } - var account = this.accounts[authToken.uid.toString('hex')] - if (!account) { return P.reject(error.unknownAccount()) } - authToken.verified = account.verified - return P(authToken) - } - - Heap.prototype.srpToken = function (id) { - log.trace({ op: 'Heap.srpToken', id: id }) - var srpToken = this.srpTokens[id.toString('hex')] - if (!srpToken) { return P.reject(error.invalidToken()) } - return P(srpToken) - } - Heap.prototype.passwordForgotToken = function (id) { log.trace({ op: 'Heap.passwordForgotToken', id: id }) var passwordForgotToken = this.passwordForgotTokens[id.toString('hex')] @@ -261,8 +228,6 @@ module.exports = function ( if (!account) { return P.reject(error.unknownAccount()) } 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.passwordForgotTokens) delete this.emailRecords[account.email] @@ -309,30 +274,6 @@ module.exports = function ( return P(true) } - Heap.prototype.deleteAuthToken = function (authToken) { - log.trace( - { - op: 'Heap.deleteAuthToken', - id: authToken && authToken.id, - uid: authToken && authToken.uid - } - ) - delete this.authTokens[authToken.id] - return P(true) - } - - Heap.prototype.deleteSrpToken = function (srpToken) { - log.trace( - { - op: 'Heap.deleteSrpToken', - id: srpToken && srpToken.id, - uid: srpToken && srpToken.uid - } - ) - delete this.srpTokens[srpToken.id] - return P(true) - } - Heap.prototype.deletePasswordForgotToken = function (passwordForgotToken) { log.trace( { @@ -371,67 +312,17 @@ module.exports = function ( account.passwordForgotToken = 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.passwordForgotTokens) return P(true) } - Heap.prototype.authFinish = function (srpToken) { - log.trace({ op: 'Heap.authFinish', uid: srpToken && srpToken.uid }) - return this.deleteSrpToken(srpToken) - .then(this.createAuthToken.bind(this, srpToken)) - } - - Heap.prototype.createSession = function (authToken) { - log.trace({ op: 'Heap.createSession', uid: authToken && authToken.uid }) - return this.deleteAuthToken(authToken) - .then( - function () { - return P.all([ - this.createKeyFetchToken(authToken), - this.createSessionToken(authToken) - ]) - }.bind(this) - ) - .then( - function (tokens) { - return { - keyFetchToken: tokens[0], - sessionToken: tokens[1] - } - } - ) - } - Heap.prototype.verifyEmail = function (account) { log.trace({ op: 'Heap.verifyEmail', uid: account && account.uid }) account.verified = true return P(true) } - Heap.prototype.createPasswordChange = function (authToken) { - log.trace({ op: 'Heap.createPasswordChange', uid: authToken && authToken.uid }) - return this.deleteAuthToken(authToken) - .then( - function () { - return P.all([ - this.createKeyFetchToken(authToken), - this.createAccountResetToken(authToken) - ]) - }.bind(this) - ) - .then( - function (tokens) { - return { - keyFetchToken: tokens[0], - accountResetToken: tokens[1] - } - } - ) - } - Heap.prototype.forgotPasswordVerified = function (passwordForgotToken) { log.trace({ op: 'Heap.forgotPasswordVerified', uid: passwordForgotToken && passwordForgotToken.uid }) return this.deletePasswordForgotToken(passwordForgotToken) diff --git a/db/index.js b/db/index.js index cd386054..2576a1ac 100644 --- a/db/index.js +++ b/db/index.js @@ -6,11 +6,9 @@ module.exports = function ( backend, log, error, - AuthToken, SessionToken, KeyFetchToken, AccountResetToken, - SrpToken, PasswordForgotToken, PasswordChangeToken) { @@ -18,11 +16,9 @@ module.exports = function ( return require('./mysql')( log, error, - AuthToken, SessionToken, KeyFetchToken, AccountResetToken, - SrpToken, PasswordForgotToken, PasswordChangeToken ) @@ -31,11 +27,9 @@ module.exports = function ( return require('./heap')( log, error, - AuthToken, SessionToken, KeyFetchToken, AccountResetToken, - SrpToken, PasswordForgotToken, PasswordChangeToken ) diff --git a/db/mysql.js b/db/mysql.js index 0bc9fa15..1a50063b 100644 --- a/db/mysql.js +++ b/db/mysql.js @@ -9,11 +9,9 @@ var schema = require('fs').readFileSync(__dirname + '/schema.sql', { encoding: ' module.exports = function ( log, error, - AuthToken, SessionToken, KeyFetchToken, AccountResetToken, - SrpToken, PasswordForgotToken, PasswordChangeToken ) { @@ -235,55 +233,6 @@ module.exports = function ( }.bind(this)) } - MySql.prototype.createAuthToken = function (srpToken) { - log.trace({ op: 'MySql.createAuthToken', uid: srpToken && srpToken.uid }) - var sql = 'INSERT INTO authTokens (tokenid, tokendata, uid) VALUES (?, ?, ?)' - var con - return this.getMasterConnection() - .then(function(thisCon) { - con = thisCon - return AuthToken.create(srpToken) - }) - .then(function(authToken) { - var d = P.defer() - con.query( - sql, - [authToken.tokenid, authToken.data, authToken.uid], - function (err) { - con.release() - if (err) return d.reject(err) - d.resolve(authToken) - } - ) - return d.promise - }.bind(this)) - } - - MySql.prototype.createSrpToken = function (emailRecord) { - log.trace({ op: 'MySql.createSrpToken', uid: emailRecord && emailRecord.uid }) - var sql = 'INSERT INTO srpTokens (tokenid, tokendata, uid) VALUES (?, ?, ?)' - - var con - return this.getMasterConnection() - .then(function(thisCon) { - con = thisCon - return SrpToken.create(emailRecord) - }) - .then(function (srpToken) { - var d = P.defer() - con.query( - sql, - [srpToken.tokenid, srpToken.data, srpToken.uid], - function (err) { - con.release() - if (err) return d.reject(err) - d.resolve(srpToken) - } - ) - return d.promise - }.bind(this)) - } - MySql.prototype.createPasswordForgotToken = function (emailRecord) { log.trace({ op: 'MySql.createPasswordForgotToken', uid: emailRecord && emailRecord.uid }) var sql = 'REPLACE INTO passwordForgotTokens (tokenid, tokendata, uid, passcode, created, tries) VALUES (?, ?, ?, ?, ?, ?)' @@ -464,64 +413,6 @@ module.exports = function ( }) } - MySql.prototype.authToken = function (id) { - log.trace({ op: 'MySql.authToken', id: id }) - var sql = 'SELECT t.uid, t.tokendata, a.verified' + - ' FROM authTokens t, accounts a' + - ' WHERE t.tokenid = ? AND t.uid = a.uid' - return this.getSlaveConnection() - .then(function(con) { - var d = P.defer() - con.query( - sql, - [id], - function (err, results) { - con.release() - if (err) return d.reject(err) - if (!results.length) return d.reject(error.invalidToken()) - var result = results[0] - AuthToken.fromHex(result.tokendata, result) - .done( - function (authToken) { - return d.resolve(authToken) - } - ) - } - ) - return d.promise - }) - } - - MySql.prototype.srpToken = function (id) { - log.trace({ op: 'MySql.srpToken', id: id }) - var sql = 'SELECT t.tokendata, t.uid, a.srp, a.passwordStretching ' + - ' FROM srpTokens t, accounts a ' + - ' WHERE t.tokenid = ? AND t.uid = a.uid' - return this.getSlaveConnection() - .then(function(con) { - var d = P.defer() - con.query( - sql, - [id], - function (err, results) { - con.release() - if (err) return d.reject(err) - if (!results.length) return d.reject(error.invalidToken()) - var result = results[0] - result.srp = JSON.parse(result.srp) - result.passwordStretching = JSON.parse(result.passwordStretching) - SrpToken.fromHex(result.tokendata, result) - .done( - function (srpToken) { - return d.resolve(srpToken) - } - ) - } - ) - return d.promise - }) - } - MySql.prototype.passwordForgotToken = function (id) { log.trace({ op: 'MySql.passwordForgotToken', id: id }) var sql = 'SELECT t.tokendata, t.uid, a.email, t.passcode, t.created, t.tries ' + @@ -760,56 +651,6 @@ module.exports = function ( }) } - MySql.prototype.deleteAuthToken = function (authToken) { - log.trace( - { - op: 'MySql.deleteAuthToken', - id: authToken && authToken.tokenid, - uid: authToken && authToken.uid - } - ) - var sql = 'DELETE FROM authTokens WHERE tokenid = ?' - return this.getMasterConnection() - .then(function(con) { - var d = P.defer() - con.query( - sql, - [authToken.tokenid], - function (err) { - con.release() - if (err) return d.reject(err) - d.resolve(true) - } - ) - return d.promise - }) - } - - MySql.prototype.deleteSrpToken = function (srpToken) { - log.trace( - { - op: 'MySql.deleteSrpToken', - id: srpToken && srpToken.tokenid, - uid: srpToken && srpToken.uid - } - ) - var sql = 'DELETE FROM srpTokens WHERE tokenid = ?' - return this.getMasterConnection() - .then(function(con) { - var d = P.defer() - con.query( - sql, - [srpToken.tokenid], - function (err) { - con.release() - if (err) return d.reject(err) - d.resolve(true) - } - ) - return d.promise - }) - } - MySql.prototype.deletePasswordForgotToken = function (passwordForgotToken) { log.trace( { @@ -905,126 +746,6 @@ module.exports = function ( }) } - MySql.prototype.authFinish = function (srpToken) { - log.trace({ op: 'MySql.authFinish', uid: srpToken && srpToken.uid }) - // Order of events: - // (1) make an AuthToken - // (2) get a connection - // (3) start a transaction - // (4) delete from srpTokens - // (5) insert into authTokens - // (6) commit transaction - // (7) release connection - // (8) resolve with the new authToken - var con - var authToken - return this.getMasterConnection() - .then(function(thisCon) { - con = thisCon - return beginTransaction(con) - }) - .then(function() { - return AuthToken.create(srpToken) - }) - .then(function (newAuthToken) { - authToken = newAuthToken - var d = P.defer() - con.query( - 'DELETE FROM srpTokens WHERE tokenid = ?', - [srpToken.tokenid], - function(err) { - if (err) d.reject(err) - d.resolve() - } - ) - return d.promise - }) - .then(function() { - var d = P.defer() - con.query( - 'INSERT INTO authTokens(tokenid, tokendata, uid) VALUES (?, ?, ?)', - [authToken.tokenid, authToken.data, authToken.uid], - function(err) { - if (err) d.reject(err) - d.resolve(authToken) - } - ) - return d.promise - }) - .then(function() { - return commitTransaction(con).then(function() { - con.release() - }) - }) - .then(function() { - return P(authToken) - }) - } - - MySql.prototype.createSession = function (authToken) { - log.trace({ op: 'MySql.createSession', uid: authToken && authToken.uid }) - var con - return P.all( - [ - KeyFetchToken.create(authToken), - SessionToken.create(authToken) - ] - ) - .then(function (tokens) { - var keyFetchToken = tokens[0] - var sessionToken = tokens[1] - - return this.getMasterConnection() - .then(function(thisCon) { - con = thisCon - return beginTransaction(con) - }) - .then(function(thisCon) { - var d = P.defer() - con.query( - 'DELETE FROM authTokens WHERE tokenid = ?', - [authToken.tokenid], - function(err) { - if (err) return d.reject(err) - d.resolve() - } - ) - return d.promise - }) - .then(function() { - var d = P.defer() - con.query( - 'INSERT INTO keyfetchTokens (tokenid, tokendata, uid) VALUES (?, ?, ?)', - [keyFetchToken.tokenid, keyFetchToken.data, keyFetchToken.uid], - function(err) { - if (err) return d.reject(err) - d.resolve() - } - ) - return d.promise - }) - .then(function() { - var d = P.defer() - con.query( - 'INSERT INTO sessionTokens (tokenid, tokendata, uid) VALUES (?, ?, ?)', - [sessionToken.tokenid, sessionToken.data, sessionToken.uid], - function(err) { - if (err) return d.reject(err) - // now commit and release - commitTransaction(con).then(function() { - con.release() - d.resolve({ - keyFetchToken: keyFetchToken, - sessionToken: sessionToken - }) - }) - } - ) - return d.promise - }) - }.bind(this)) - } - MySql.prototype.verifyEmail = function (account) { log.trace({ op: 'MySql.verifyEmail', uid: account && account.uid }) var sql = 'UPDATE accounts SET verified = true WHERE uid = ?' @@ -1044,73 +765,6 @@ module.exports = function ( }) } - MySql.prototype.createPasswordChange = function (authToken) { - log.trace({ op: 'MySql.createPasswordChange', uid: authToken && authToken.uid }) - var con - return P.all( - [ - KeyFetchToken.create(authToken), - AccountResetToken.create(authToken) - ] - ) - .then(function (tokens) { - var keyFetchToken = tokens[0] - var accountResetToken = tokens[1] - - return this.getMasterConnection() - .then(function(thisCon) { - con = thisCon - return beginTransaction(con) - }) - .then(function(thisCon) { - var d = P.defer() - con.query( - 'DELETE FROM authTokens WHERE tokenid = ?', - [authToken.tokenid], - function(err) { - if (err) return d.reject(err) - d.resolve() - } - ) - return d.promise - }) - .then(function() { - var d = P.defer() - con.query( - 'INSERT INTO keyfetchTokens (tokenid, tokendata, uid) VALUES (?, ?, ?)', - [keyFetchToken.tokenid, keyFetchToken.data, keyFetchToken.uid], - function(err) { - if (err) return d.reject(err) - d.resolve() - } - ) - return d.promise - }) - .then(function() { - var d = P.defer() - con.query( - 'REPLACE INTO resetTokens (tokenid, tokendata, uid) VALUES (?, ?, ?)', - [accountResetToken.tokenid, accountResetToken.data, accountResetToken.uid], - function(err) { - if (err) return d.reject(err) - d.resolve() - } - ) - return d.promise - }) - .then(function() { - return commitTransaction(con) - }) - .then(function() { - con.release() - return P({ - keyFetchToken: keyFetchToken, - accountResetToken: accountResetToken - }) - }) - }.bind(this)) - } - MySql.prototype.forgotPasswordVerified = function (passwordForgotToken) { log.trace({ op: 'MySql.forgotPasswordVerified', uid: passwordForgotToken && passwordForgotToken.uid }) diff --git a/routes/auth.js b/routes/auth.js deleted file mode 100644 index 7311e805..00000000 --- a/routes/auth.js +++ /dev/null @@ -1,119 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -var HEX_STRING = require('./validators').HEX_STRING -var HEX_EMAIL = require('./validators').HEX_EMAIL - -module.exports = function (log, isA, error, db, Token) { - - var routes = [ - { - method: 'POST', - path: '/auth/start', - config: { - description: - "Begins an SRP login for the supplied email address, " + - "returning the temporary srpToken and parameters for " + - "key stretching and the SRP protocol for the client.", - tags: ["srp", "account"], - handler: function (request) { - log.begin('Auth.start', request) - var reply = request.reply.bind(request) - db.emailRecord(Buffer(request.payload.email, 'hex').toString()) - .then( - function (emailRecord) { - return db.createSrpToken(emailRecord) - } - ) - .then( - function (srpToken) { - return srpToken.clientData() - } - ) - .done(reply, reply) - }, - validate: { - payload: { - email: isA.String().max(1024).regex(HEX_EMAIL).required() - }, - response: { - schema: { - srpToken: isA.String().required(), - passwordStretching: isA.Object(), - srp: isA.Object({ - type: isA.String().required(), - salt: isA.String().regex(HEX_STRING), // salt - B: isA.String().regex(HEX_STRING) // server's public key value - }) - } - } - } - } - }, - { - method: 'POST', - path: '/auth/finish', - config: { - description: - "Finishes the SRP dance, with the client providing " + - "proof-of-knownledge of the password and receiving " + - "the bundle encrypted with the authToken.", - tags: ["srp", "session"], - handler: function (request) { - log.begin('Auth.finish', request) - var reply = request.reply.bind(request) - var srpTokenId = Buffer(request.payload.srpToken, 'hex') - var srpToken = null; - db.srpToken(srpTokenId) - .then( - function (token) { - srpToken = token - return srpToken.finish(request.payload.A, request.payload.M) - } - ) - .then( - function (srpToken) { - log.security({ event: 'login-success', uid: srpToken.uid }); - return srpToken - }, - function (err) { - log.security({ event: 'login-failure', err: err, uid: srpToken.uid }); - throw err - } - ) - .then( - function (srpToken) { - return db.authFinish(srpToken) - .then( - function (authToken) { - return srpToken.bundleAuth(authToken.data) - } - ) - .then( - function (bundle) { - return {bundle: bundle} - } - ) - } - ) - .done(reply, reply) - }, - validate: { - payload: { - srpToken: isA.String().regex(HEX_STRING).required(), - A: isA.String().regex(HEX_STRING).required(), - M: isA.String().regex(HEX_STRING).required() - }, - response: { - schema: { - bundle: isA.String().regex(HEX_STRING).required() - } - } - } - } - } - ] - - return routes -} diff --git a/routes/index.js b/routes/index.js index 373e550a..016f1d96 100644 --- a/routes/index.js +++ b/routes/index.js @@ -14,14 +14,11 @@ module.exports = function ( error, serverPublicKey, signer, - clientHelper, db, mailer, - Token, config ) { var isProduction = config.env === 'prod' - 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, P, uuid, isA, error, db, mailer, isProduction) @@ -29,16 +26,13 @@ module.exports = function ( var session = require('./session')(log, isA, error, db) var sign = require('./sign')(log, isA, error, signer, config.domain) var util = require('./util')(log, crypto, isA, config) - var raw = require('./rawpassword')(log, isA, error, clientHelper, crypto, db, isProduction) var v1Routes = [].concat( - auth, account, password, session, sign, - util, - raw + util ) v1Routes.forEach(function(route) { route.path = "/v1" + route.path diff --git a/routes/rawpassword.js b/routes/rawpassword.js deleted file mode 100644 index 17334672..00000000 --- a/routes/rawpassword.js +++ /dev/null @@ -1,193 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -var HEX_STRING = require('./validators').HEX_STRING -var HEX_EMAIL = require('./validators').HEX_EMAIL - -module.exports = function (log, isA, error, clientHelper, crypto, db, isProduction) { - - function enqueueWithHelper(message, cb) { - clientHelper.enqueue(message, function(err, result) { - if (err) { - log.error({ op: 'clientHelper.enqueue', err: err, result: result }) - return cb(error.serviceUnavailable()) - } - if (result && result.err) { - return cb(result.err) - } - return cb(null, result) - }) - } - - var routes = [ - { - method: 'POST', - path: '/raw_password/session/create', - config: { - description: 'Create a session from an email and password', - tags: ['raw', 'session'], - handler: function (request) { - log.begin('RawPassword.sessionCreate', request) - enqueueWithHelper( - { - action: 'session/create', - email: Buffer(request.payload.email, 'hex').toString('utf8'), - password: request.payload.password - }, - function (err, result) { - if (err) { - return request.reply(error.wrap(err)) - } - return request.reply(result) - } - ) - }, - validate: { - payload: { - email: isA.String().max(1024).regex(HEX_EMAIL).required(), - password: isA.String().required() - }, - response: { - schema: { - uid: isA.String().required(), - verified: isA.Boolean().required(), - sessionToken: isA.String().regex(HEX_STRING).required() - } - } - } - } - }, - { - method: 'POST', - path: '/raw_password/account/create', - config: { - description: 'Creates an account associated with an email address', - tags: ['raw', 'account'], - handler: function accountCreate(request) { - log.begin('RawPassword.accountCreate', request) - enqueueWithHelper( - { - action: 'account/create', - email: Buffer(request.payload.email, 'hex').toString('utf8'), - password: request.payload.password, - options: { - preVerified: request.payload.preVerified || false, - service: request.payload.service, - lang: request.app.preferredLang - } - }, - function (err, result) { - if (err) { - return request.reply(error.wrap(err)) - } - return request.reply(result) - } - ) - }, - validate: { - payload: { - email: isA.String().max(1024).regex(HEX_EMAIL).required(), - password: isA.String().required(), - preVerified: isA.Boolean(), - service: isA.String().max(16).alphanum().optional() - } - } - } - }, - { - method: 'POST', - path: '/raw_password/password/change', - config: { - description: 'Creates an account associated with an email address', - tags: ['raw', 'account'], - handler: function passwordChange(request) { - log.begin('RawPassword.passwordChange', request) - enqueueWithHelper( - { - action: 'password/change', - email: Buffer(request.payload.email, 'hex').toString('utf8'), - oldPassword: request.payload.oldPassword, - newPassword: request.payload.newPassword - }, - function (err, result) { - if (err) { - err = error.wrap(err) - log.security({ event: 'pwd-change-failure', err: err }) - return request.reply(err); - } - log.security({ event: 'pwd-change-success' }) - return request.reply(result) - } - ) - }, - validate: { - payload: { - email: isA.String().max(1024).regex(HEX_EMAIL).required(), - oldPassword: isA.String().required(), - newPassword: isA.String().required() - } - } - } - }, - { - method: 'POST', - path: '/raw_password/password/reset', - config: { - description: 'Resets the password associated with an account', - auth: { - strategy: 'accountResetToken' - }, - tags: ['raw', 'account'], - handler: function passwordReset(request) { - log.begin('RawPassword.passwordReset', request) - var accountResetToken = request.auth.credentials - var form = request.payload - - db.account(accountResetToken.uid) - .then( - function (account) { - enqueueWithHelper( - { - action: 'password/reset', - email: account.email, - newPassword: form.newPassword, - passwordStretching: account.passwordStretching - }, - function (err, result) { - if (err) { - err = error.wrap(err) - log.security({ event: 'pwd-reset-failure', err: err }) - return request.reply(err) - } - log.security({ event: 'pwd-reset-success' }) - result.wrapKb = crypto.randomBytes(32) - db.resetAccount(accountResetToken, result) - .done( - function () { - return request.reply({}) - }, - function (err) { - return request.reply(error.wrap(err)) - } - ) - } - ) - } - ) - }, - validate: { - payload: { - newPassword: isA.String().required() - } - } - } - }, - ] - - if (isProduction) { - delete routes[1].config.validate.payload.preVerified - } - - return routes -} diff --git a/routes/session.js b/routes/session.js index bd9c5364..4f359c1b 100644 --- a/routes/session.js +++ b/routes/session.js @@ -5,42 +5,6 @@ module.exports = function (log, isA, error, db) { var routes = [ - { - method: 'POST', - path: '/session/create', - config: { - description: "Creates a new session", - tags: ["session"], - auth: { - strategy: 'authToken' - }, - handler: function (request) { - log.begin('Session.create', request) - var reply = request.reply.bind(request) - var authToken = request.auth.credentials - log.security({ event: 'session-create' }) - db.createSession(authToken) - .then( - function (tokens) { - return authToken.bundleSession( - tokens.keyFetchToken.data, - tokens.sessionToken.data - ) - } - ) - .then( - function (bundle) { - return { - uid: authToken.uid.toString('hex'), - verified: authToken.verified, - bundle: bundle - } - } - ) - .done(reply, reply) - } - } - }, { method: 'POST', path: '/session/destroy', diff --git a/server/server.js b/server/server.js index 52542379..a193a277 100644 --- a/server/server.js +++ b/server/server.js @@ -71,11 +71,6 @@ module.exports = function (path, url, Hapi, toobusy) { hawk: hawkOptions, getCredentialsFunc: makeCredentialFn(db.accountResetToken.bind(db)) }, - authToken: { - scheme: 'hawk', - hawk: hawkOptions, - getCredentialsFunc: makeCredentialFn(db.authToken.bind(db)) - }, passwordForgotToken: { scheme: 'hawk', hawk: hawkOptions, diff --git a/test/run/auth_token_tests.js b/test/run/auth_token_tests.js deleted file mode 100644 index 527c2b35..00000000 --- a/test/run/auth_token_tests.js +++ /dev/null @@ -1,148 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -var test = require('../ptaptest') -var crypto = require('crypto') -var log = { trace: function() {} } - -var tokens = require('../../tokens')(log) -var AuthToken = tokens.AuthToken - -var ACCOUNT = { - uid: 'xxx' -} - - -test( - 're-creation from tokendata works', - function (t) { - var token = null; - return AuthToken.create(ACCOUNT) - .then( - function (x) { - token = x - } - ) - .then( - function () { - return AuthToken.fromHex(token.data, ACCOUNT) - } - ) - .then( - function (token2) { - t.deepEqual(token.data, token2.data) - t.deepEqual(token.id, token2.id) - t.deepEqual(token.authKey, token2.authKey) - t.deepEqual(token.bundleKey, token2.bundleKey) - t.deepEqual(token.uid, token2.uid) - } - ) - } -) - - -test( - 'bundle / unbundle of session data works', - function (t) { - var token = null; - var keyFetchToken = crypto.randomBytes(32) - var sessionToken = crypto.randomBytes(32) - return AuthToken.create(ACCOUNT) - .then( - function (x) { - token = x - return x.bundleSession(keyFetchToken, sessionToken) - } - ) - .then( - function (b) { - return token.unbundleSession(b) - } - ) - .then( - function (ub) { - t.deepEqual(ub.keyFetchToken, keyFetchToken) - t.deepEqual(ub.sessionToken, sessionToken) - } - ) - } -) - - -test( - 'bundle / unbundle of account reset data works', - function (t) { - var token = null; - var keyFetchToken = crypto.randomBytes(32) - var resetToken = crypto.randomBytes(32) - return AuthToken.create(ACCOUNT) - .then( - function (x) { - token = x - return x.bundleAccountReset(keyFetchToken, resetToken) - } - ) - .then( - function (b) { - return token.unbundleAccountReset(b) - } - ) - .then( - function (ub) { - t.deepEqual(ub.keyFetchToken, keyFetchToken) - t.deepEqual(ub.accountResetToken, resetToken) - } - ) - } -) - -test( - 'authToken key derivations are test-vector compliant', - function (t) { - var token = null; - var tokendata = '606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f' - return AuthToken.fromHex(tokendata, ACCOUNT) - .then( - function (x) { - token = x - t.equal(token.data.toString('hex'), tokendata) - t.equal(token.id.toString('hex'), '9a39818e3bbe613238c9d7ff013a18411ed2c66c3565c3c4de03feefecb7d212') - t.equal(token.authKey.toString('hex'), '4a17cbdd54ee17db426fcd7baddff587231d7eadb408c091ce19ca915b715985') - t.equal(token.bundleKey.toString('hex'), '9d93978e662bfc6e8cc203fa4628ef5a7bf1ddfd7ee54e97ec5c033257b4fca9') - } - ) - .then( - function () { - var keyFetchToken = Buffer('808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f', 'hex') - var sessionToken = Buffer('a0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebf', 'hex') - return token.bundleSession(keyFetchToken, sessionToken) - } - ) - .then( - function (bundle) { - t.equal(bundle, - '04a347b2c75b2f418cc37162dea57c1ee408f9109f820234' + - '7768a841cf8ad3dc324f1adf6b2f710fa4ea823f4ccb70c4' + - 'bf46b4eb6b0a99b0017ecafbf95073eb7973ddbb184b601a' + - 'c4df09704028ebfc754dd50e7d8eebfa52ce3fd868c69852') - } - ) - .then( - function () { - var keyFetchToken = Buffer('808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f', 'hex') - var accountResetToken = Buffer('c0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedf', 'hex') - return token.bundleAccountReset(keyFetchToken, accountResetToken) - } - ) - .then( - function (bundle) { - t.equal(bundle, - 'bd643fdd047f7ecd5743d91d980cad6011155fd8559fea1d' + - '438f12d2c66270f820be421ad000d69800a4a03980862f7e' + - '3fbd4eb5c0f77a94c0c2e7f2be97d21d804fc4bc30923cc0' + - 'd6c07ffea954848e0076b94f7deee71fa34db5c106d91980') - } - ) - } -) diff --git a/test/run/db_tests.js b/test/run/db_tests.js index fbd9f995..b3e598a0 100644 --- a/test/run/db_tests.js +++ b/test/run/db_tests.js @@ -12,11 +12,9 @@ var DB = require('../../db')( config, log, Token.error, - Token.AuthToken, Token.SessionToken, Token.KeyFetchToken, Token.AccountResetToken, - Token.SrpToken, Token.PasswordForgotToken ) @@ -82,62 +80,6 @@ DB.connect() } ) - test( - 'srp token handling', - function (t) { - return db.emailRecord(ACCOUNT.email) - .then(function(emailRecord) { - return db.createSrpToken(emailRecord) - }) - .then(function(srpToken) { - t.deepEqual(srpToken.uid, ACCOUNT.uid, 'srpToken.uid is the same as the ACCOUNT.uid') - t.equal(srpToken.v.toString('hex'), ACCOUNT.srp.verifier) - t.equal(srpToken.s, ACCOUNT.srp.salt, 'srpToken.s == ACCOUNT.srp.salt') - t.ok(srpToken.b, 'srpToken.b is true') - return srpToken - }) - .then(function(srpToken) { - return db.srpToken(srpToken.tokenid) - }) - .then(function(srpToken) { - t.deepEqual(srpToken.uid, ACCOUNT.uid) - t.equal(srpToken.v.toString('hex'), ACCOUNT.srp.verifier) - t.equal(srpToken.s, ACCOUNT.srp.salt) - t.ok(srpToken.b) - return srpToken - }) - .then(function(srpToken) { - return db.deleteSrpToken(srpToken.tokenid) - }) - } - ) - - test( - 'auth token handling', - function (t) { - var tokenid; - return db.emailRecord(ACCOUNT.email) - .then(function(emailRecord) { - return db.createAuthToken({ uid: emailRecord.uid }) - }) - .then(function(authToken) { - t.deepEqual(authToken.uid, ACCOUNT.uid) - tokenid = authToken.tokenid - }) - .then(function() { - return db.authToken(tokenid) - }) - .then(function(authToken) { - t.deepEqual(authToken.tokenid, tokenid, 'token id matches') - t.deepEqual(authToken.uid, ACCOUNT.uid) - return authToken - }) - .then(function(authToken) { - return db.deleteAuthToken(authToken) - }) - } - ) - test( 'session token handling', function (t) { @@ -276,88 +218,6 @@ DB.connect() } ) - test( - 'db.authFinish', - function (t) { - return db.emailRecord(ACCOUNT.email) - .then(function(emailRecord) { - return db.createSrpToken(emailRecord) - }) - .then(function(srpToken) { - return db.authFinish(srpToken) - }) - .then(function(authToken) { - t.deepEqual(authToken.uid, ACCOUNT.uid) - }) - } - ) -/* - test( - 'db.createSession', - function (t) { - var tokens1; - return db.emailRecord(ACCOUNT.email) - .then(function(emailRecord) { - return db.createAuthToken(emailRecord) - }) - .then(function(authToken) { - return db.createSession(authToken) - }) - .then(function(tokens) { - t.deepEqual(tokens.keyFetchToken.uid, ACCOUNT.uid, 'keyFetchToken uid and account uid should be the same') - t.deepEqual(tokens.sessionToken.uid, ACCOUNT.uid, 'sessionToken uid and account uid should be the same') - tokens1 = tokens - }) - .then(function() { - return db.keyFetchToken(tokens1.keyFetchToken.tokenid) - }) - .then(function(keyFetchToken) { - t.deepEqual(keyFetchToken.uid, ACCOUNT.uid, 'keyFetchToken uid and account uid should still be the same') - return db.deleteKeyFetchToken(tokens1.keyFetchToken) - }) - .then(function() { - return db.sessionToken(tokens1.sessionToken.tokenid) - }) - .then(function(sessionToken) { - t.deepEqual(sessionToken.uid, ACCOUNT.uid, 'sessionToken uid and account uid should still be the same') - return db.deleteSessionToken(tokens1.sessionToken) - }) - } - ) - - test( - 'db.createPasswordChange', - function (t) { - var tokens1; - return db.emailRecord(ACCOUNT.email) - .then(function(emailRecord) { - return db.createAuthToken(emailRecord) - }) - .then(function(authToken) { - return db.createPasswordChange(authToken) - }) - .then(function(tokens) { - t.deepEqual(tokens.keyFetchToken.uid, ACCOUNT.uid, 'keyFetchToken.uid is the same as the original ACCOUNT.uid') - t.deepEqual(tokens.accountResetToken.uid, ACCOUNT.uid, 'accountResetToken.uid is the same as the original ACCOUNT.uid') - tokens1 = tokens - }) - .then(function() { - return db.keyFetchToken(tokens1.keyFetchToken.tokenid) - }) - .then(function(keyFetchToken) { - t.deepEqual(keyFetchToken.uid, ACCOUNT.uid) - return db.deleteKeyFetchToken(tokens1.keyFetchToken) - }) - .then(function() { - return db.accountResetToken(tokens1.accountResetToken.tokenid) - }) - .then(function(accountResetToken) { - t.deepEqual(accountResetToken.uid, ACCOUNT.uid) - return db.deleteAccountResetToken(tokens1.accountResetToken) - }) - } - ) -*/ test( 'db.forgotPasswordVerified', function (t) { diff --git a/test/run/raw_password_tests.js b/test/run/raw_password_tests.js deleted file mode 100644 index caead001..00000000 --- a/test/run/raw_password_tests.js +++ /dev/null @@ -1,183 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -var test = require('../ptaptest') -var crypto = require('crypto') -var Client = require('../../client') -var config = require('../../config').root() -var TestServer = require('../test_server') - -function uniqueID() { - return crypto.randomBytes(10).toString('hex'); -} - -TestServer.start(config.publicUrl) -.then(function main(server) { - - // Randomly-generated account names for testing. - // This makes it easy to run the tests against an existing server - // which may already have some accounts in its db. - - var email1 = uniqueID() + "@example.com" - - test( - '(reduced security) Create account', - function (t) { - var clientApi = new Client.Api(config.publicUrl) - var email = Buffer(email1).toString('hex') - var password = 'allyourbasearebelongtous' - return clientApi.rawPasswordAccountCreate(email, password, {preVerified: true}) - .then( - function (result) { - var client = null - t.equal(typeof(result.uid), 'string') - return Client.login(config.publicUrl, email1, password) - .then( - function (x) { - client = x - return client.keys() - } - ) - .then( - function (keys) { - t.ok(Buffer.isBuffer(keys.kA), 'kA exists') - t.ok(Buffer.isBuffer(keys.wrapKb), 'wrapKb exists') - t.ok(Buffer.isBuffer(keys.kB), 'kB exists') - t.equal(client.kB.length, 32, 'kB exists, has the right length') - } - ) - } - ) - .then( - function () { - return server.assertLogs(t, { - 'account-create-success': 1, - 'session-create': 1 - }) - } - ) - } - ) - - test( - '(reduced security) Login with email and password', - function (t) { - var clientApi = new Client.Api(config.publicUrl) - var email = Buffer(email1).toString('hex') - var password = 'allyourbasearebelongtous' - return clientApi.rawPasswordSessionCreate(email, password) - .then( - function (result) { - t.ok(result.uid, 'uid exists') - t.equal(result.verified, true, 'email verified') - t.equal(typeof(result.sessionToken), 'string', 'sessionToken exists') - } - ) - .then( - function () { - return server.assertLogs(t, { - 'account-create-success': 0, - 'session-create': 1 - }) - } - ) - } - ) - - test( - '(reduced security) Login with email and wrong password', - function (t) { - var clientApi = new Client.Api(config.publicUrl) - var email = Buffer(email1).toString('hex') - var password = 'xxx' - return clientApi.rawPasswordSessionCreate(email, password) - .then( - function (result) { - t.fail('login succeeded') - }, - function (err) { - t.equal(err.errno, 103) - } - ) - .then( - function () { - return server.assertLogs(t, { - 'login-failure': 1, - 'login-success': 0, - 'session-create': 0 - }) - } - ) - } - ) - - test( - '(reduced security) Login with unknown email', - function (t) { - var clientApi = new Client.Api(config.publicUrl) - var email = Buffer('x@y.me').toString('hex') - var password = 'allyourbasearebelongtous' - return clientApi.rawPasswordSessionCreate(email, password) - .then( - function (result) { - t.fail('login succeeded') - }, - function (err) { - t.equal(err.errno, 102) - } - ) - .then( - function () { - return server.assertLogs(t, { - // the error here is "account does not exist" - // which doesn't trigger security logging - 'login-failure': 0, - 'login-success': 0, - 'session-create': 0 - }) - } - ) - } - ) - - test( - '(reduced security) Change password', - function (t) { - var clientApi = new Client.Api(config.publicUrl) - var email = Buffer(email1).toString('hex') - var password = 'allyourbasearebelongtous' - var newPassword = 'wow' - return clientApi.rawPasswordPasswordChange(email, password, newPassword) - .then( - function (result) { - t.equal(JSON.stringify(result), '{}', 'password changed') - return clientApi.rawPasswordSessionCreate(email, newPassword) - } - ) - .then( - function (result) { - t.ok(result.uid, 'uid exists') - t.equal(result.verified, true, 'email verified') - t.equal(typeof(result.sessionToken), 'string', 'sessionToken exists') - } - ) - .then( - function () { - return server.assertLogs(t, { - 'pwd-reset-success': 1, - 'pwd-reset-failure': 0 - }) - } - ) - } - ) - - test( - 'teardown', - function (t) { - server.stop() - t.end() - } - ) -}) diff --git a/test/run/srp_session_tests.js b/test/run/srp_session_tests.js deleted file mode 100644 index c08d1d7b..00000000 --- a/test/run/srp_session_tests.js +++ /dev/null @@ -1,128 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -var test = require('../ptaptest') -var crypto = require('crypto') -var srp = require('srp') -var log = { trace: function() {} } - -var Token = require('../../tokens')(log) -var DB = require('../../db/heap')( - log, - Token.error, - Token.AuthToken, - Token.SessionToken, - Token.KeyFetchToken, - Token.AccountResetToken, - Token.SrpToken, - Token.PasswordForgotToken -) -var db = new DB() - -var SrpToken = Token.SrpToken - -var alice = { - uid: 'xxx', - email: Buffer('somebödy@example.com').toString('hex'), - password: 'awesomeSauce', - srp: { - verifier: null, - salt: 'BAD1' - }, - kA: 'BAD3', - wrapKb: 'BAD4' -} - -alice.srp.verifier = srp.computeVerifier( - srp.params[2048], - Buffer(alice.srp.salt, 'hex'), - Buffer(alice.email), - Buffer(alice.password) -).toString('hex') - - -db.createAccount(alice) -.then( - function (a) { - - test( - 'create login session works', - function (t) { - return SrpToken.create(a) - .then( - function (s) { - t.equal(s.uid, a.uid) - t.equal(s.s, a.srp.salt) - } - ) - } - ) - - test( - 'finish login session works', - function (t) { - var session = null - var K = null - return SrpToken.create(a) - .then( - function (s) { - session = s - var a = crypto.randomBytes(32) - var clientData = s.clientData() - var srpClient = new srp.Client( - srp.params[2048], - Buffer(clientData.srp.salt, 'hex'), - Buffer(alice.email), - Buffer(alice.password), - a - ) - srpClient.setB(Buffer(clientData.srp.B, 'hex')) - return { - A: srpClient.computeA().toString('hex'), - M: srpClient.computeM1().toString('hex'), - K: srpClient.computeK().toString('hex'), - } - } - ) - .then( - function (x) { - K = x.K - return session.finish(x.A, x.M) - } - ) - .then( - function (s) { - t.equal(s.K.toString('hex'), K) - } - ) - } - ) - } -) -.done( - function () { - - test( - 'authToken encryption is test-vector compliant', - function (t) { - var srpK = 'e68fd0112bfa31dcffc8e9c96a1cbadb4c3145978ff35c73e5bf8d30bbc7499a' - var authToken = Buffer('606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f', 'hex') - var bundle = '253957f10e861c7c0a12bb0193d384d9579db544666d50bd3252d6576c768a68' + - 'a98c87f5769ab4ccca3df863faeb217eb16ddc29d712b30112b446324ee806d6' - return SrpToken.create(alice) - .then( - function (token) { - token.K = Buffer(srpK, 'hex') - return token.bundleAuth(authToken) - } - ) - .then( - function (b) { - t.equal(b, bundle) - } - ) - } - ) - } -) diff --git a/tokens/auth_token.js b/tokens/auth_token.js deleted file mode 100644 index 55de48ce..00000000 --- a/tokens/auth_token.js +++ /dev/null @@ -1,62 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -module.exports = function (log, inherits, Token, error) { - - function AuthToken(keys, details) { - Token.call(this, keys, details) - this.verified = !!details.verified - } - inherits(AuthToken, Token) - - AuthToken.tokenTypeID = 'authToken' - - AuthToken.create = function (details) { - log.trace({ op: 'AuthToken.create', uid: details && details.uid }) - return Token.createNewToken(AuthToken, details || {}) - } - - AuthToken.fromHex = function (string, details) { - log.trace({ op: 'AuthToken.fromHex' }) - return Token.createTokenFromHexData(AuthToken, string, details || {}) - } - - AuthToken.prototype.bundleSession = function (keyFetchToken, sessionToken) { - log.trace({ op: 'authToken.bundleSession', id: this.id }) - return this.bundle('session/create', Buffer.concat([keyFetchToken, sessionToken])) - } - - AuthToken.prototype.unbundleSession = function (bundle) { - log.trace({ op: 'authToken.unbundleSession', id: this.id }) - return this.unbundle('session/create', bundle) - .then( - function (plaintext) { - return { - keyFetchToken: plaintext.slice(0, 32), - sessionToken: plaintext.slice(32, 64) - } - } - ) - } - - AuthToken.prototype.bundleAccountReset = function (keyFetchToken, resetToken) { - log.trace({ op: 'authToken.bundleAccountReset', id: this.id }) - return this.bundle('password/change', Buffer.concat([keyFetchToken, resetToken])) - } - - AuthToken.prototype.unbundleAccountReset = function (bundle) { - log.trace({ op: 'authToken.unbundleAccountReset', id: this.id }) - return this.unbundle('password/change', bundle) - .then( - function (plaintext) { - return { - keyFetchToken: plaintext.slice(0, 32), - accountResetToken: plaintext.slice(32, 64) - } - } - ) - } - - return AuthToken -} diff --git a/tokens/index.js b/tokens/index.js index 31deb7ba..d8850fc6 100644 --- a/tokens/index.js +++ b/tokens/index.js @@ -6,8 +6,6 @@ var crypto = require('crypto') var inherits = require('util').inherits var P = require('p-promise') -var srp = require('srp') -var uuid = require('uuid') var hkdf = require('../hkdf') var error = require('./error') @@ -25,7 +23,6 @@ module.exports = function (log) { crypto ) var SessionToken = require('./session_token')(log, inherits, Token) - var AuthToken = require('./auth_token')(log, inherits, Token, error) var PasswordForgotToken = require('./password_forgot_token')( log, inherits, @@ -33,16 +30,6 @@ module.exports = function (log) { Token, crypto ) - var SrpToken = require('./srp_token')( - log, - inherits, - P, - uuid, - srp, - Bundle, - Token, - error - ) var PasswordChangeToken = require('./password_change_token')( log, @@ -55,9 +42,7 @@ module.exports = function (log) { Token.AccountResetToken = AccountResetToken Token.KeyFetchToken = KeyFetchToken Token.SessionToken = SessionToken - Token.AuthToken = AuthToken Token.PasswordForgotToken = PasswordForgotToken - Token.SrpToken = SrpToken Token.PasswordChangeToken = PasswordChangeToken return Token diff --git a/tokens/srp_token.js b/tokens/srp_token.js deleted file mode 100644 index 820ea30f..00000000 --- a/tokens/srp_token.js +++ /dev/null @@ -1,85 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -module.exports = function (log, inherits, P, uuid, srp, Bundle, Token, error) { - - function SrpToken(keys, details) { - if (!details.srp) { details.srp = {} } - Token.call(this, keys, details) - this.b = this.bundleKey - this.v = details.srp.verifier ? Buffer(details.srp.verifier, 'hex') : null - this.s = details.srp.salt ? details.srp.salt : null - this.passwordStretching = details.passwordStretching || null - this.srpServer = new srp.Server(srp.params[2048], this.v, this.b) - this.K = null - } - inherits(SrpToken, Token) - - SrpToken.tokenTypeID = 'srpToken' - - SrpToken.create = function (details) { - log.trace({ op: 'SrpToken.create', uid: details && details.uid }) - return Token.createNewToken(SrpToken, details || {}) - } - - SrpToken.fromHex = function (string, details) { - log.trace({ op: 'SrpToken.create', uid: details && details.uid }) - return Token.createTokenFromHexData(SrpToken, string, details || {}) - } - - // Get the data to be sent back to the client in the first message. - // - SrpToken.prototype.clientData = function () { - return { - srpToken: this.id.toString('hex'), - passwordStretching: this.passwordStretching, - srp: { - type: 'SRP-6a/SHA256/2048/v1', - salt: this.s, - B: this.srpServer.computeB().toString('hex') - } - } - } - - // Complete the SRP dance, verifying the correct credentials and - // deriving the value of the shared secret. - // - SrpToken.prototype.finish = function (A, M1) { - A = Buffer(A, 'hex') - this.srpServer.setA(A) - try { - this.srpServer.checkM1(Buffer(M1, 'hex')) - } - catch (e) { - throw error.incorrectPassword() - } - this.K = this.srpServer.computeK() - return this - } - - SrpToken.prototype.bundleAuth = function (authToken) { - log.trace({ op: 'srpToken.bundleAuth', id: this.id, auth: authToken }) - if (!this.K) { - return P.reject('Shared secret missing; SRP handshake was not completed') - } - return Bundle.bundle(this.K, 'auth/finish', authToken) - } - - SrpToken.prototype.unbundleAuth = function (bundle) { - log.trace({ op: 'srpToken.unbundleAuth', id: this.id }) - if (!this.K) { - return P.reject('Shared secret missing; SRP handshake was not completed') - } - return Bundle.unbundle(this.K, 'auth/finish', bundle) - .then( - function (plaintext) { - return { - authToken: plaintext, - } - } - ) - } - - return SrpToken -}