1
0
mirror of https://github.com/bitwarden/browser.git synced 2024-11-09 09:51:02 +01:00

switch to jslib auth service

This commit is contained in:
Kyle Spearrin 2018-02-01 22:53:36 -05:00
parent f382f125be
commit 146254b646
9 changed files with 47 additions and 153 deletions

View File

@ -33,7 +33,7 @@ angular
return; return;
} }
$scope.loginPromise = authService.logIn(model.email, model.masterPassword, null, null); $scope.loginPromise = authService.logIn(model.email, model.masterPassword);
$scope.loginPromise.then(function (response) { $scope.loginPromise.then(function (response) {
if (response.twoFactor) { if (response.twoFactor) {

View File

@ -36,17 +36,17 @@ angular
}); });
var constants = constantsService; var constants = constantsService;
var email = $stateParams.email; var email = authService.email;
var masterPassword = $stateParams.masterPassword; var masterPasswordHash = authService.masterPasswordHash;
var providers = $stateParams.providers; var providers = authService.twoFactorProviders;
if (!email || !masterPassword || !providers) { if (!email || !masterPasswordHash || !providers) {
$state.go('login'); $state.go('login');
return; return;
} }
$scope.providerType = $stateParams.provider || $stateParams.provider === 0 ? $stateParams.provider : $scope.providerType = $stateParams.provider || $stateParams.provider === 0 ? $stateParams.provider :
getDefaultProvider(providers); authService.getDefaultTwoFactorProvider(platformUtilsService.supportsU2f($window));
$scope.twoFactorEmail = null; $scope.twoFactorEmail = null;
$scope.token = null; $scope.token = null;
$scope.constantsProvider = constants.twoFactorProvider; $scope.constantsProvider = constants.twoFactorProvider;
@ -74,7 +74,7 @@ angular
token = token.replace(' ', ''); 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 () { $scope.loginPromise.then(function () {
$analytics.eventTrack('Logged In From Two-step'); $analytics.eventTrack('Logged In From Two-step');
$state.go('tabs.vault', { animation: 'in-slide-left', syncOnLoad: true }).then(function () { $state.go('tabs.vault', { animation: 'in-slide-left', syncOnLoad: true }).then(function () {
@ -97,9 +97,7 @@ angular
return; return;
} }
var key = cryptoService.makeKey(masterPassword, email); var request = new TwoFactorEmailRequest(email, masterPasswordHash);
cryptoService.hashPassword(masterPassword, key).then(function (hash) {
var request = new TwoFactorEmailRequest(email, hash);
apiService.postTwoFactorEmail(request, function () { apiService.postTwoFactorEmail(request, function () {
if (doToast) { if (doToast) {
toastr.success('Verification email sent to ' + $scope.twoFactorEmail + '.'); toastr.success('Verification email sent to ' + $scope.twoFactorEmail + '.');
@ -107,15 +105,11 @@ angular
}, function () { }, function () {
toastr.error('Could not send verification email.'); toastr.error('Could not send verification email.');
}); });
});
}; };
$scope.anotherMethod = function () { $scope.anotherMethod = function () {
$state.go('twoFactorMethods', { $state.go('twoFactorMethods', {
animation: 'in-slide-up', animation: 'in-slide-up',
email: email,
masterPassword: masterPassword,
providers: providers,
provider: $scope.providerType 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() { function init() {
u2f.stop(); u2f.stop();
u2f.cleanup(); u2f.cleanup();
@ -169,9 +144,8 @@ angular
codeInput.focus(); codeInput.focus();
} }
var params; var params = providers.get($scope.providerType);
if ($scope.providerType === constants.twoFactorProvider.duo) { if ($scope.providerType === constants.twoFactorProvider.duo) {
params = providers[constants.twoFactorProvider.duo];
if (platformUtilsService.isSafari()) { if (platformUtilsService.isSafari()) {
var tab = BrowserApi.createNewTab(BrowserApi.getAssetUrl('2fa/index.html')); var tab = BrowserApi.createNewTab(BrowserApi.getAssetUrl('2fa/index.html'));
var tabToSend = BrowserApi.makeTabObject(tab); var tabToSend = BrowserApi.makeTabObject(tab);
@ -200,7 +174,6 @@ angular
} }
} }
else if ($scope.providerType === constants.twoFactorProvider.u2f) { else if ($scope.providerType === constants.twoFactorProvider.u2f) {
params = providers[constants.twoFactorProvider.u2f];
var challenges = JSON.parse(params.Challenges); var challenges = JSON.parse(params.Challenges);
u2f.init({ u2f.init({
@ -213,7 +186,6 @@ angular
}); });
} }
else if ($scope.providerType === constants.twoFactorProvider.email) { else if ($scope.providerType === constants.twoFactorProvider.email) {
params = providers[constants.twoFactorProvider.email];
$scope.twoFactorEmail = params.Email; $scope.twoFactorEmail = params.Email;
if (!platformUtilsService.isSafari() && BrowserApi.isPopupOpen() && if (!platformUtilsService.isSafari() && BrowserApi.isPopupOpen() &&
@ -230,12 +202,12 @@ angular
BrowserApi.createNewTab('/popup/index.html?uilocation=tab#!/login', true); BrowserApi.createNewTab('/popup/index.html?uilocation=tab#!/login', true);
return; return;
} }
else if (Object.keys(providers).length > 1) { else if (providers.size > 1) {
$scope.sendEmail(false); $scope.sendEmail(false);
} }
}); });
} }
else if (Object.keys(providers).length > 1) { else if (providers.size > 1) {
$scope.sendEmail(false); $scope.sendEmail(false);
} }
} }

View File

@ -2,50 +2,41 @@ angular
.module('bit.accounts') .module('bit.accounts')
.controller('accountsTwoFactorMethodsController', function ($scope, $state, $stateParams, constantsService, .controller('accountsTwoFactorMethodsController', function ($scope, $state, $stateParams, constantsService,
utilsService, i18nService, $analytics, platformUtilsService) { utilsService, i18nService, $analytics, platformUtilsService, authService, $window) {
$scope.i18n = i18nService; $scope.i18n = i18nService;
var constants = constantsService; var constants = constantsService;
var masterPassword = $stateParams.masterPassword; var providers = authService.twoFactorProviders;
var email = $stateParams.email;
var providers = $stateParams.providers;
var provider = $stateParams.provider; var provider = $stateParams.provider;
$scope.providers = []; $scope.providers = [];
if (providers.hasOwnProperty(constants.twoFactorProvider.authenticator)) { if (providers.get(constants.twoFactorProvider.authenticator)) {
add(constants.twoFactorProvider.authenticator); add(constants.twoFactorProvider.authenticator);
} }
if (providers.hasOwnProperty(constants.twoFactorProvider.yubikey)) { if (providers.get(constants.twoFactorProvider.yubikey)) {
add(constants.twoFactorProvider.yubikey); add(constants.twoFactorProvider.yubikey);
} }
if (providers.hasOwnProperty(constants.twoFactorProvider.email)) { if (providers.get(constants.twoFactorProvider.email)) {
add(constants.twoFactorProvider.email); add(constants.twoFactorProvider.email);
} }
if (providers.hasOwnProperty(constants.twoFactorProvider.duo)) { if (providers.get(constants.twoFactorProvider.duo)) {
add(constants.twoFactorProvider.duo); add(constants.twoFactorProvider.duo);
} }
if (providers.hasOwnProperty(constants.twoFactorProvider.u2f) && if (providers.get(constants.twoFactorProvider.u2f) && platformUtilsService.supportsU2f($window)) {
(platformUtilsService.isChrome() || platformUtilsService.isOpera())) {
add(constants.twoFactorProvider.u2f); add(constants.twoFactorProvider.u2f);
} }
$scope.choose = function (provider) { $scope.choose = function (p) {
$state.go('twoFactor', { $state.go('twoFactor', {
animation: 'out-slide-down', animation: 'out-slide-down',
email: email, provider: p.type
masterPassword: masterPassword,
providers: providers,
provider: provider.type
}); });
}; };
$scope.cancel = function () { $scope.cancel = function () {
$state.go('twoFactor', { $state.go('twoFactor', {
animation: 'out-slide-down', animation: 'out-slide-down',
email: email,
masterPassword: masterPassword,
providers: providers,
provider: provider provider: provider
}); });
}; };

View File

@ -84,14 +84,14 @@ angular
controller: 'accountsLoginTwoFactorController', controller: 'accountsLoginTwoFactorController',
template: require('./accounts/views/accountsLoginTwoFactor.html'), template: require('./accounts/views/accountsLoginTwoFactor.html'),
data: { authorize: false }, data: { authorize: false },
params: { animation: null, email: null, masterPassword: null, providers: null, provider: null } params: { animation: null, provider: null }
}) })
.state('twoFactorMethods', { .state('twoFactorMethods', {
url: '/two-factor-methods', url: '/two-factor-methods',
controller: 'accountsTwoFactorMethodsController', controller: 'accountsTwoFactorMethodsController',
template: require('./accounts/views/accountsTwoFactorMethods.html'), template: require('./accounts/views/accountsTwoFactorMethods.html'),
data: { authorize: false }, data: { authorize: false },
params: { animation: null, email: null, masterPassword: null, providers: null, provider: null } params: { animation: null, provider: null }
}) })
.state('register', { .state('register', {
url: '/register', url: '/register',

View File

@ -1,7 +1,6 @@
import { BrowserApi } from '../../../browser/browserApi'; 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'; import { UtilsService } from 'jslib/abstractions/utils.service';
export class MainController implements ng.IController { export class MainController implements ng.IController {

View File

@ -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'];

View File

@ -9,6 +9,7 @@ import { CollectionService } from 'jslib/abstractions/collection.service';
import { CryptoService } from 'jslib/abstractions/crypto.service'; import { CryptoService } from 'jslib/abstractions/crypto.service';
import { EnvironmentService } from 'jslib/abstractions/environment.service'; import { EnvironmentService } from 'jslib/abstractions/environment.service';
import { FolderService } from 'jslib/abstractions/folder.service'; import { FolderService } from 'jslib/abstractions/folder.service';
import { I18nService } from 'jslib/abstractions/i18n.service';
import { LockService } from 'jslib/abstractions/lock.service'; import { LockService } from 'jslib/abstractions/lock.service';
import { PasswordGenerationService } from 'jslib/abstractions/passwordGeneration.service'; import { PasswordGenerationService } from 'jslib/abstractions/passwordGeneration.service';
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service'; import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
@ -43,6 +44,7 @@ export const platformUtilsService = getBackgroundService<PlatformUtilsService>('
export const utilsService = getBackgroundService<UtilsService>('utilsService'); export const utilsService = getBackgroundService<UtilsService>('utilsService');
export const appIdService = getBackgroundService<AppIdService>('appIdService'); export const appIdService = getBackgroundService<AppIdService>('appIdService');
export const i18nService = getBackgroundService<any>('i18nService'); export const i18nService = getBackgroundService<any>('i18nService');
export const i18n2Service = getBackgroundService<I18nService>('i18n2Service');
export const constantsService = getBackgroundService<ConstantsService>('constantsService'); export const constantsService = getBackgroundService<ConstantsService>('constantsService');
export const settingsService = getBackgroundService<SettingsService>('settingsService'); export const settingsService = getBackgroundService<SettingsService>('settingsService');
export const lockService = getBackgroundService<LockService>('lockService'); export const lockService = getBackgroundService<LockService>('lockService');

View File

@ -1,21 +1,27 @@
import * as angular from 'angular'; import * as angular from 'angular';
import { AuthService } from './auth.service';
import * as backgroundServices from './background.service'; import * as backgroundServices from './background.service';
import { PopupUtilsService } from './popupUtils.service'; import { PopupUtilsService } from './popupUtils.service';
import { StateService } from './state.service'; import { StateService } from './state.service';
import { ValidationService } from './validation.service'; import { ValidationService } from './validation.service';
import { AuthService } from 'jslib/services/auth.service';
import BrowserMessagingService from '../../../services/browserMessaging.service'; import BrowserMessagingService from '../../../services/browserMessaging.service';
const messagingService = new BrowserMessagingService(backgroundServices.platformUtilsService()); 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 export default angular
.module('bit.services', ['toastr']) .module('bit.services', ['toastr'])
.service('stateService', StateService) .service('stateService', StateService)
.service('validationService', ValidationService) .service('validationService', ValidationService)
.service('authService', AuthService)
.service('popupUtilsService', PopupUtilsService) .service('popupUtilsService', PopupUtilsService)
.factory('authService', () => authService)
.factory('messagingService', () => messagingService) .factory('messagingService', () => messagingService)
.factory('storageService', backgroundServices.storageService) .factory('storageService', backgroundServices.storageService)
.factory('tokenService', backgroundServices.tokenService) .factory('tokenService', backgroundServices.tokenService)

View File

@ -152,6 +152,14 @@ export default class BrowserPlatformUtilsService implements PlatformUtilsService
return BrowserApi.getApplicationVersion(); 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 { private sidebarViewName(): string {
if ((window as any).chrome.sidebarAction && this.isFirefox()) { if ((window as any).chrome.sidebarAction && this.isFirefox()) {
return 'sidebar'; return 'sidebar';