diff --git a/src/popup/app/accounts/accountsLoginTwoFactorController.js b/src/popup/app/accounts/accountsLoginTwoFactorController.js index 34e72bfb..e0b6d5cb 100644 --- a/src/popup/app/accounts/accountsLoginTwoFactorController.js +++ b/src/popup/app/accounts/accountsLoginTwoFactorController.js @@ -7,16 +7,19 @@ utilsService.initListSectionItemListeners($(document), angular); var u2f = new U2f(function (data) { - $scope.login(data); - $scope.$apply(); + $timeout(function () { + $scope.login(data); + }); }, function (error) { - toastr.error(error, i18nService.errorsOccurred); - $scope.$apply(); + $timeout(function () { + toastr.error(error, i18nService.errorsOccurred); + }); }, function (info) { - if (info === 'ready') { - $scope.u2fReady = true; - } - $scope.$apply(); + $timeout(function () { + if (info === 'ready') { + $scope.u2fReady = true; + } + }); }); var constants = constantsService; @@ -62,7 +65,6 @@ $scope.loginPromise.then(function () { $analytics.eventTrack('Logged In From Two-step'); $state.go('tabs.vault', { animation: 'in-slide-left', syncOnLoad: true }); - u2f = null; }, function () { u2f.start(); }); @@ -87,8 +89,6 @@ }; $scope.anotherMethod = function () { - u2f.stop(); - u2f = null; $state.go('twoFactorMethods', { animation: 'in-slide-up', email: email, @@ -99,13 +99,17 @@ }; $scope.back = function () { - u2f.stop(); - u2f = null; $state.go('login', { animation: 'out-slide-right' }); }; + $scope.$on('$destroy', function () { + u2f.stop(); + u2f.cleanup(); + u2f = null; + }); + function getDefaultProvider(twoFactorProviders) { var keys = Object.keys(twoFactorProviders); var providerType = null; @@ -127,6 +131,7 @@ function init() { u2f.stop(); + u2f.cleanup(); $timeout(function () { $('#code').focus(); diff --git a/src/scripts/u2f.js b/src/scripts/u2f.js index f53ddb97..2e5b7ae7 100644 --- a/src/scripts/u2f.js +++ b/src/scripts/u2f.js @@ -6,65 +6,79 @@ this.connectorLink = document.createElement('a'); } -U2f.prototype.init = function (data) { - var self = this; +(function () { + var thisU2f = null; - self.connectorLink.href = 'https://vault.bitwarden.com/u2f-connector.html' + - '?data=' + this.base64Encode(JSON.stringify(data)) + - '&parent=' + encodeURIComponent(document.location.href) + - '&v=1'; + U2f.prototype.init = function (data) { + var self = thisU2f = this; - self.iframe = document.getElementById('u2f_iframe'); - self.iframe.src = self.connectorLink.href; + self.connectorLink.href = 'https://vault.bitwarden.com/u2f-connector.html' + + '?data=' + this.base64Encode(JSON.stringify(data)) + + '&parent=' + encodeURIComponent(document.location.href) + + '&v=1'; - window.addEventListener('message', function (event) { - if (!self.validMessage(event)) { - self.error('Invalid message.'); + self.iframe = document.getElementById('u2f_iframe'); + self.iframe.src = self.connectorLink.href; + + window.addEventListener('message', parseMessage, false); + }; + + U2f.prototype.validMessage = function (event) { + if (!event.origin || event.origin === '' || event.origin !== this.connectorLink.origin) { + return false; + } + + return event.data.indexOf('success|') === 0 || event.data.indexOf('error|') === 0 || event.data.indexOf('info|') === 0; + }; + + U2f.prototype.stop = function () { + this.sendMessage('stop'); + }; + + U2f.prototype.start = function () { + this.sendMessage('start'); + }; + + U2f.prototype.sendMessage = function (message) { + var self = this; + if (!self.iframe || !self.iframe.src || !self.iframe.contentWindow) { + return; + } + + self.iframe.contentWindow.postMessage(message, self.iframe.src); + }; + + U2f.prototype.base64Encode = function (str) { + return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function (match, p1) { + return String.fromCharCode('0x' + p1); + })); + }; + + U2f.prototype.cleanup = function () { + window.removeEventListener('message', parseMessage, false); + }; + + function parseMessage(event) { + if (!thisU2f) { + return; + } + + if (!thisU2f.validMessage(event)) { + thisU2f.error('Invalid message.'); return; } var parts = event.data.split('|'); - if (parts[0] === 'success' && self.success) { - self.success(parts[1]); + if (parts[0] === 'success' && thisU2f.success) { + thisU2f.success(parts[1]); } - else if (parts[0] === 'error' && self.error) { - self.error(parts[1]); + else if (parts[0] === 'error' && thisU2f.error) { + thisU2f.error(parts[1]); } else if (parts[0] === 'info') { - if (self.info) { - self.info(parts[1]); + if (thisU2f.info) { + thisU2f.info(parts[1]); } } - }, false); -}; - -U2f.prototype.validMessage = function (event) { - if (!event.origin || event.origin === '' || event.origin !== this.connectorLink.origin) { - return false; - } - - return event.data.indexOf('success|') === 0 || event.data.indexOf('error|') === 0 || event.data.indexOf('info|') === 0; -}; - -U2f.prototype.stop = function () { - this.sendMessage('stop'); -}; - -U2f.prototype.start = function () { - this.sendMessage('start'); -}; - -U2f.prototype.sendMessage = function (message) { - var self = this; - if (!self.iframe || !self.iframe.src || !self.iframe.contentWindow) { - return; - } - - self.iframe.contentWindow.postMessage(message, self.iframe.src); -}; - -U2f.prototype.base64Encode = function (str) { - return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function (match, p1) { - return String.fromCharCode('0x' + p1); - })); -}; + }; +})();