diff --git a/app/scripts/lib/fxa-client.js b/app/scripts/lib/fxa-client.js index 4521a68a7..3021f7cdd 100644 --- a/app/scripts/lib/fxa-client.js +++ b/app/scripts/lib/fxa-client.js @@ -1008,6 +1008,10 @@ define(function (require, exports, module) { * * @param {String} sessionToken SessionToken obtained from signIn * @param {String} code TOTP code + * @param {Object} [options={}] Options + * @param {String} [options.metricsContext] - context metadata for use in + * flow events + * @param {String} [options.service] - service used * @returns {Promise} resolves when complete */ verifyTotpCode: createClientDelegate('verifyTotpCode'), diff --git a/app/scripts/models/account.js b/app/scripts/models/account.js index d95a27199..fa63ab3ed 100644 --- a/app/scripts/models/account.js +++ b/app/scripts/models/account.js @@ -1294,16 +1294,18 @@ define(function (require, exports, module) { * Verifies a TOTP code. If code is verified, token will be marked as verified. * * @param {String} code - * + * @param {String} service * @returns {Promise} */ - verifyTotpCode (code) { + verifyTotpCode (code, service) { + const options = { + metricsContext: this._metrics.getFlowEventMetadata(), + service: service + }; return this._fxaClient.verifyTotpCode( this.get('sessionToken'), code, - { - metricsContext: this._metrics.getFlowEventMetadata(), - } + options ); }, diff --git a/app/scripts/views/settings/two_step_authentication.js b/app/scripts/views/settings/two_step_authentication.js index 854984161..b1a31938d 100644 --- a/app/scripts/views/settings/two_step_authentication.js +++ b/app/scripts/views/settings/two_step_authentication.js @@ -150,7 +150,7 @@ const View = FormView.extend({ const account = this.getSignedInAccount(); const code = this.getElementValue('input.totp-code'); - return account.verifyTotpCode(code) + return account.verifyTotpCode(code, this.relier.get('service')) .then((result) => { if (result.success) { this.displaySuccess(t('Two-step authentication enabled'), {}); diff --git a/app/scripts/views/sign_in_totp_code.js b/app/scripts/views/sign_in_totp_code.js index 03d2ad240..ebd1a2f6b 100644 --- a/app/scripts/views/sign_in_totp_code.js +++ b/app/scripts/views/sign_in_totp_code.js @@ -27,7 +27,7 @@ const View = FormView.extend({ submit () { const account = this.getSignedInAccount(); const code = this.getElementValue('input.totp-code'); - return account.verifyTotpCode(code) + return account.verifyTotpCode(code, this.relier.get('service')) .then((result) => { if (result.success) { this.logViewEvent('success'); diff --git a/app/tests/spec/lib/fxa-client.js b/app/tests/spec/lib/fxa-client.js index 1aa0ceff6..bdea82031 100644 --- a/app/tests/spec/lib/fxa-client.js +++ b/app/tests/spec/lib/fxa-client.js @@ -1579,13 +1579,17 @@ define(function (require, exports, module) { const resp = { success: true }; + const options = { + metricsContext: { foo: 'bar' }, + service: 'someservice' + }; sinon.stub(realClient, 'verifyTotpCode').callsFake(() => Promise.resolve(resp)); - return client.verifyTotpCode('code') + return client.verifyTotpCode('code', options) .then((_resp) => { assert.strictEqual(_resp, resp); assert.isTrue(realClient.verifyTotpCode.calledOnce); - assert.isTrue(realClient.verifyTotpCode.calledWith('code')); + assert.isTrue(realClient.verifyTotpCode.calledWith('code', options)); }); }); }); diff --git a/app/tests/spec/models/account.js b/app/tests/spec/models/account.js index 32a4f41a0..5fee3eb80 100644 --- a/app/tests/spec/models/account.js +++ b/app/tests/spec/models/account.js @@ -2676,5 +2676,32 @@ define(function (require, exports, module) { assert.isTrue(account._isAssertionValid({ __expiresAt: Date.now() + 2 })); }); }); + + describe('verifyTotpCode', () => { + const flowEventMetaData = { + startTime: Date.now() + }; + + beforeEach(() => { + sinon.stub(fxaClient, 'verifyTotpCode').callsFake(() => Promise.resolve()); + sinon.stub(metrics, 'getFlowEventMetadata').callsFake(() => flowEventMetaData); + + account.set('sessionToken', 'sessionToken'); + return account.verifyTotpCode('000000', 'service'); + }); + + it('delegates to the fxa-client', () => { + assert.isTrue(fxaClient.verifyTotpCode.calledOnce); + assert.isTrue(fxaClient.verifyTotpCode.calledWith( + 'sessionToken', + '000000', + { + metricsContext: flowEventMetaData, + service: 'service' + } + )); + }); + }); + }); }); diff --git a/app/tests/spec/views/settings/two_step_authentication.js b/app/tests/spec/views/settings/two_step_authentication.js index be2fc727c..e77f76a4e 100644 --- a/app/tests/spec/views/settings/two_step_authentication.js +++ b/app/tests/spec/views/settings/two_step_authentication.js @@ -7,6 +7,7 @@ const assert = require('chai').assert; const Broker = require('models/auth_brokers/base'); const Metrics = require('lib/metrics'); const Notifier = require('lib/channels/notifier'); +const Relier = require('models/reliers/base'); const SentryMetrics = require('lib/sentry'); const sinon = require('sinon'); const TestHelpers = require('../../../lib/helpers'); @@ -22,6 +23,7 @@ describe('views/settings/two_step_authentication', () => { let featureEnabled; let hasToken; let inTotpExperiment; + let relier; let sentryMetrics; let validCode; const UID = '123'; @@ -30,10 +32,11 @@ describe('views/settings/two_step_authentication', () => { function initView() { view = new View({ - broker: broker, - metrics: metrics, - notifier: notifier, - user: user + broker, + metrics, + notifier, + relier, + user }); sinon.stub(view, 'setupSessionGateIfRequired').callsFake(() => Promise.resolve(featureEnabled)); @@ -58,6 +61,7 @@ describe('views/settings/two_step_authentication', () => { uid: UID, verified: true }); + relier = new Relier(); sinon.stub(account, 'checkTotpTokenExists').callsFake(() => { return Promise.resolve({exists: hasToken});