diff --git a/src/popup/app/accounts/accountsLoginController.js b/src/popup/app/accounts/accountsLoginController.js index 5ad41060e2..5382e62459 100644 --- a/src/popup/app/accounts/accountsLoginController.js +++ b/src/popup/app/accounts/accountsLoginController.js @@ -33,7 +33,7 @@ angular return; } - $scope.loginPromise = authService.logIn(model.email, model.masterPassword, null, null); + $scope.loginPromise = authService.logIn(model.email, model.masterPassword); $scope.loginPromise.then(function (response) { if (response.twoFactor) { diff --git a/src/popup/app/accounts/accountsLoginTwoFactorController.js b/src/popup/app/accounts/accountsLoginTwoFactorController.js index d3df2f32f4..990017c211 100644 --- a/src/popup/app/accounts/accountsLoginTwoFactorController.js +++ b/src/popup/app/accounts/accountsLoginTwoFactorController.js @@ -36,17 +36,17 @@ angular }); var constants = constantsService; - var email = $stateParams.email; - var masterPassword = $stateParams.masterPassword; - var providers = $stateParams.providers; + var email = authService.email; + var masterPasswordHash = authService.masterPasswordHash; + var providers = authService.twoFactorProviders; - if (!email || !masterPassword || !providers) { + if (!email || !masterPasswordHash || !providers) { $state.go('login'); return; } $scope.providerType = $stateParams.provider || $stateParams.provider === 0 ? $stateParams.provider : - getDefaultProvider(providers); + authService.getDefaultTwoFactorProvider(platformUtilsService.supportsU2f($window)); $scope.twoFactorEmail = null; $scope.token = null; $scope.constantsProvider = constants.twoFactorProvider; @@ -74,7 +74,7 @@ angular token = token.replace(' ', ''); } - $scope.loginPromise = authService.logIn(email, masterPassword, $scope.providerType, token, $scope.remember.checked); + $scope.loginPromise = authService.logInTwoFactor($scope.providerType, token, $scope.remember.checked); $scope.loginPromise.then(function () { $analytics.eventTrack('Logged In From Two-step'); $state.go('tabs.vault', { animation: 'in-slide-left', syncOnLoad: true }).then(function () { @@ -97,25 +97,19 @@ angular return; } - var key = cryptoService.makeKey(masterPassword, email); - cryptoService.hashPassword(masterPassword, key).then(function (hash) { - var request = new TwoFactorEmailRequest(email, hash); - apiService.postTwoFactorEmail(request, function () { - if (doToast) { - toastr.success('Verification email sent to ' + $scope.twoFactorEmail + '.'); - } - }, function () { - toastr.error('Could not send verification email.'); - }); + var request = new TwoFactorEmailRequest(email, masterPasswordHash); + apiService.postTwoFactorEmail(request, function () { + if (doToast) { + toastr.success('Verification email sent to ' + $scope.twoFactorEmail + '.'); + } + }, function () { + toastr.error('Could not send verification email.'); }); }; $scope.anotherMethod = function () { $state.go('twoFactorMethods', { animation: 'in-slide-up', - email: email, - masterPassword: masterPassword, - providers: providers, provider: $scope.providerType }); }; @@ -140,25 +134,6 @@ angular } }); - function getDefaultProvider(twoFactorProviders) { - var keys = Object.keys(twoFactorProviders); - var providerType = null; - var providerPriority = -1; - for (var i = 0; i < keys.length; i++) { - var provider = $filter('filter')(constants.twoFactorProviderInfo, { type: keys[i], active: true }); - if (provider.length && provider[0].priority > providerPriority) { - if (provider[0].type == constants.twoFactorProvider.u2f && (typeof $window.u2f === 'undefined') && - !platformUtilsService.isChrome() && !platformUtilsService.isOpera()) { - continue; - } - - providerType = provider[0].type; - providerPriority = provider[0].priority; - } - } - return providerType === null ? null : parseInt(providerType); - } - function init() { u2f.stop(); u2f.cleanup(); @@ -169,9 +144,8 @@ angular codeInput.focus(); } - var params; + var params = providers.get($scope.providerType); if ($scope.providerType === constants.twoFactorProvider.duo) { - params = providers[constants.twoFactorProvider.duo]; if (platformUtilsService.isSafari()) { var tab = BrowserApi.createNewTab(BrowserApi.getAssetUrl('2fa/index.html')); var tabToSend = BrowserApi.makeTabObject(tab); @@ -200,7 +174,6 @@ angular } } else if ($scope.providerType === constants.twoFactorProvider.u2f) { - params = providers[constants.twoFactorProvider.u2f]; var challenges = JSON.parse(params.Challenges); u2f.init({ @@ -213,7 +186,6 @@ angular }); } else if ($scope.providerType === constants.twoFactorProvider.email) { - params = providers[constants.twoFactorProvider.email]; $scope.twoFactorEmail = params.Email; if (!platformUtilsService.isSafari() && BrowserApi.isPopupOpen() && @@ -230,12 +202,12 @@ angular BrowserApi.createNewTab('/popup/index.html?uilocation=tab#!/login', true); return; } - else if (Object.keys(providers).length > 1) { + else if (providers.size > 1) { $scope.sendEmail(false); } }); } - else if (Object.keys(providers).length > 1) { + else if (providers.size > 1) { $scope.sendEmail(false); } } diff --git a/src/popup/app/accounts/accountsTwoFactorMethodsController.js b/src/popup/app/accounts/accountsTwoFactorMethodsController.js index 333f759b14..8a77dfe346 100644 --- a/src/popup/app/accounts/accountsTwoFactorMethodsController.js +++ b/src/popup/app/accounts/accountsTwoFactorMethodsController.js @@ -2,50 +2,41 @@ angular .module('bit.accounts') .controller('accountsTwoFactorMethodsController', function ($scope, $state, $stateParams, constantsService, - utilsService, i18nService, $analytics, platformUtilsService) { + utilsService, i18nService, $analytics, platformUtilsService, authService, $window) { $scope.i18n = i18nService; var constants = constantsService; - var masterPassword = $stateParams.masterPassword; - var email = $stateParams.email; - var providers = $stateParams.providers; + var providers = authService.twoFactorProviders; var provider = $stateParams.provider; $scope.providers = []; - if (providers.hasOwnProperty(constants.twoFactorProvider.authenticator)) { + if (providers.get(constants.twoFactorProvider.authenticator)) { add(constants.twoFactorProvider.authenticator); } - if (providers.hasOwnProperty(constants.twoFactorProvider.yubikey)) { + if (providers.get(constants.twoFactorProvider.yubikey)) { add(constants.twoFactorProvider.yubikey); } - if (providers.hasOwnProperty(constants.twoFactorProvider.email)) { + if (providers.get(constants.twoFactorProvider.email)) { add(constants.twoFactorProvider.email); } - if (providers.hasOwnProperty(constants.twoFactorProvider.duo)) { + if (providers.get(constants.twoFactorProvider.duo)) { add(constants.twoFactorProvider.duo); } - if (providers.hasOwnProperty(constants.twoFactorProvider.u2f) && - (platformUtilsService.isChrome() || platformUtilsService.isOpera())) { + if (providers.get(constants.twoFactorProvider.u2f) && platformUtilsService.supportsU2f($window)) { add(constants.twoFactorProvider.u2f); } - $scope.choose = function (provider) { + $scope.choose = function (p) { $state.go('twoFactor', { animation: 'out-slide-down', - email: email, - masterPassword: masterPassword, - providers: providers, - provider: provider.type + provider: p.type }); }; $scope.cancel = function () { $state.go('twoFactor', { animation: 'out-slide-down', - email: email, - masterPassword: masterPassword, - providers: providers, provider: provider }); }; diff --git a/src/popup/app/config.js b/src/popup/app/config.js index e74869350d..fa47f26e88 100644 --- a/src/popup/app/config.js +++ b/src/popup/app/config.js @@ -84,14 +84,14 @@ angular controller: 'accountsLoginTwoFactorController', template: require('./accounts/views/accountsLoginTwoFactor.html'), data: { authorize: false }, - params: { animation: null, email: null, masterPassword: null, providers: null, provider: null } + params: { animation: null, provider: null } }) .state('twoFactorMethods', { url: '/two-factor-methods', controller: 'accountsTwoFactorMethodsController', template: require('./accounts/views/accountsTwoFactorMethods.html'), data: { authorize: false }, - params: { animation: null, email: null, masterPassword: null, providers: null, provider: null } + params: { animation: null, provider: null } }) .state('register', { url: '/register', diff --git a/src/popup/app/global/main.controller.ts b/src/popup/app/global/main.controller.ts index 3c5adbac7d..a45401c6d8 100644 --- a/src/popup/app/global/main.controller.ts +++ b/src/popup/app/global/main.controller.ts @@ -1,7 +1,6 @@ import { BrowserApi } from '../../../browser/browserApi'; -import { AuthService } from '../services/auth.service'; - +import { AuthService } from 'jslib/abstractions/auth.service'; import { UtilsService } from 'jslib/abstractions/utils.service'; export class MainController implements ng.IController { diff --git a/src/popup/app/services/auth.service.ts b/src/popup/app/services/auth.service.ts deleted file mode 100644 index 363f96b26a..0000000000 --- a/src/popup/app/services/auth.service.ts +++ /dev/null @@ -1,84 +0,0 @@ -import { DeviceRequest } from 'jslib/models/request/deviceRequest'; -import { TokenRequest } from 'jslib/models/request/tokenRequest'; - -import { ConstantsService } from 'jslib/services/constants.service'; - -import { ApiService } from 'jslib/abstractions/api.service'; -import { AppIdService } from 'jslib/abstractions/appId.service'; -import { CryptoService } from 'jslib/abstractions/crypto.service'; -import { MessagingService } from 'jslib/abstractions/messaging.service'; -import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service'; -import { TokenService } from 'jslib/abstractions/token.service'; -import { UserService } from 'jslib/abstractions/user.service'; - -export class AuthService { - constructor(public cryptoService: CryptoService, public apiService: ApiService, public userService: UserService, - public tokenService: TokenService, public $rootScope: any, public appIdService: AppIdService, - public platformUtilsService: PlatformUtilsService, public constantsService: ConstantsService, - public messagingService: MessagingService) { - } - - async logIn(email: string, masterPassword: string, twoFactorProvider?: number, - twoFactorToken?: string, remember?: boolean) { - email = email.toLowerCase(); - - const key = this.cryptoService.makeKey(masterPassword, email); - const appId = await this.appIdService.getAppId(); - const storedTwoFactorToken = await this.tokenService.getTwoFactorToken(email); - const hashedPassword = await this.cryptoService.hashPassword(masterPassword, key); - - const deviceRequest = new DeviceRequest(appId, this.platformUtilsService); - - let request: TokenRequest; - - if (twoFactorToken != null && twoFactorProvider != null) { - request = new TokenRequest(email, hashedPassword, twoFactorProvider, twoFactorToken, remember, - deviceRequest); - } else if (storedTwoFactorToken) { - request = new TokenRequest(email, hashedPassword, this.constantsService.twoFactorProvider.remember, - storedTwoFactorToken, false, deviceRequest); - } else { - request = new TokenRequest(email, hashedPassword, null, null, false, deviceRequest); - } - - const response = await this.apiService.postIdentityToken(request); - if (!response) { - return; - } - - if (!response.accessToken) { - // two factor required - return { - twoFactor: true, - twoFactorProviders: response, - }; - } - - if (response.twoFactorToken) { - this.tokenService.setTwoFactorToken(response.twoFactorToken, email); - } - - await this.tokenService.setTokens(response.accessToken, response.refreshToken); - await this.cryptoService.setKey(key); - await this.cryptoService.setKeyHash(hashedPassword); - await this.userService.setUserIdAndEmail(this.tokenService.getUserId(), this.tokenService.getEmail()); - await this.cryptoService.setEncKey(response.key); - await this.cryptoService.setEncPrivateKey(response.privateKey); - - this.messagingService.send('loggedIn'); - return { - twoFactor: false, - twoFactorProviders: null, - }; - } - - logOut(callback: Function) { - this.$rootScope.vaultCiphers = null; - this.$rootScope.vaultFolders = null; - this.$rootScope.vaultCollections = null; - callback(); - } -} - -AuthService.$inject = ['cryptoService', 'apiService', 'userService', 'tokenService', '$rootScope', 'appIdService', - 'platformUtilsService', 'constantsService', 'messagingService']; diff --git a/src/popup/app/services/background.service.ts b/src/popup/app/services/background.service.ts index e135d8a4bf..40e1bbd43f 100644 --- a/src/popup/app/services/background.service.ts +++ b/src/popup/app/services/background.service.ts @@ -9,6 +9,7 @@ import { CollectionService } from 'jslib/abstractions/collection.service'; import { CryptoService } from 'jslib/abstractions/crypto.service'; import { EnvironmentService } from 'jslib/abstractions/environment.service'; import { FolderService } from 'jslib/abstractions/folder.service'; +import { I18nService } from 'jslib/abstractions/i18n.service'; import { LockService } from 'jslib/abstractions/lock.service'; import { PasswordGenerationService } from 'jslib/abstractions/passwordGeneration.service'; import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service'; @@ -43,6 +44,7 @@ export const platformUtilsService = getBackgroundService(' export const utilsService = getBackgroundService('utilsService'); export const appIdService = getBackgroundService('appIdService'); export const i18nService = getBackgroundService('i18nService'); +export const i18n2Service = getBackgroundService('i18n2Service'); export const constantsService = getBackgroundService('constantsService'); export const settingsService = getBackgroundService('settingsService'); export const lockService = getBackgroundService('lockService'); diff --git a/src/popup/app/services/services.module.ts b/src/popup/app/services/services.module.ts index bc22460381..04fbc06104 100644 --- a/src/popup/app/services/services.module.ts +++ b/src/popup/app/services/services.module.ts @@ -1,21 +1,27 @@ import * as angular from 'angular'; -import { AuthService } from './auth.service'; import * as backgroundServices from './background.service'; import { PopupUtilsService } from './popupUtils.service'; import { StateService } from './state.service'; import { ValidationService } from './validation.service'; +import { AuthService } from 'jslib/services/auth.service'; + import BrowserMessagingService from '../../../services/browserMessaging.service'; const messagingService = new BrowserMessagingService(backgroundServices.platformUtilsService()); +const authService = new AuthService(backgroundServices.cryptoService(), backgroundServices.apiService(), + backgroundServices.userService(), backgroundServices.tokenService(), backgroundServices.appIdService(), + backgroundServices.i18n2Service(), backgroundServices.platformUtilsService(), + backgroundServices.constantsService(), messagingService); +authService.init(); export default angular .module('bit.services', ['toastr']) .service('stateService', StateService) .service('validationService', ValidationService) - .service('authService', AuthService) .service('popupUtilsService', PopupUtilsService) + .factory('authService', () => authService) .factory('messagingService', () => messagingService) .factory('storageService', backgroundServices.storageService) .factory('tokenService', backgroundServices.tokenService) diff --git a/src/services/browserPlatformUtils.service.ts b/src/services/browserPlatformUtils.service.ts index 3f18125f00..b83256c0e4 100644 --- a/src/services/browserPlatformUtils.service.ts +++ b/src/services/browserPlatformUtils.service.ts @@ -152,6 +152,14 @@ export default class BrowserPlatformUtilsService implements PlatformUtilsService return BrowserApi.getApplicationVersion(); } + supportsU2f(win: Window): boolean { + if (win != null && (win as any).u2f !== 'undefined') { + return true; + } + + return this.isChrome() || this.isOpera(); + } + private sidebarViewName(): string { if ((window as any).chrome.sidebarAction && this.isFirefox()) { return 'sidebar';