implement two-factor setup page

This commit is contained in:
Kyle Spearrin 2018-06-26 22:51:58 -04:00
parent 381da132f8
commit e345bbcae0
9 changed files with 142 additions and 5 deletions

2
jslib

@ -1 +1 @@
Subproject commit 32a636e5a5068f705b167f8f16dd15b53493b821
Subproject commit 3cc759791e12b7692fc2d2b4be1a2b010eee1c8e

View File

@ -18,6 +18,7 @@ import { AccountComponent } from './settings/account.component';
import { DomainRulesComponent } from './settings/domain-rules.component';
import { OptionsComponent } from './settings/options.component';
import { SettingsComponent } from './settings/settings.component';
import { TwoFactorSetupComponent } from './settings/two-factor-setup.component';
import { ExportComponent } from './tools/export.component';
import { ImportComponent } from './tools/import.component';
@ -55,6 +56,7 @@ const routes: Routes = [
{ path: 'account', component: AccountComponent, canActivate: [AuthGuardService] },
{ path: 'options', component: OptionsComponent, canActivate: [AuthGuardService] },
{ path: 'domain-rules', component: DomainRulesComponent, canActivate: [AuthGuardService] },
{ path: 'two-factor', component: TwoFactorSetupComponent, canActivate: [AuthGuardService] },
],
},
{

View File

@ -42,6 +42,7 @@ import { OptionsComponent } from './settings/options.component';
import { ProfileComponent } from './settings/profile.component';
import { PurgeVaultComponent } from './settings/purge-vault.component';
import { SettingsComponent } from './settings/settings.component';
import { TwoFactorSetupComponent } from './settings/two-factor-setup.component';
import { ExportComponent } from './tools/export.component';
import { ImportComponent } from './tools/import.component';
@ -144,6 +145,7 @@ import { SearchCiphersPipe } from 'jslib/angular/pipes/search-ciphers.pipe';
TrueFalseValueDirective,
TwoFactorComponent,
TwoFactorOptionsComponent,
TwoFactorSetupComponent,
UserLayoutComponent,
VaultComponent,
],

View File

@ -16,8 +16,8 @@
<a routerLink="billing" class="list-group-item" routerLinkActive="active">
Billing &amp; Licensing
</a>
<a routerLink="two-step" class="list-group-item" routerLinkActive="active">
Two-step Login
<a routerLink="two-factor" class="list-group-item" routerLinkActive="active">
{{'twoStepLogin' | i18n}}
</a>
<a routerLink="domain-rules" class="list-group-item" routerLinkActive="active">
Domain Rules

View File

@ -0,0 +1,35 @@
<div class="page-header">
<h1>{{'twoStepLogin' | i18n}}</h1>
</div>
<app-callout type="warning">
<p>{{'twoStepLoginRecoveryWarning' | i18n}}</p>
<button type="button" class="btn btn-outline-secondary">{{'viewRecoveryCode' | i18n}}</button>
</app-callout>
<h2 class="mt-5">
{{'providers' | i18n}}
<small *ngIf="loading">
<i class="fa fa-spinner fa-spin text-muted"></i>
</small>
</h2>
<ul class="list-group list-group-2fa">
<li *ngFor="let p of providers" class="list-group-item d-flex align-items-center">
<div class="logo-2fa d-flex justify-content-center">
<img [src]="'../images/two-factor/' + p.type + '.png'" alt="">
</div>
<div class="mx-4">
<h3 class="mb-0">
{{p.name}}
<i class="fa fa-check text-success fa-fw" *ngIf="p.enabled" title="{{'enabled' | i18n}}"></i>
<a href="#" appStopClick class="badge badge-primary" *ngIf="!premium && p.premium">
{{'premium' | i18n}}
</a>
</h3>
{{p.description}}
</div>
<div class="ml-auto">
<button type="button" class="btn btn-outline-secondary btn-sm" [disabled]="!premium && p.premium">
{{'manage' | i18n}}
</button>
</div>
</li>
</ul>

View File

@ -0,0 +1,69 @@
import {
Component,
OnInit,
} from '@angular/core';
import { ToasterService } from 'angular2-toaster';
import { Angulartics2 } from 'angulartics2';
import { ApiService } from 'jslib/abstractions/api.service';
import { I18nService } from 'jslib/abstractions/i18n.service';
import { TokenService } from 'jslib/abstractions/token.service';
import { TwoFactorProviders } from 'jslib/services/auth.service';
import { TwoFactorProviderType } from 'jslib/enums/twoFactorProviderType';
@Component({
selector: 'app-two-factor-setup',
templateUrl: 'two-factor-setup.component.html',
})
export class TwoFactorSetupComponent implements OnInit {
providers: any[] = [];
premium: boolean;
loading = true;
constructor(private apiService: ApiService, private i18nService: I18nService,
private analytics: Angulartics2, private toasterService: ToasterService,
private tokenService: TokenService) { }
async ngOnInit() {
this.premium = this.tokenService.getPremium();
for (const key in TwoFactorProviders) {
if (!TwoFactorProviders.hasOwnProperty(key)) {
continue;
}
const p = (TwoFactorProviders as any)[key];
if (p.type === TwoFactorProviderType.OrganizationDuo) {
continue;
}
this.providers.push({
type: p.type,
name: p.name,
description: p.description,
enabled: false,
premium: p.premium,
sort: p.sort,
});
}
this.providers.sort((a: any, b: any) => a.sort - b.sort);
await this.load();
}
async load() {
this.loading = true;
const providerList = await this.apiService.getTwoFactorProviders();
providerList.data.forEach((p) => {
this.providers.forEach((p2) => {
if (p.type === p2.type) {
p2.enabled = p.enabled;
}
});
});
this.loading = false;
}
}

View File

@ -943,7 +943,7 @@
"message": "New Custom Domain"
},
"newCustomDomainDesc": {
"message": "Only \"base\" domains are allowed. Do not enter subdomains. For example, enter \"google.com\" instead of \"www.google.com\". You can also enter \"androidapp://package.name\" to associate an android app with other website domains."
"message": "Enter a list of domains separated by commas. Only \"base\" domains are allowed. Do not enter subdomains. For example, enter \"google.com\" instead of \"www.google.com\". You can also enter \"androidapp://package.name\" to associate an android app with other website domains."
},
"customDomainX": {
"message": "Custom Domain $INDEX$",
@ -956,5 +956,27 @@
},
"domainsUpdated": {
"message": "Domains updated"
},
"twoStepLogin": {
"message": "Two-step Login"
},
"twoStepLoginRecoveryWarning": {
"message": "Enabling two-step login can permanently lock you out of your Bitwarden account. A recovery code allows you to access your account in the event that you can no longer use your normal two-step login provider (ex. you lose your device). Bitwarden support will not be able to assist you if you lose access to your account. We recommend you write down or print the recovery code and keep it in a safe place."
},
"viewRecoveryCode": {
"message": "View Recovery Code"
},
"providers": {
"message": "Providers",
"description": "Two-step login providers such as YubiKey, Duo, Authenticator apps, Email, etc."
},
"enabled": {
"message": "Enabled"
},
"premium": {
"message": "Premium"
},
"manage": {
"message": "Manage"
}
}

View File

@ -502,3 +502,9 @@ app-avatar {
}
}
}
.list-group-2fa {
.logo-2fa {
min-width: 100px;
}
}

View File

@ -48,6 +48,7 @@
"check-preblock",
"check-separator",
"check-type"
]
],
"max-classes-per-file": false
}
}