From 1674ef202db8a78d715eaed4bb4d7b97e794e334 Mon Sep 17 00:00:00 2001 From: Kyle Spearrin Date: Wed, 4 Apr 2018 09:47:49 -0400 Subject: [PATCH] share components with jslib --- jslib | 2 +- src/app/accounts/environment.component.ts | 54 +------ src/app/accounts/hint.component.ts | 35 +---- src/app/accounts/register.component.ts | 71 ++------- .../accounts/two-factor-options.component.ts | 64 ++------- src/app/accounts/two-factor.component.ts | 136 ++---------------- 6 files changed, 41 insertions(+), 321 deletions(-) diff --git a/jslib b/jslib index 7b4d0a71de..bb8cf89788 160000 --- a/jslib +++ b/jslib @@ -1 +1 @@ -Subproject commit 7b4d0a71de640ce14c3c446bfd2e8ce36635db3f +Subproject commit bb8cf8978860b68d9f8011b0da0cb8588e729b37 diff --git a/src/app/accounts/environment.component.ts b/src/app/accounts/environment.component.ts index 56dadf4dae..f9de7008da 100644 --- a/src/app/accounts/environment.component.ts +++ b/src/app/accounts/environment.component.ts @@ -1,10 +1,6 @@ import * as template from './environment.component.html'; -import { - Component, - EventEmitter, - Output, -} from '@angular/core'; +import { Component } from '@angular/core'; import { ToasterService } from 'angular2-toaster'; import { Angulartics2 } from 'angulartics2'; @@ -12,51 +8,15 @@ import { Angulartics2 } from 'angulartics2'; import { EnvironmentService } from 'jslib/abstractions/environment.service'; import { I18nService } from 'jslib/abstractions/i18n.service'; +import { EnvironmentComponent as BaseEnvironmentComponent } from 'jslib/angular/components/environment.component'; + @Component({ selector: 'app-environment', template: template, }) -export class EnvironmentComponent { - iconsUrl: string; - identityUrl: string; - apiUrl: string; - webVaultUrl: string; - baseUrl: string; - showCustom = false; - - @Output() onSaved = new EventEmitter(); - - constructor(private analytics: Angulartics2, private toasterService: ToasterService, - private environmentService: EnvironmentService, private i18nService: I18nService) { - this.baseUrl = environmentService.baseUrl || ''; - this.webVaultUrl = environmentService.webVaultUrl || ''; - this.apiUrl = environmentService.apiUrl || ''; - this.identityUrl = environmentService.identityUrl || ''; - this.iconsUrl = environmentService.iconsUrl || ''; - } - - async submit() { - const resUrls = await this.environmentService.setUrls({ - base: this.baseUrl, - api: this.apiUrl, - identity: this.identityUrl, - webVault: this.webVaultUrl, - icons: this.iconsUrl, - }); - - // re-set urls since service can change them, ex: prefixing https:// - this.baseUrl = resUrls.base; - this.apiUrl = resUrls.api; - this.identityUrl = resUrls.identity; - this.webVaultUrl = resUrls.webVault; - this.iconsUrl = resUrls.icons; - - this.analytics.eventTrack.next({ action: 'Set Environment URLs' }); - this.toasterService.popAsync('success', null, this.i18nService.t('environmentSaved')); - this.onSaved.emit(); - } - - toggleCustom() { - this.showCustom = !this.showCustom; +export class EnvironmentComponent extends BaseEnvironmentComponent { + constructor(analytics: Angulartics2, toasterService: ToasterService, + environmentService: EnvironmentService, i18nService: I18nService) { + super(analytics, toasterService, environmentService, i18nService); } } diff --git a/src/app/accounts/hint.component.ts b/src/app/accounts/hint.component.ts index 8b57336e8f..8f542845ca 100644 --- a/src/app/accounts/hint.component.ts +++ b/src/app/accounts/hint.component.ts @@ -6,40 +6,19 @@ import { Router } from '@angular/router'; import { ToasterService } from 'angular2-toaster'; import { Angulartics2 } from 'angulartics2'; -import { PasswordHintRequest } from 'jslib/models/request/passwordHintRequest'; - import { ApiService } from 'jslib/abstractions/api.service'; import { I18nService } from 'jslib/abstractions/i18n.service'; +import { HintComponent as BaseHintComponent } from 'jslib/angular/components/hint.component'; + @Component({ selector: 'app-hint', template: template, }) -export class HintComponent { - email: string = ''; - formPromise: Promise; - - constructor(private router: Router, private analytics: Angulartics2, private toasterService: ToasterService, - private i18nService: I18nService, private apiService: ApiService) { } - - async submit() { - if (this.email == null || this.email === '') { - this.toasterService.popAsync('error', this.i18nService.t('errorOccurred'), - this.i18nService.t('emailRequired')); - return; - } - if (this.email.indexOf('@') === -1) { - this.toasterService.popAsync('error', this.i18nService.t('errorOccurred'), - this.i18nService.t('invalidEmail')); - return; - } - - try { - this.formPromise = this.apiService.postPasswordHint(new PasswordHintRequest(this.email)); - await this.formPromise; - this.analytics.eventTrack.next({ action: 'Requested Hint' }); - this.toasterService.popAsync('success', null, this.i18nService.t('masterPassSent')); - this.router.navigate(['login']); - } catch { } +export class HintComponent extends BaseHintComponent { + constructor(router: Router, analytics: Angulartics2, + toasterService: ToasterService, i18nService: I18nService, + apiService: ApiService) { + super(router, analytics, toasterService, i18nService, apiService); } } diff --git a/src/app/accounts/register.component.ts b/src/app/accounts/register.component.ts index df303364a8..a2f2e7fa42 100644 --- a/src/app/accounts/register.component.ts +++ b/src/app/accounts/register.component.ts @@ -6,77 +6,22 @@ import { Router } from '@angular/router'; import { ToasterService } from 'angular2-toaster'; import { Angulartics2 } from 'angulartics2'; -import { RegisterRequest } from 'jslib/models/request/registerRequest'; - import { ApiService } from 'jslib/abstractions/api.service'; import { AuthService } from 'jslib/abstractions/auth.service'; import { CryptoService } from 'jslib/abstractions/crypto.service'; import { I18nService } from 'jslib/abstractions/i18n.service'; +import { RegisterComponent as BaseRegisterComponent } from 'jslib/angular/components/register.component'; + @Component({ selector: 'app-register', template: template, }) -export class RegisterComponent { - email: string = ''; - masterPassword: string = ''; - confirmMasterPassword: string = ''; - hint: string = ''; - showPassword: boolean = false; - formPromise: Promise; - - constructor(private authService: AuthService, private router: Router, private analytics: Angulartics2, - private toasterService: ToasterService, private i18nService: I18nService, - private cryptoService: CryptoService, private apiService: ApiService) { } - - async submit() { - if (this.email == null || this.email === '') { - this.toasterService.popAsync('error', this.i18nService.t('errorOccurred'), - this.i18nService.t('emailRequired')); - return; - } - if (this.email.indexOf('@') === -1) { - this.toasterService.popAsync('error', this.i18nService.t('errorOccurred'), - this.i18nService.t('invalidEmail')); - return; - } - if (this.masterPassword == null || this.masterPassword === '') { - this.toasterService.popAsync('error', this.i18nService.t('errorOccurred'), - this.i18nService.t('masterPassRequired')); - return; - } - if (this.masterPassword.length < 8) { - this.toasterService.popAsync('error', this.i18nService.t('errorOccurred'), - this.i18nService.t('masterPassLength')); - return; - } - if (this.masterPassword !== this.confirmMasterPassword) { - this.toasterService.popAsync('error', this.i18nService.t('errorOccurred'), - this.i18nService.t('masterPassDoesntMatch')); - return; - } - - try { - this.formPromise = this.register(); - await this.formPromise; - this.analytics.eventTrack.next({ action: 'Registered' }); - this.toasterService.popAsync('success', null, this.i18nService.t('newAccountCreated')); - this.router.navigate(['login']); - } catch { } - } - - togglePassword(confirmField: boolean) { - this.analytics.eventTrack.next({ action: 'Toggled Master Password on Register' }); - this.showPassword = !this.showPassword; - document.getElementById(confirmField ? 'masterPasswordRetype' : 'masterPassword').focus(); - } - - private async register() { - this.email = this.email.toLowerCase(); - const key = this.cryptoService.makeKey(this.masterPassword, this.email); - const encKey = await this.cryptoService.makeEncKey(key); - const hashedPassword = await this.cryptoService.hashPassword(this.masterPassword, key); - const request = new RegisterRequest(this.email, hashedPassword, this.hint, encKey.encryptedString); - await this.apiService.postRegister(request); +export class RegisterComponent extends BaseRegisterComponent { + constructor(authService: AuthService, router: Router, + analytics: Angulartics2, toasterService: ToasterService, + i18nService: I18nService, cryptoService: CryptoService, + apiService: ApiService) { + super(authService, router, analytics, toasterService, i18nService, cryptoService, apiService); } } diff --git a/src/app/accounts/two-factor-options.component.ts b/src/app/accounts/two-factor-options.component.ts index 4bf541581b..6115898431 100644 --- a/src/app/accounts/two-factor-options.component.ts +++ b/src/app/accounts/two-factor-options.component.ts @@ -1,73 +1,27 @@ import * as template from './two-factor-options.component.html'; -import { - Component, - EventEmitter, - Input, - OnInit, - Output, -} from '@angular/core'; +import { Component, } from '@angular/core'; import { Router } from '@angular/router'; import { ToasterService } from 'angular2-toaster'; import { Angulartics2 } from 'angulartics2'; -import { TwoFactorProviderType } from 'jslib/enums/twoFactorProviderType'; - import { AuthService } from 'jslib/abstractions/auth.service'; import { I18nService } from 'jslib/abstractions/i18n.service'; import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service'; -import { TwoFactorProviders } from 'jslib/services/auth.service'; +import { + TwoFactorOptionsComponent as BaseTwoFactorOptionsComponent +} from 'jslib/angular/components/two-factor-options.component'; @Component({ selector: 'app-two-factor-options', template: template, }) -export class TwoFactorOptionsComponent implements OnInit { - @Output() onProviderSelected = new EventEmitter(); - @Output() onRecoverSelected = new EventEmitter(); - - providers: any[] = []; - - constructor(private authService: AuthService, private router: Router, private analytics: Angulartics2, - private toasterService: ToasterService, private i18nService: I18nService, - private platformUtilsService: PlatformUtilsService) { } - - ngOnInit() { - if (this.authService.twoFactorProviders.has(TwoFactorProviderType.OrganizationDuo)) { - this.providers.push(TwoFactorProviders[TwoFactorProviderType.OrganizationDuo]); - } - - if (this.authService.twoFactorProviders.has(TwoFactorProviderType.Authenticator)) { - this.providers.push(TwoFactorProviders[TwoFactorProviderType.Authenticator]); - } - - if (this.authService.twoFactorProviders.has(TwoFactorProviderType.Yubikey)) { - this.providers.push(TwoFactorProviders[TwoFactorProviderType.Yubikey]); - } - - if (this.authService.twoFactorProviders.has(TwoFactorProviderType.Duo)) { - this.providers.push(TwoFactorProviders[TwoFactorProviderType.Duo]); - } - - if (this.authService.twoFactorProviders.has(TwoFactorProviderType.U2f) && - this.platformUtilsService.supportsU2f(window)) { - this.providers.push(TwoFactorProviders[TwoFactorProviderType.U2f]); - } - - if (this.authService.twoFactorProviders.has(TwoFactorProviderType.Email)) { - this.providers.push(TwoFactorProviders[TwoFactorProviderType.Email]); - } - } - - choose(p: any) { - this.onProviderSelected.emit(p.type); - } - - recover() { - this.analytics.eventTrack.next({ action: 'Selected Recover' }); - this.platformUtilsService.launchUri('https://help.bitwarden.com/article/lost-two-step-device/'); - this.onRecoverSelected.emit(); +export class TwoFactorOptionsComponent extends BaseTwoFactorOptionsComponent { + constructor(authService: AuthService, router: Router, + analytics: Angulartics2, toasterService: ToasterService, + i18nService: I18nService, platformUtilsService: PlatformUtilsService) { + super(authService, router, analytics, toasterService, i18nService, platformUtilsService); } } diff --git a/src/app/accounts/two-factor.component.ts b/src/app/accounts/two-factor.component.ts index 139bb9fae5..670646b70b 100644 --- a/src/app/accounts/two-factor.component.ts +++ b/src/app/accounts/two-factor.component.ts @@ -3,7 +3,6 @@ import * as template from './two-factor.component.html'; import { Component, ComponentFactoryResolver, - OnInit, ViewChild, ViewContainerRef, } from '@angular/core'; @@ -19,145 +18,28 @@ import { TwoFactorOptionsComponent } from './two-factor-options.component'; import { TwoFactorProviderType } from 'jslib/enums/twoFactorProviderType'; -import { TwoFactorEmailRequest } from 'jslib/models/request/twoFactorEmailRequest'; - import { ApiService } from 'jslib/abstractions/api.service'; import { AuthService } from 'jslib/abstractions/auth.service'; import { I18nService } from 'jslib/abstractions/i18n.service'; import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service'; import { SyncService } from 'jslib/abstractions/sync.service'; -import { TwoFactorProviders } from 'jslib/services/auth.service'; +import { TwoFactorComponent as BaseTwoFactorComponent } from 'jslib/angular/components/two-factor.component'; @Component({ selector: 'app-two-factor', template: template, }) -export class TwoFactorComponent implements OnInit { +export class TwoFactorComponent extends BaseTwoFactorComponent { @ViewChild('twoFactorOptions', { read: ViewContainerRef }) twoFactorOptionsModal: ViewContainerRef; - token: string = ''; - remember: boolean = false; - u2fReady: boolean = false; - providers = TwoFactorProviders; - providerType = TwoFactorProviderType; - selectedProviderType: TwoFactorProviderType = TwoFactorProviderType.Authenticator; - u2fSupported: boolean = false; - u2f: any = null; - title: string = ''; - twoFactorEmail: string = null; - formPromise: Promise; - emailPromise: Promise; - - constructor(private authService: AuthService, private router: Router, private analytics: Angulartics2, - private toasterService: ToasterService, private i18nService: I18nService, private apiService: ApiService, - private platformUtilsService: PlatformUtilsService, - private componentFactoryResolver: ComponentFactoryResolver, private syncService: SyncService) { - this.u2fSupported = this.platformUtilsService.supportsU2f(window); - } - - async ngOnInit() { - if (this.authService.email == null || this.authService.masterPasswordHash == null || - this.authService.twoFactorProviders == null) { - this.router.navigate(['login']); - return; - } - - this.selectedProviderType = this.authService.getDefaultTwoFactorProvider(this.u2fSupported); - await this.init(); - } - - async init() { - if (this.selectedProviderType == null) { - this.title = this.i18nService.t('loginUnavailable'); - return; - } - - this.title = (TwoFactorProviders as any)[this.selectedProviderType].name; - const params = this.authService.twoFactorProviders.get(this.selectedProviderType); - switch (this.selectedProviderType) { - case TwoFactorProviderType.U2f: - if (!this.u2fSupported) { - break; - } - - const challenges = JSON.parse(params.Challenges); - // TODO: init u2f - break; - case TwoFactorProviderType.Duo: - case TwoFactorProviderType.OrganizationDuo: - setTimeout(() => { - (window as any).Duo.init({ - host: params.Host, - sig_request: params.Signature, - submit_callback: async (f: HTMLFormElement) => { - const sig = f.querySelector('input[name="sig_response"]') as HTMLInputElement; - if (sig != null) { - this.token = sig.value; - await this.submit(); - } - }, - }); - }); - break; - case TwoFactorProviderType.Email: - this.twoFactorEmail = params.Email; - if (this.authService.twoFactorProviders.size > 1) { - await this.sendEmail(false); - } - break; - default: - break; - } - } - - async submit() { - if (this.token == null || this.token === '') { - this.toasterService.popAsync('error', this.i18nService.t('errorOccurred'), - this.i18nService.t('verificationCodeRequired')); - return; - } - - if (this.selectedProviderType === TwoFactorProviderType.U2f) { - // TODO: stop U2f - } else if (this.selectedProviderType === TwoFactorProviderType.Email || - this.selectedProviderType === TwoFactorProviderType.Authenticator) { - this.token = this.token.replace(' ', '').trim(); - } - - try { - this.formPromise = this.authService.logInTwoFactor(this.selectedProviderType, this.token, this.remember); - await this.formPromise; - this.syncService.fullSync(true); - this.analytics.eventTrack.next({ action: 'Logged In From Two-step' }); - this.router.navigate(['vault']); - } catch { - if (this.selectedProviderType === TwoFactorProviderType.U2f) { - // TODO: start U2F again - } - } - } - - async sendEmail(doToast: boolean) { - if (this.selectedProviderType !== TwoFactorProviderType.Email) { - return; - } - - if (this.emailPromise != null) { - return; - } - - try { - const request = new TwoFactorEmailRequest(this.authService.email, this.authService.masterPasswordHash); - this.emailPromise = this.apiService.postTwoFactorEmail(request); - await this.emailPromise; - if (doToast) { - this.toasterService.popAsync('success', null, - this.i18nService.t('verificationCodeEmailSent', this.twoFactorEmail)); - } - } catch { } - - this.emailPromise = null; + constructor(authService: AuthService, router: Router, + analytics: Angulartics2, toasterService: ToasterService, + i18nService: I18nService, apiService: ApiService, + platformUtilsService: PlatformUtilsService, syncService: SyncService, + private componentFactoryResolver: ComponentFactoryResolver) { + super(authService, router, analytics, toasterService, i18nService, apiService, + platformUtilsService, syncService); } anotherMethod() {