1
0
mirror of https://github.com/bitwarden/desktop.git synced 2024-11-30 12:54:31 +01:00

Add password show/hide to reprompt (#959)

This commit is contained in:
Oscar Hinton 2021-08-27 15:30:44 +02:00 committed by GitHub
parent 5b4931e260
commit 2ba8925b81
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 126 additions and 125 deletions

2
jslib

@ -1 +1 @@
Subproject commit 1f0127966e85aa29f9e50144de9b2a03b00de5d4 Subproject commit daa4f6f9a6dc84d6cd9a937be6b5392d2cf51eca

View File

@ -1,6 +1,5 @@
import { import {
Component, Component,
ComponentFactoryResolver,
NgZone, NgZone,
OnDestroy, OnDestroy,
ViewChild, ViewChild,
@ -24,9 +23,9 @@ import { SyncService } from 'jslib-common/abstractions/sync.service';
import { UserService } from 'jslib-common/abstractions/user.service'; import { UserService } from 'jslib-common/abstractions/user.service';
import { BroadcasterService } from 'jslib-angular/services/broadcaster.service'; import { BroadcasterService } from 'jslib-angular/services/broadcaster.service';
import { ModalService } from 'jslib-angular/services/modal.service';
import { LoginComponent as BaseLoginComponent } from 'jslib-angular/components/login.component'; import { LoginComponent as BaseLoginComponent } from 'jslib-angular/components/login.component';
import { ModalComponent } from 'jslib-angular/components/modal.component';
const BroadcasterSubscriptionId = 'LoginComponent'; const BroadcasterSubscriptionId = 'LoginComponent';
@ -42,7 +41,7 @@ export class LoginComponent extends BaseLoginComponent implements OnDestroy {
private deferFocus: boolean = null; private deferFocus: boolean = null;
constructor(authService: AuthService, router: Router, i18nService: I18nService, constructor(authService: AuthService, router: Router, i18nService: I18nService,
syncService: SyncService, private componentFactoryResolver: ComponentFactoryResolver, syncService: SyncService, private modalService: ModalService,
platformUtilsService: PlatformUtilsService, stateService: StateService, platformUtilsService: PlatformUtilsService, stateService: StateService,
environmentService: EnvironmentService, passwordGenerationService: PasswordGenerationService, environmentService: EnvironmentService, passwordGenerationService: PasswordGenerationService,
cryptoFunctionService: CryptoFunctionService, storageService: StorageService, cryptoFunctionService: CryptoFunctionService, storageService: StorageService,
@ -89,20 +88,16 @@ export class LoginComponent extends BaseLoginComponent implements OnDestroy {
this.broadcasterService.unsubscribe(BroadcasterSubscriptionId); this.broadcasterService.unsubscribe(BroadcasterSubscriptionId);
} }
settings() { async settings() {
const factory = this.componentFactoryResolver.resolveComponentFactory(ModalComponent); const [modal, childComponent] = await this.modalService.openViewRef(EnvironmentComponent, this.environmentModal);
const modal = this.environmentModal.createComponent(factory).instance;
modal.onShown.subscribe(() => { modal.onShown.subscribe(() => {
this.showingModal = true; this.showingModal = true;
}); });
modal.onClosed.subscribe(() => { modal.onClosed.subscribe(() => {
this.showingModal = false; this.showingModal = false;
modal.onShown.unsubscribe();
modal.onClosed.unsubscribe();
}); });
const childComponent = modal.show<EnvironmentComponent>(EnvironmentComponent,
this.environmentModal);
childComponent.onSaved.subscribe(() => { childComponent.onSaved.subscribe(() => {
modal.close(); modal.close();
}); });

View File

@ -1,6 +1,5 @@
import { import {
Component, Component,
ComponentFactoryResolver,
ViewChild, ViewChild,
ViewContainerRef, ViewContainerRef,
} from '@angular/core'; } from '@angular/core';
@ -24,7 +23,8 @@ import { StorageService } from 'jslib-common/abstractions/storage.service';
import { SyncService } from 'jslib-common/abstractions/sync.service'; import { SyncService } from 'jslib-common/abstractions/sync.service';
import { UserService } from 'jslib-common/abstractions/user.service'; import { UserService } from 'jslib-common/abstractions/user.service';
import { ModalComponent } from 'jslib-angular/components/modal.component'; import { ModalService } from 'jslib-angular/services/modal.service';
import { TwoFactorComponent as BaseTwoFactorComponent } from 'jslib-angular/components/two-factor.component'; import { TwoFactorComponent as BaseTwoFactorComponent } from 'jslib-angular/components/two-factor.component';
@Component({ @Component({
@ -39,7 +39,7 @@ export class TwoFactorComponent extends BaseTwoFactorComponent {
constructor(authService: AuthService, router: Router, constructor(authService: AuthService, router: Router,
i18nService: I18nService, apiService: ApiService, i18nService: I18nService, apiService: ApiService,
platformUtilsService: PlatformUtilsService, syncService: SyncService, platformUtilsService: PlatformUtilsService, syncService: SyncService,
environmentService: EnvironmentService, private componentFactoryResolver: ComponentFactoryResolver, environmentService: EnvironmentService, private modalService: ModalService,
stateService: StateService, storageService: StorageService, route: ActivatedRoute, stateService: StateService, storageService: StorageService, route: ActivatedRoute,
private userService: UserService) { private userService: UserService) {
super(authService, router, i18nService, apiService, platformUtilsService, window, environmentService, super(authService, router, i18nService, apiService, platformUtilsService, window, environmentService,
@ -53,20 +53,16 @@ export class TwoFactorComponent extends BaseTwoFactorComponent {
}; };
} }
anotherMethod() { async anotherMethod() {
const factory = this.componentFactoryResolver.resolveComponentFactory(ModalComponent); const [modal, childComponent] = await this.modalService.openViewRef(TwoFactorOptionsComponent, this.twoFactorOptionsModal);
const modal = this.twoFactorOptionsModal.createComponent(factory).instance;
modal.onShown.subscribe(() => { modal.onShown.subscribe(() => {
this.showingModal = true; this.showingModal = true;
}); });
modal.onClosed.subscribe(() => { modal.onClosed.subscribe(() => {
this.showingModal = false; this.showingModal = false;
modal.onShown.unsubscribe();
modal.onClosed.unsubscribe();
}); });
const childComponent = modal.show<TwoFactorOptionsComponent>(TwoFactorOptionsComponent,
this.twoFactorOptionsModal);
childComponent.onProviderSelected.subscribe(async (provider: TwoFactorProviderType) => { childComponent.onProviderSelected.subscribe(async (provider: TwoFactorProviderType) => {
modal.close(); modal.close();
this.selectedProviderType = provider; this.selectedProviderType = provider;

View File

@ -22,8 +22,6 @@ import { PremiumComponent } from './accounts/premium.component';
import { SettingsComponent } from './accounts/settings.component'; import { SettingsComponent } from './accounts/settings.component';
import { PasswordGeneratorHistoryComponent } from './vault/password-generator-history.component'; import { PasswordGeneratorHistoryComponent } from './vault/password-generator-history.component';
import { ModalComponent } from 'jslib-angular/components/modal.component';
import { BroadcasterService } from 'jslib-angular/services/broadcaster.service'; import { BroadcasterService } from 'jslib-angular/services/broadcaster.service';
import { AuthService } from 'jslib-common/abstractions/auth.service'; import { AuthService } from 'jslib-common/abstractions/auth.service';
@ -52,6 +50,8 @@ import { ConstantsService } from 'jslib-common/services/constants.service';
import { CipherType } from 'jslib-common/enums/cipherType'; import { CipherType } from 'jslib-common/enums/cipherType';
import { ModalRef } from 'jslib-angular/components/modal/modal.ref';
import { ModalService } from 'jslib-angular/services/modal.service';
import { ExportComponent } from './vault/export.component'; import { ExportComponent } from './vault/export.component';
import { FolderAddEditComponent } from './vault/folder-add-edit.component'; import { FolderAddEditComponent } from './vault/folder-add-edit.component';
import { PasswordGeneratorComponent } from './vault/password-generator.component'; import { PasswordGeneratorComponent } from './vault/password-generator.component';
@ -91,7 +91,7 @@ export class AppComponent implements OnInit {
}); });
private lastActivity: number = null; private lastActivity: number = null;
private modal: ModalComponent = null; private modal: ModalRef = null;
private idleTimer: number = null; private idleTimer: number = null;
private isIdle = false; private isIdle = false;
@ -108,7 +108,7 @@ export class AppComponent implements OnInit {
private searchService: SearchService, private notificationsService: NotificationsService, private searchService: SearchService, private notificationsService: NotificationsService,
private platformUtilsService: PlatformUtilsService, private systemService: SystemService, private platformUtilsService: PlatformUtilsService, private systemService: SystemService,
private stateService: StateService, private eventService: EventService, private stateService: StateService, private eventService: EventService,
private policyService: PolicyService) { } private policyService: PolicyService, private modalService: ModalService) { }
ngOnInit() { ngOnInit() {
this.ngZone.runOutsideAngular(() => { this.ngZone.runOutsideAngular(() => {
@ -170,10 +170,10 @@ export class AppComponent implements OnInit {
case 'syncCompleted': case 'syncCompleted':
break; break;
case 'openSettings': case 'openSettings':
this.openModal<SettingsComponent>(SettingsComponent, this.settingsRef); await this.openModal<SettingsComponent>(SettingsComponent, this.settingsRef);
break; break;
case 'openPremium': case 'openPremium':
this.openModal<PremiumComponent>(PremiumComponent, this.premiumRef); await this.openModal<PremiumComponent>(PremiumComponent, this.premiumRef);
break; break;
case 'showFingerprintPhrase': case 'showFingerprintPhrase':
const fingerprint = await this.cryptoService.getFingerprint( const fingerprint = await this.cryptoService.getFingerprint(
@ -188,7 +188,7 @@ export class AppComponent implements OnInit {
} }
break; break;
case 'openPasswordHistory': case 'openPasswordHistory':
this.openModal<PasswordGeneratorHistoryComponent>( await this.openModal<PasswordGeneratorHistoryComponent>(
PasswordGeneratorHistoryComponent, this.passwordHistoryRef); PasswordGeneratorHistoryComponent, this.passwordHistoryRef);
break; break;
case 'showToast': case 'showToast':
@ -207,7 +207,7 @@ export class AppComponent implements OnInit {
this.i18nService.t('premiumRequiredDesc'), this.i18nService.t('premiumRequired'), this.i18nService.t('premiumRequiredDesc'), this.i18nService.t('premiumRequired'),
this.i18nService.t('learnMore'), this.i18nService.t('cancel')); this.i18nService.t('learnMore'), this.i18nService.t('cancel'));
if (premiumConfirmed) { if (premiumConfirmed) {
this.openModal<PremiumComponent>(PremiumComponent, this.premiumRef); await this.openModal<PremiumComponent>(PremiumComponent, this.premiumRef);
} }
break; break;
case 'emailVerificationRequired': case 'emailVerificationRequired':
@ -281,9 +281,8 @@ export class AppComponent implements OnInit {
this.modal.close(); this.modal.close();
} }
const factory = this.componentFactoryResolver.resolveComponentFactory(ModalComponent); const [modal, childComponent] = await this.modalService.openViewRef(ExportComponent, this.exportVaultModalRef);
this.modal = this.exportVaultModalRef.createComponent(factory).instance; this.modal = modal;
const childComponent = this.modal.show<ExportComponent>(ExportComponent, this.exportVaultModalRef);
childComponent.onSaved.subscribe(() => { childComponent.onSaved.subscribe(() => {
this.modal.close(); this.modal.close();
@ -299,10 +298,9 @@ export class AppComponent implements OnInit {
this.modal.close(); this.modal.close();
} }
const factory = this.componentFactoryResolver.resolveComponentFactory(ModalComponent); const [modal, childComponent] = await this.modalService.openViewRef(FolderAddEditComponent,
this.modal = this.folderAddEditModalRef.createComponent(factory).instance; this.folderAddEditModalRef, comp => comp.folderId = null);
const childComponent = this.modal.show<FolderAddEditComponent>( this.modal = modal;
FolderAddEditComponent, this.folderAddEditModalRef, true, comp => comp.folderId = null);
childComponent.onSavedFolder.subscribe(async () => { childComponent.onSavedFolder.subscribe(async () => {
this.modal.close(); this.modal.close();
@ -319,10 +317,8 @@ export class AppComponent implements OnInit {
this.modal.close(); this.modal.close();
} }
const factory = this.componentFactoryResolver.resolveComponentFactory(ModalComponent); [this.modal] = await this.modalService.openViewRef(PasswordGeneratorComponent, this.folderAddEditModalRef,
this.modal = this.passwordGeneratorModalRef.createComponent(factory).instance; comp => comp.showSelect = false);
this.modal.show<PasswordGeneratorComponent>(PasswordGeneratorComponent,
this.passwordGeneratorModalRef, true, comp => comp.showSelect = false);
this.modal.onClosed.subscribe(() => { this.modal.onClosed.subscribe(() => {
this.modal = null; this.modal = null;
@ -401,14 +397,12 @@ export class AppComponent implements OnInit {
} }
} }
private openModal<T>(type: Type<T>, ref: ViewContainerRef) { private async openModal<T>(type: Type<T>, ref: ViewContainerRef) {
if (this.modal != null) { if (this.modal != null) {
this.modal.close(); this.modal.close();
} }
const factory = this.componentFactoryResolver.resolveComponentFactory(ModalComponent); [this.modal] = await this.modalService.openViewRef(type, ref);
this.modal = ref.createComponent(factory).instance;
this.modal.show<T>(type, ref);
this.modal.onClosed.subscribe(() => { this.modal.onClosed.subscribe(() => {
this.modal = null; this.modal = null;

View File

@ -30,7 +30,6 @@ import { UpdateTempPasswordComponent } from './accounts/update-temp-password.com
import { CalloutComponent } from 'jslib-angular/components/callout.component'; import { CalloutComponent } from 'jslib-angular/components/callout.component';
import { IconComponent } from 'jslib-angular/components/icon.component'; import { IconComponent } from 'jslib-angular/components/icon.component';
import { ModalComponent } from 'jslib-angular/components/modal.component';
import { A11yTitleDirective } from 'jslib-angular/directives/a11y-title.directive'; import { A11yTitleDirective } from 'jslib-angular/directives/a11y-title.directive';
import { ApiActionDirective } from 'jslib-angular/directives/api-action.directive'; import { ApiActionDirective } from 'jslib-angular/directives/api-action.directive';
@ -68,6 +67,8 @@ import { SendComponent } from './send/send.component';
import { NavComponent } from './layout/nav.component'; import { NavComponent } from './layout/nav.component';
import { PasswordRepromptComponent } from './components/password-reprompt.component';
import { registerLocaleData } from '@angular/common'; import { registerLocaleData } from '@angular/common';
import localeAf from '@angular/common/locales/af'; import localeAf from '@angular/common/locales/af';
import localeAz from '@angular/common/locales/az'; import localeAz from '@angular/common/locales/az';
@ -195,7 +196,6 @@ registerLocaleData(localeZhTw, 'zh-TW');
IconComponent, IconComponent,
LockComponent, LockComponent,
LoginComponent, LoginComponent,
ModalComponent,
NavComponent, NavComponent,
PasswordGeneratorComponent, PasswordGeneratorComponent,
PasswordGeneratorHistoryComponent, PasswordGeneratorHistoryComponent,
@ -219,6 +219,7 @@ registerLocaleData(localeZhTw, 'zh-TW');
UpdateTempPasswordComponent, UpdateTempPasswordComponent,
VaultComponent, VaultComponent,
ViewComponent, ViewComponent,
PasswordRepromptComponent,
], ],
providers: [DatePipe], providers: [DatePipe],
bootstrap: [AppComponent], bootstrap: [AppComponent],

View File

@ -0,0 +1,38 @@
<div class="modal fade" tabindex="-1" role="dialog" aria-modal="true" aria-labelledby="confirmUserTitle">
<div class="modal-dialog modal-dialog-scrollable" role="document">
<form class="modal-content" #form (ngSubmit)="submit()">
<div class="modal-body">
<div class="box">
<div class="box-header">{{'passwordConfirmation' | i18n}}</div>
<div class="box-content">
<div class="box-content-row box-content-row-flex" appBoxRow>
<div class="row-main">
<label for="masterPassword">{{'masterPass' | i18n}}</label>
<input id="masterPassword" type="{{showPassword ? 'text' : 'password'}}" name="MasterPassword"
class="monospaced" [(ngModel)]="masterPassword" required appAutofocus>
</div>
<div class="action-buttons">
<a class="row-btn" href="#" appStopClick appBlurClick role="button"
appA11yTitle="{{'toggleVisibility' | i18n}}" (click)="togglePassword()">
<i class="fa fa-lg" aria-hidden="true"
[ngClass]="{'fa-eye': !showPassword, 'fa-eye-slash': showPassword}"></i>
</a>
</div>
</div>
</div>
<div class="box-footer">
{{'passwordConfirmationDesc' | i18n}}
</div>
</div>
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-primary btn-submit" appBlurClick>
<span>{{'ok' | i18n}}</span>
</button>
<button type="button" class="btn btn-outline-secondary" data-dismiss="modal">
{{'cancel' | i18n}}
</button>
</div>
</form>
</div>
</div>

View File

@ -0,0 +1,8 @@
import { Component } from '@angular/core';
import { PasswordRepromptComponent as BasePasswordRepromptComponent } from 'jslib-angular/components/password-reprompt.component';
@Component({
templateUrl: 'password-reprompt.component.html',
})
export class PasswordRepromptComponent extends BasePasswordRepromptComponent {}

View File

@ -7,17 +7,19 @@ import {
import { ToasterModule } from 'angular2-toaster'; import { ToasterModule } from 'angular2-toaster';
import { ElectronLogService } from 'jslib-electron/services/electronLog.service'; import { ElectronLogService } from 'jslib-electron/services/electronLog.service';
import { ElectronPlatformUtilsService } from 'jslib-electron/services/electronPlatformUtils.service';
import { ElectronRendererMessagingService } from 'jslib-electron/services/electronRendererMessaging.service'; import { ElectronRendererMessagingService } from 'jslib-electron/services/electronRendererMessaging.service';
import { ElectronRendererSecureStorageService } from 'jslib-electron/services/electronRendererSecureStorage.service'; import { ElectronRendererSecureStorageService } from 'jslib-electron/services/electronRendererSecureStorage.service';
import { ElectronRendererStorageService } from 'jslib-electron/services/electronRendererStorage.service'; import { ElectronRendererStorageService } from 'jslib-electron/services/electronRendererStorage.service';
import { ElectronPlatformUtilsService } from '../services/electronPlatformUtils.service';
import { I18nService } from '../services/i18n.service'; import { I18nService } from '../services/i18n.service';
import { NativeMessagingService } from '../services/nativeMessaging.service'; import { NativeMessagingService } from '../services/nativeMessaging.service';
import { PasswordRepromptService } from '../services/passwordReprompt.service';
import { AuthGuardService } from 'jslib-angular/services/auth-guard.service'; import { AuthGuardService } from 'jslib-angular/services/auth-guard.service';
import { BroadcasterService } from 'jslib-angular/services/broadcaster.service'; import { BroadcasterService } from 'jslib-angular/services/broadcaster.service';
import { LockGuardService } from 'jslib-angular/services/lock-guard.service'; import { LockGuardService } from 'jslib-angular/services/lock-guard.service';
import { ModalService } from 'jslib-angular/services/modal.service';
import { UnauthGuardService } from 'jslib-angular/services/unauth-guard.service'; import { UnauthGuardService } from 'jslib-angular/services/unauth-guard.service';
import { ValidationService } from 'jslib-angular/services/validation.service'; import { ValidationService } from 'jslib-angular/services/validation.service';
@ -36,7 +38,6 @@ import { FileUploadService } from 'jslib-common/services/fileUpload.service';
import { FolderService } from 'jslib-common/services/folder.service'; import { FolderService } from 'jslib-common/services/folder.service';
import { NotificationsService } from 'jslib-common/services/notifications.service'; import { NotificationsService } from 'jslib-common/services/notifications.service';
import { PasswordGenerationService } from 'jslib-common/services/passwordGeneration.service'; import { PasswordGenerationService } from 'jslib-common/services/passwordGeneration.service';
import { PasswordRepromptService } from 'jslib-common/services/passwordReprompt.service';
import { PolicyService } from 'jslib-common/services/policy.service'; import { PolicyService } from 'jslib-common/services/policy.service';
import { SearchService } from 'jslib-common/services/search.service'; import { SearchService } from 'jslib-common/services/search.service';
import { SendService } from 'jslib-common/services/send.service'; import { SendService } from 'jslib-common/services/send.service';
@ -137,7 +138,6 @@ const systemService = new SystemService(storageService, vaultTimeoutService, mes
null); null);
const nativeMessagingService = new NativeMessagingService(cryptoFunctionService, cryptoService, platformUtilsService, const nativeMessagingService = new NativeMessagingService(cryptoFunctionService, cryptoService, platformUtilsService,
logService, i18nService, userService, messagingService, vaultTimeoutService, storageService); logService, i18nService, userService, messagingService, vaultTimeoutService, storageService);
const passwordRepromptService = new PasswordRepromptService(i18nService, cryptoService, platformUtilsService);
containerService.attachToGlobal(window); containerService.attachToGlobal(window);
@ -191,6 +191,7 @@ export function initFactory(): Function {
AuthGuardService, AuthGuardService,
UnauthGuardService, UnauthGuardService,
LockGuardService, LockGuardService,
ModalService,
{ provide: AuditServiceAbstraction, useValue: auditService }, { provide: AuditServiceAbstraction, useValue: auditService },
{ provide: AuthServiceAbstraction, useValue: authService }, { provide: AuthServiceAbstraction, useValue: authService },
{ provide: CipherServiceAbstraction, useValue: cipherService }, { provide: CipherServiceAbstraction, useValue: cipherService },
@ -224,7 +225,7 @@ export function initFactory(): Function {
{ provide: CryptoFunctionServiceAbstraction, useValue: cryptoFunctionService }, { provide: CryptoFunctionServiceAbstraction, useValue: cryptoFunctionService },
{ provide: NativeMessagingService, useValue: nativeMessagingService }, { provide: NativeMessagingService, useValue: nativeMessagingService },
{ provide: FileUploadServiceAbstraction, useValue: fileUploadService }, { provide: FileUploadServiceAbstraction, useValue: fileUploadService },
{ provide: PasswordRepromptServiceAbstraction, useValue: passwordRepromptService }, { provide: PasswordRepromptServiceAbstraction, useClass: PasswordRepromptService },
{ {
provide: APP_INITIALIZER, provide: APP_INITIALIZER,
useFactory: initFactory, useFactory: initFactory,

View File

@ -1,7 +1,6 @@
import { import {
ChangeDetectorRef, ChangeDetectorRef,
Component, Component,
ComponentFactoryResolver,
NgZone, NgZone,
OnDestroy, OnDestroy,
OnInit, OnInit,
@ -17,8 +16,6 @@ import { ToasterService } from 'angular2-toaster';
import { BroadcasterService } from 'jslib-angular/services/broadcaster.service'; import { BroadcasterService } from 'jslib-angular/services/broadcaster.service';
import { ModalComponent } from 'jslib-angular/components/modal.component';
import { AddEditComponent } from './add-edit.component'; import { AddEditComponent } from './add-edit.component';
import { AttachmentsComponent } from './attachments.component'; import { AttachmentsComponent } from './attachments.component';
import { CiphersComponent } from './ciphers.component'; import { CiphersComponent } from './ciphers.component';
@ -37,6 +34,9 @@ import { EventType } from 'jslib-common/enums/eventType';
import { CipherView } from 'jslib-common/models/view/cipherView'; import { CipherView } from 'jslib-common/models/view/cipherView';
import { FolderView } from 'jslib-common/models/view/folderView'; import { FolderView } from 'jslib-common/models/view/folderView';
import { ModalRef } from 'jslib-angular/components/modal/modal.ref';
import { ModalService } from 'jslib-angular/services/modal.service';
import { EventService } from 'jslib-common/abstractions/event.service'; import { EventService } from 'jslib-common/abstractions/event.service';
import { I18nService } from 'jslib-common/abstractions/i18n.service'; import { I18nService } from 'jslib-common/abstractions/i18n.service';
import { MessagingService } from 'jslib-common/abstractions/messaging.service'; import { MessagingService } from 'jslib-common/abstractions/messaging.service';
@ -78,15 +78,16 @@ export class VaultComponent implements OnInit, OnDestroy {
deleted = false; deleted = false;
userHasPremiumAccess = false; userHasPremiumAccess = false;
private modal: ModalComponent = null; private modal: ModalRef = null;
constructor(private route: ActivatedRoute, private router: Router, constructor(private route: ActivatedRoute, private router: Router,
private componentFactoryResolver: ComponentFactoryResolver, private i18nService: I18nService, private i18nService: I18nService, private modalService: ModalService,
private broadcasterService: BroadcasterService, private changeDetectorRef: ChangeDetectorRef, private broadcasterService: BroadcasterService, private changeDetectorRef: ChangeDetectorRef,
private ngZone: NgZone, private syncService: SyncService, private ngZone: NgZone, private syncService: SyncService,
private toasterService: ToasterService, private messagingService: MessagingService, private toasterService: ToasterService, private messagingService: MessagingService,
private platformUtilsService: PlatformUtilsService, private eventService: EventService, private platformUtilsService: PlatformUtilsService, private eventService: EventService,
private totpService: TotpService, private userService: UserService, private passwordRepromptService: PasswordRepromptService) { } private totpService: TotpService, private userService: UserService,
private passwordRepromptService: PasswordRepromptService) { }
async ngOnInit() { async ngOnInit() {
this.userHasPremiumAccess = await this.userService.canAccessPremium(); this.userHasPremiumAccess = await this.userService.canAccessPremium();
@ -422,15 +423,15 @@ export class VaultComponent implements OnInit, OnDestroy {
await this.ciphersComponent.refresh(); await this.ciphersComponent.refresh();
} }
editCipherAttachments(cipher: CipherView) { async editCipherAttachments(cipher: CipherView) {
if (this.modal != null) { if (this.modal != null) {
this.modal.close(); this.modal.close();
} }
const factory = this.componentFactoryResolver.resolveComponentFactory(ModalComponent); const [modal, childComponent] = await this.modalService.openViewRef(AttachmentsComponent, this.attachmentsModalRef,
this.modal = this.attachmentsModalRef.createComponent(factory).instance; comp => comp.cipherId = cipher.id);
const childComponent = this.modal.show<AttachmentsComponent>(AttachmentsComponent, this.attachmentsModalRef, this.modal = modal;
true, comp => comp.cipherId = cipher.id);
let madeAttachmentChanges = false; let madeAttachmentChanges = false;
childComponent.onUploadedAttachment.subscribe(() => madeAttachmentChanges = true); childComponent.onUploadedAttachment.subscribe(() => madeAttachmentChanges = true);
childComponent.onDeletedAttachment.subscribe(() => madeAttachmentChanges = true); childComponent.onDeletedAttachment.subscribe(() => madeAttachmentChanges = true);
@ -444,15 +445,14 @@ export class VaultComponent implements OnInit, OnDestroy {
}); });
} }
shareCipher(cipher: CipherView) { async shareCipher(cipher: CipherView) {
if (this.modal != null) { if (this.modal != null) {
this.modal.close(); this.modal.close();
} }
const factory = this.componentFactoryResolver.resolveComponentFactory(ModalComponent); const [modal, childComponent] = await this.modalService.openViewRef(ShareComponent, this.shareModalRef,
this.modal = this.shareModalRef.createComponent(factory).instance;
const childComponent = this.modal.show<ShareComponent>(ShareComponent, this.shareModalRef, true,
comp => comp.cipherId = cipher.id); comp => comp.cipherId = cipher.id);
this.modal = modal;
childComponent.onSharedCipher.subscribe(async () => { childComponent.onSharedCipher.subscribe(async () => {
this.modal.close(); this.modal.close();
@ -464,15 +464,14 @@ export class VaultComponent implements OnInit, OnDestroy {
}); });
} }
cipherCollections(cipher: CipherView) { async cipherCollections(cipher: CipherView) {
if (this.modal != null) { if (this.modal != null) {
this.modal.close(); this.modal.close();
} }
const factory = this.componentFactoryResolver.resolveComponentFactory(ModalComponent); const [modal, childComponent] = await this.modalService.openViewRef(CollectionsComponent, this.collectionsModalRef,
this.modal = this.collectionsModalRef.createComponent(factory).instance; comp => comp.cipherId = cipher.id);
const childComponent = this.modal.show<CollectionsComponent>(CollectionsComponent, this.collectionsModalRef, this.modal = modal;
true, comp => comp.cipherId = cipher.id);
childComponent.onSavedCollections.subscribe(() => { childComponent.onSavedCollections.subscribe(() => {
this.modal.close(); this.modal.close();
@ -483,15 +482,14 @@ export class VaultComponent implements OnInit, OnDestroy {
}); });
} }
viewCipherPasswordHistory(cipher: CipherView) { async viewCipherPasswordHistory(cipher: CipherView) {
if (this.modal != null) { if (this.modal != null) {
this.modal.close(); this.modal.close();
} }
const factory = this.componentFactoryResolver.resolveComponentFactory(ModalComponent); [this.modal] = await this.modalService.openViewRef(PasswordHistoryComponent, this.passwordHistoryModalRef,
this.modal = this.passwordHistoryModalRef.createComponent(factory).instance; comp => comp.cipherId = cipher.id);
this.modal.show<PasswordHistoryComponent>(PasswordHistoryComponent,
this.passwordHistoryModalRef, true, comp => comp.cipherId = cipher.id);
this.modal.onClosed.subscribe(async () => { this.modal.onClosed.subscribe(async () => {
this.modal = null; this.modal = null;
}); });
@ -559,10 +557,9 @@ export class VaultComponent implements OnInit, OnDestroy {
this.modal.close(); this.modal.close();
} }
const factory = this.componentFactoryResolver.resolveComponentFactory(ModalComponent); const [modal, childComponent] = await this.modalService.openViewRef(PasswordGeneratorComponent, this.passwordGeneratorModalRef,
this.modal = this.passwordGeneratorModalRef.createComponent(factory).instance; comp => comp.showSelect = showSelect);
const childComponent = this.modal.show<PasswordGeneratorComponent>(PasswordGeneratorComponent, this.modal = modal;
this.passwordGeneratorModalRef, true, comp => comp.showSelect = showSelect);
childComponent.onSelected.subscribe((password: string) => { childComponent.onSelected.subscribe((password: string) => {
this.modal.close(); this.modal.close();
@ -587,10 +584,9 @@ export class VaultComponent implements OnInit, OnDestroy {
this.modal.close(); this.modal.close();
} }
const factory = this.componentFactoryResolver.resolveComponentFactory(ModalComponent); const [modal, childComponent] = await this.modalService.openViewRef(FolderAddEditComponent, this.folderAddEditModalRef,
this.modal = this.folderAddEditModalRef.createComponent(factory).instance; comp => comp.folderId = folderId);
const childComponent = this.modal.show<FolderAddEditComponent>( this.modal = modal;
FolderAddEditComponent, this.folderAddEditModalRef, true, comp => comp.folderId = folderId);
childComponent.onSavedFolder.subscribe(async (folder: FolderView) => { childComponent.onSavedFolder.subscribe(async (folder: FolderView) => {
this.modal.close(); this.modal.close();

View File

@ -415,3 +415,8 @@ app-root > #loading {
margin: 0; margin: 0;
} }
} }
.password-reprompt {
text-align: left;
margin-top: 15px;
}

View File

@ -1,42 +0,0 @@
import Swal from 'sweetalert2';
import { I18nService } from 'jslib-common/abstractions/i18n.service';
import { MessagingService } from 'jslib-common/abstractions/messaging.service';
import { StorageService } from 'jslib-common/abstractions/storage.service';
import {
ElectronPlatformUtilsService as BaseElectronPlatformUtilsService
} from 'jslib-electron/services/electronPlatformUtils.service';
export class ElectronPlatformUtilsService extends BaseElectronPlatformUtilsService {
constructor(i18nService: I18nService, messagingService: MessagingService,
isDesktopApp: boolean, storageService: StorageService) {
super(i18nService, messagingService, isDesktopApp, storageService);
}
async showPasswordDialog(title: string, body: string, passwordValidation: (value: string) => Promise<boolean>):
Promise<boolean> {
const result = await Swal.fire({
heightAuto: false,
titleText: title,
input: 'password',
text: body,
confirmButtonText: this.i18nService.t('ok'),
showCancelButton: true,
cancelButtonText: this.i18nService.t('cancel'),
inputAttributes: {
autocapitalize: 'off',
autocorrect: 'off',
},
inputValidator: async (value: string): Promise<any> => {
if (await passwordValidation(value)) {
return false;
}
return this.i18nService.t('invalidMasterPassword');
},
});
return result.isConfirmed;
}
}

View File

@ -0,0 +1,9 @@
import { Injectable } from '@angular/core';
import { PasswordRepromptService as BasePasswordRepromptService } from 'jslib-angular/services/passwordReprompt.service';
import { PasswordRepromptComponent } from '../app/components/password-reprompt.component';
@Injectable()
export class PasswordRepromptService extends BasePasswordRepromptService {
component = PasswordRepromptComponent;
}