2fa method selection

This commit is contained in:
Kyle Spearrin 2017-06-20 17:06:14 -04:00
parent cf5b0635e4
commit 2f3035a08f
6 changed files with 159 additions and 35 deletions

View File

@ -2,7 +2,7 @@ angular
.module('bit.accounts')
.controller('accountsLoginController', function ($scope, $rootScope, $cookies, apiService, cryptoService, authService,
$state, constants, $analytics) {
$state, constants, $analytics, $uibModal, $timeout) {
$scope.state = $state;
var returnState;
@ -24,8 +24,11 @@ angular
};
}
var email,
masterPassword;
var _email,
_masterPassword;
$scope.twoFactorProviders = null;
$scope.twoFactorProvider = null;
$scope.login = function (model) {
$scope.loginPromise = authService.logIn(model.email, model.masterPassword);
@ -44,12 +47,18 @@ angular
$cookies.remove(constants.rememberedEmailCookieName);
}
if (twoFactorProviders && twoFactorProviders.length > 0) {
email = model.email;
masterPassword = model.masterPassword;
if (twoFactorProviders && Object.keys(twoFactorProviders).length > 0) {
_email = model.email;
_masterPassword = model.masterPassword;
$scope.twoFactorProviders = twoFactorProviders;
$scope.twoFactorProvider = parseInt(Object.keys(twoFactorProviders)[0]);
$analytics.eventTrack('Logged In To Two-step');
$state.go('frontend.login.twoFactor', { returnState: returnState });
$state.go('frontend.login.twoFactor', { returnState: returnState }).then(function () {
$timeout(function () {
$("#code").focus();
});
});
}
else {
$analytics.eventTrack('Logged In');
@ -58,9 +67,8 @@ angular
});
};
$scope.twoFactor = function (model) {
// Only supporting Authenticator (0) provider for now
$scope.twoFactorPromise = authService.logIn(email, masterPassword, model.code, 0);
$scope.twoFactor = function (token) {
$scope.twoFactorPromise = authService.logIn(_email, _masterPassword, token, $scope.twoFactorProvider);
$scope.twoFactorPromise.then(function () {
$analytics.eventTrack('Logged In From Two-step');
@ -68,6 +76,24 @@ angular
});
};
$scope.anotherMethod = function () {
var modal = $uibModal.open({
animation: true,
templateUrl: 'app/accounts/views/accountsTwoFactorMethods.html',
controller: 'accountsTwoFactorMethodsController',
resolve: {
providers: function () { return $scope.twoFactorProviders; }
}
});
modal.result.then(function (provider) {
$scope.twoFactorProvider = provider;
$timeout(function () {
$("#code").focus();
});
});
};
function loggedInGo() {
if (returnState) {
$state.go(returnState.name, returnState.params);

View File

@ -0,0 +1,47 @@
angular
.module('bit.accounts')
.controller('accountsTwoFactorMethodsController', function ($scope, $uibModalInstance, $analytics, providers, constants) {
$analytics.eventTrack('accountsTwoFactorMethodsController', { category: 'Modal' });
$scope.providers = [];
if (providers.hasOwnProperty(constants.twoFactorProvider.authenticator)) {
$scope.providers.push({
id: constants.twoFactorProvider.authenticator,
name: 'Authenticator App'
});
}
if (providers.hasOwnProperty(constants.twoFactorProvider.yubikey)) {
$scope.providers.push({
id: constants.twoFactorProvider.yubikey,
name: 'YubiKey'
});
}
if (providers.hasOwnProperty(constants.twoFactorProvider.email)) {
$scope.providers.push({
id: constants.twoFactorProvider.email,
name: 'Email'
});
}
if (providers.hasOwnProperty(constants.twoFactorProvider.duo)) {
$scope.providers.push({
id: constants.twoFactorProvider.duo,
name: 'Duo'
});
}
if (providers.hasOwnProperty(constants.twoFactorProvider.u2f)) {
$scope.providers.push({
id: constants.twoFactorProvider.u2f,
name: 'FIDO U2F Security Key'
});
}
$scope.choose = function (provider) {
$uibModalInstance.close(provider.id);
};
$scope.close = function () {
$uibModalInstance.dismiss('close');
};
});

View File

@ -1,25 +1,59 @@
<p class="login-box-msg">Enter your two-step verification code.</p>
<form name="twoFactorForm" ng-submit="twoFactorForm.$valid && twoFactor(model)" api-form="twoFactorPromise">
<div class="callout callout-danger validation-errors" ng-show="twoFactorForm.$errors">
<h4>Errors have occurred</h4>
<ul>
<li ng-repeat="e in twoFactorForm.$errors">{{e}}</li>
</ul>
</div>
<div class="form-group has-feedback" show-errors>
<label for="code" class="sr-only">Code</label>
<input type="text" id="code" name="Code" class="form-control" placeholder="Verification code" ng-model="model.code"
required api-field />
<span class="fa fa-lock form-control-feedback"></span>
</div>
<div class="row">
<div class="col-xs-7">
<a ui-sref="frontend.recover">Lost authenticator app?</a>
<div ng-if="twoFactorProvider === 0 || twoFactorProvider === 1">
<p class="login-box-msg" ng-if="twoFactorProvider === 0">
Enter the 6 digit verification code from your authenticator app.
</p>
<p class="login-box-msg" ng-if="twoFactorProvider === 1">
Enter the 6 digit verification code that was emailed to you.
</p>
<form name="twoFactorForm" ng-submit="twoFactorForm.$valid && twoFactor(token)" api-form="twoFactorPromise">
<div class="callout callout-danger validation-errors" ng-show="twoFactorForm.$errors">
<h4>Errors have occurred</h4>
<ul>
<li ng-repeat="e in twoFactorForm.$errors">{{e}}</li>
</ul>
</div>
<div class="col-xs-5">
<button type="submit" class="btn btn-primary btn-block btn-flat" ng-disabled="twoFactorForm.$loading">
<i class="fa fa-refresh fa-spin loading-icon" ng-show="twoFactorForm.$loading"></i>Log In
</button>
<div class="form-group has-feedback" show-errors>
<label for="code" class="sr-only">Code</label>
<input type="text" id="code" name="Code" class="form-control" placeholder="Verification code"
ng-model="token" required api-field />
<span class="fa fa-lock form-control-feedback"></span>
</div>
</div>
</form>
<div class="row">
<div class="col-xs-7">
<a stop-click href="#" ng-click="anotherMethod()">Use another method?</a>
</div>
<div class="col-xs-5">
<button type="submit" class="btn btn-primary btn-block btn-flat" ng-disabled="twoFactorForm.$loading">
<i class="fa fa-refresh fa-spin loading-icon" ng-show="twoFactorForm.$loading"></i>Log In
</button>
</div>
</div>
</form>
</div>
<div ng-if="twoFactorProvider === 3">
<p class="login-box-msg">
Insert your YubiKey into a USB slot and touch its gold button.
</p>
<form name="twoFactorForm" ng-submit="twoFactorForm.$valid && twoFactor(token)" api-form="twoFactorPromise">
<div class="callout callout-danger validation-errors" ng-show="twoFactorForm.$errors">
<h4>Errors have occurred</h4>
<ul>
<li ng-repeat="e in twoFactorForm.$errors">{{e}}</li>
</ul>
</div>
<div class="form-group" show-errors>
<label for="code" class="sr-only">Token</label>
<input type="password" id="code" name="Token" class="form-control" ng-model="token" required api-field />
</div>
<div class="row">
<div class="col-xs-7">
<a stop-click href="#" ng-click="anotherMethod()">Use another method?</a>
</div>
<div class="col-xs-5">
<button type="submit" class="btn btn-primary btn-block btn-flat" ng-disabled="twoFactorForm.$loading">
<i class="fa fa-refresh fa-spin loading-icon" ng-show="twoFactorForm.$loading"></i>Log In
</button>
</div>
</div>
</form>
</div>

View File

@ -0,0 +1,15 @@
<div class="modal-header">
<button type="button" class="close" ng-click="close()" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title"><i class="fa fa-key"></i> Two-step Providers</h4>
</div>
<div class="modal-body no-padding">
<div class="list-group" ng-repeat="provider in providers">
<a href="#" stop-click class="list-group-item" ng-click="choose(provider)">
<h4 class="list-group-item-heading">{{::provider.name}}</h4>
<p class="list-group-item-text">{{::provider.description}}</p>
</a>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default btn-flat" ng-click="close()">Close</button>
</div>

View File

@ -63,8 +63,9 @@ angular
}, function (error) {
_service.logOut();
if (error.status === 400 && error.data.TwoFactorProviders && error.data.TwoFactorProviders.length) {
deferred.resolve(error.data.TwoFactorProviders);
if (error.status === 400 && error.data.TwoFactorProviders2 &&
Object.keys(error.data.TwoFactorProviders2).length) {
deferred.resolve(error.data.TwoFactorProviders2);
}
else {
deferred.reject(error);

View File

@ -147,6 +147,7 @@
<script src="app/accounts/accountsPasswordHintController.js"></script>
<script src="app/accounts/accountsRecoverController.js"></script>
<script src="app/accounts/accountsOrganizationAcceptController.js"></script>
<script src="app/accounts/accountsTwoFactorMethodsController.js"></script>
<script src="app/vault/vaultModule.js"></script>
<script src="app/vault/vaultController.js"></script>