1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-24 04:04:24 +00:00

[PM-1504] Migrate Dialogs to DialogService (#5013)

This PR introduces a generic `DialogService` which can be used by all the clients. This allows us to decouple dialogs from the `PlatformUtilsHelper`.

The `DialogService` provides a new method, `openSimpleDialog` which is the new interface for that type of dialogs.

This gives us 3 different implementations: 
- Web: DialogService modern dialogs
- Browser: SweetAlert
- Desktop: Native electron based
This commit is contained in:
Oscar Hinton
2023-05-02 18:46:03 +02:00
committed by GitHub
parent 7c4b2c04b9
commit 4e1867682f
144 changed files with 1514 additions and 1212 deletions

View File

@@ -2,6 +2,7 @@ import { Component, NgZone } from "@angular/core";
import { Router } from "@angular/router";
import { LockComponent as BaseLockComponent } from "@bitwarden/angular/auth/components/lock.component";
import { DialogServiceAbstraction } from "@bitwarden/angular/services/dialog";
import { ApiService } from "@bitwarden/common/abstractions/api.service";
import { CryptoService } from "@bitwarden/common/abstractions/crypto.service";
import { EnvironmentService } from "@bitwarden/common/abstractions/environment.service";
@@ -48,7 +49,8 @@ export class LockComponent extends BaseLockComponent {
policyApiService: PolicyApiServiceAbstraction,
policyService: InternalPolicyService,
passwordGenerationService: PasswordGenerationServiceAbstraction,
private authService: AuthService
private authService: AuthService,
dialogService: DialogServiceAbstraction
) {
super(
router,
@@ -66,7 +68,8 @@ export class LockComponent extends BaseLockComponent {
ngZone,
policyApiService,
policyService,
passwordGenerationService
passwordGenerationService,
dialogService
);
this.successRoute = "/tabs/current";
this.isInitialLockScreen = (window as any).previousPopupUrl == null;

View File

@@ -3,6 +3,7 @@ import { UntypedFormBuilder } from "@angular/forms";
import { Router } from "@angular/router";
import { RegisterComponent as BaseRegisterComponent } from "@bitwarden/angular/components/register.component";
import { DialogServiceAbstraction } from "@bitwarden/angular/services/dialog";
import { ApiService } from "@bitwarden/common/abstractions/api.service";
import { AuditService } from "@bitwarden/common/abstractions/audit.service";
import { CryptoService } from "@bitwarden/common/abstractions/crypto.service";
@@ -36,7 +37,8 @@ export class RegisterComponent extends BaseRegisterComponent {
passwordGenerationService: PasswordGenerationServiceAbstraction,
environmentService: EnvironmentService,
logService: LogService,
auditService: AuditService
auditService: AuditService,
dialogService: DialogServiceAbstraction
) {
super(
formValidationErrorService,
@@ -51,7 +53,8 @@ export class RegisterComponent extends BaseRegisterComponent {
passwordGenerationService,
environmentService,
logService,
auditService
auditService,
dialogService
);
}
}

View File

@@ -2,6 +2,7 @@ import { Component } from "@angular/core";
import { ActivatedRoute, Router } from "@angular/router";
import { SetPasswordComponent as BaseSetPasswordComponent } from "@bitwarden/angular/components/set-password.component";
import { DialogServiceAbstraction } from "@bitwarden/angular/services/dialog";
import { ApiService } from "@bitwarden/common/abstractions/api.service";
import { CryptoService } from "@bitwarden/common/abstractions/crypto.service";
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
@@ -34,7 +35,8 @@ export class SetPasswordComponent extends BaseSetPasswordComponent {
syncService: SyncService,
route: ActivatedRoute,
organizationApiService: OrganizationApiServiceAbstraction,
organizationUserService: OrganizationUserService
organizationUserService: OrganizationUserService,
dialogService: DialogServiceAbstraction
) {
super(
i18nService,
@@ -50,7 +52,8 @@ export class SetPasswordComponent extends BaseSetPasswordComponent {
route,
stateService,
organizationApiService,
organizationUserService
organizationUserService,
dialogService
);
}
}

View File

@@ -3,6 +3,7 @@ import { ActivatedRoute, Router } from "@angular/router";
import { first } from "rxjs/operators";
import { TwoFactorComponent as BaseTwoFactorComponent } from "@bitwarden/angular/auth/components/two-factor.component";
import { DialogServiceAbstraction, SimpleDialogType } from "@bitwarden/angular/services/dialog";
import { ApiService } from "@bitwarden/common/abstractions/api.service";
import { AppIdService } from "@bitwarden/common/abstractions/appId.service";
import { BroadcasterService } from "@bitwarden/common/abstractions/broadcaster.service";
@@ -46,7 +47,8 @@ export class TwoFactorComponent extends BaseTwoFactorComponent {
logService: LogService,
twoFactorService: TwoFactorService,
appIdService: AppIdService,
loginService: LoginService
loginService: LoginService,
private dialogService: DialogServiceAbstraction
) {
super(
authService,
@@ -102,12 +104,11 @@ export class TwoFactorComponent extends BaseTwoFactorComponent {
this.selectedProviderType === TwoFactorProviderType.Email &&
this.popupUtilsService.inPopup(window)
) {
const confirmed = await this.platformUtilsService.showDialog(
this.i18nService.t("popup2faCloseMessage"),
null,
this.i18nService.t("yes"),
this.i18nService.t("no")
);
const confirmed = await this.dialogService.openSimpleDialog({
title: { key: "warning" },
content: { key: "popup2faCloseMessage" },
type: SimpleDialogType.WARNING,
});
if (confirmed) {
this.popupUtilsService.popOut(window);
}

View File

@@ -153,10 +153,11 @@ export class NativeMessagingBackground {
this.connected = false;
this.messagingService.send("showDialog", {
text: this.i18nService.t("nativeMessagingInvalidEncryptionDesc"),
title: this.i18nService.t("nativeMessagingInvalidEncryptionTitle"),
confirmText: this.i18nService.t("ok"),
type: "error",
title: { key: "nativeMessagingInvalidEncryptionTitle" },
content: { key: "nativeMessagingInvalidEncryptionDesc" },
acceptButtonText: { key: "ok" },
cancelButtonText: null,
type: "danger",
});
break;
case "verifyFingerprint": {
@@ -199,10 +200,11 @@ export class NativeMessagingBackground {
showWrongUserDialog() {
this.messagingService.send("showDialog", {
text: this.i18nService.t("nativeMessagingWrongUserDesc"),
title: this.i18nService.t("nativeMessagingWrongUserTitle"),
confirmText: this.i18nService.t("ok"),
type: "error",
title: { key: "nativeMessagingWrongUserTitle" },
content: { key: "nativeMessagingWrongUserDesc" },
acceptButtonText: { key: "ok" },
cancelButtonText: null,
type: "danger",
});
}
@@ -258,10 +260,11 @@ export class NativeMessagingBackground {
this.connected = false;
this.messagingService.send("showDialog", {
text: this.i18nService.t("nativeMessagingInvalidEncryptionDesc"),
title: this.i18nService.t("nativeMessagingInvalidEncryptionTitle"),
confirmText: this.i18nService.t("ok"),
type: "error",
title: { key: "nativeMessagingInvalidEncryptionTitle" },
content: { key: "nativeMessagingInvalidEncryptionDesc" },
acceptButtonText: { key: "ok" },
cancelButtonText: null,
type: "danger",
});
}
}
@@ -285,18 +288,20 @@ export class NativeMessagingBackground {
if (message.response === "not enabled") {
this.messagingService.send("showDialog", {
text: this.i18nService.t("biometricsNotEnabledDesc"),
title: this.i18nService.t("biometricsNotEnabledTitle"),
confirmText: this.i18nService.t("ok"),
type: "error",
title: { key: "biometricsNotEnabledTitle" },
content: { key: "biometricsNotEnabledDesc" },
acceptButtonText: { key: "ok" },
cancelButtonText: null,
type: "danger",
});
break;
} else if (message.response === "not supported") {
this.messagingService.send("showDialog", {
text: this.i18nService.t("biometricsNotSupportedDesc"),
title: this.i18nService.t("biometricsNotSupportedTitle"),
confirmText: this.i18nService.t("ok"),
type: "error",
title: { key: "biometricsNotSupportedTitle" },
content: { key: "biometricsNotSupportedDesc" },
acceptButtonText: { key: "ok" },
cancelButtonText: null,
type: "danger",
});
break;
}
@@ -377,13 +382,8 @@ export class NativeMessagingBackground {
await this.cryptoService.getFingerprint(await this.stateService.getUserId(), this.publicKey)
).join(" ");
this.messagingService.send("showDialog", {
html: `${this.i18nService.t(
"desktopIntegrationVerificationText"
)}<br><br><strong>${fingerprint}</strong>`,
title: this.i18nService.t("desktopSyncVerificationTitle"),
confirmText: this.i18nService.t("ok"),
type: "warning",
this.messagingService.send("showNativeMessagingFinterprintDialog", {
fingerprint: fingerprint,
});
}
}

View File

@@ -119,9 +119,6 @@ export default class RuntimeBackground {
BrowserApi.closeBitwardenExtensionTab();
}, msg.delay ?? 0);
break;
case "showDialogResolve":
this.platformUtilsService.resolveDialogPromise(msg.dialogId, msg.confirmed);
break;
case "bgCollectPageDetails":
await this.main.collectPageDetailsForContentScript(sender.tab, msg.sender, sender.frameId);
break;
@@ -204,10 +201,10 @@ export default class RuntimeBackground {
break;
case "emailVerificationRequired":
this.messagingService.send("showDialog", {
dialogId: "emailVerificationRequired",
title: this.i18nService.t("emailVerificationRequired"),
text: this.i18nService.t("emailVerificationRequiredDesc"),
confirmText: this.i18nService.t("ok"),
title: { key: "emailVerificationRequired" },
content: { key: "emailVerificationRequiredDesc" },
acceptButtonText: { key: "ok" },
cancelButtonText: null,
type: "info",
});
break;

View File

@@ -10,8 +10,9 @@ import { DomSanitizer } from "@angular/platform-browser";
import { NavigationEnd, Router, RouterOutlet } from "@angular/router";
import { IndividualConfig, ToastrService } from "ngx-toastr";
import { Subject, takeUntil } from "rxjs";
import Swal, { SweetAlertIcon } from "sweetalert2";
import Swal from "sweetalert2";
import { DialogServiceAbstraction, SimpleDialogOptions } from "@bitwarden/angular/services/dialog";
import { BroadcasterService } from "@bitwarden/common/abstractions/broadcaster.service";
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
import { MessagingService } from "@bitwarden/common/abstractions/messaging.service";
@@ -48,7 +49,8 @@ export class AppComponent implements OnInit, OnDestroy {
private changeDetectorRef: ChangeDetectorRef,
private ngZone: NgZone,
private sanitizer: DomSanitizer,
private platformUtilsService: PlatformUtilsService
private platformUtilsService: PlatformUtilsService,
private dialogService: DialogServiceAbstraction
) {}
async ngOnInit() {
@@ -102,6 +104,9 @@ export class AppComponent implements OnInit, OnDestroy {
}
} else if (msg.command === "showDialog") {
await this.showDialog(msg);
} else if (msg.command === "showNativeMessagingFinterprintDialog") {
// TODO: Should be refactored to live in another service.
await this.showNativeMessagingFingerprintDialog(msg);
} else if (msg.command === "showToast") {
this.ngZone.run(() => {
this.showToast(msg);
@@ -222,51 +227,24 @@ export class AppComponent implements OnInit, OnDestroy {
this.toastrService.show(message, msg.title, options, "toast-" + msg.type);
}
private async showDialog(msg: any) {
let iconClasses: string = null;
const type = msg.type;
if (type != null) {
// If you add custom types to this part, the type to SweetAlertIcon cast below needs to be changed.
switch (type) {
case "success":
iconClasses = "bwi-check text-success";
break;
case "warning":
iconClasses = "bwi-exclamation-triangle text-warning";
break;
case "error":
iconClasses = "bwi-error text-danger";
break;
case "info":
iconClasses = "bwi-info-circle text-info";
break;
default:
break;
}
}
private async showDialog(msg: SimpleDialogOptions) {
await this.dialogService.openSimpleDialog(msg);
}
const cancelText = msg.cancelText;
const confirmText = msg.confirmText;
const confirmed = await Swal.fire({
private async showNativeMessagingFingerprintDialog(msg: any) {
await Swal.fire({
heightAuto: false,
buttonsStyling: false,
icon: type as SweetAlertIcon, // required to be any of the SweetAlertIcons to output the iconHtml.
iconHtml:
iconClasses != null ? `<i class="swal-custom-icon bwi ${iconClasses}"></i>` : undefined,
text: msg.text,
html: msg.html,
titleText: msg.title,
showCancelButton: cancelText != null,
cancelButtonText: cancelText,
icon: "warning",
iconHtml: '<i class="swal-custom-icon bwi bwi-exclamation-triangle text-warning"></i>',
html: `${this.i18nService.t("desktopIntegrationVerificationText")}<br><br><strong>${
msg.fingerprint
}</strong>`,
titleText: this.i18nService.t("desktopSyncVerificationTitle"),
showConfirmButton: true,
confirmButtonText: confirmText == null ? this.i18nService.t("ok") : confirmText,
confirmButtonText: this.i18nService.t("ok"),
timer: 300000,
});
this.messagingService.send("showDialogResolve", {
dialogId: msg.dialogId,
confirmed: confirmed.value,
});
}
private async clearComponentStates() {

View File

@@ -1,14 +1,10 @@
import { A11yModule } from "@angular/cdk/a11y";
import { DialogModule } from "@angular/cdk/dialog";
import { DragDropModule } from "@angular/cdk/drag-drop";
import { LayoutModule } from "@angular/cdk/layout";
import { OverlayModule } from "@angular/cdk/overlay";
import { ScrollingModule } from "@angular/cdk/scrolling";
// eslint-disable-next-line import/order
import { CurrencyPipe, DatePipe } from "@angular/common";
// Register the locales for the application
import "./locales";
import { NgModule } from "@angular/core";
import { FormsModule, ReactiveFormsModule } from "@angular/forms";
import { BrowserModule } from "@angular/platform-browser";
@@ -76,6 +72,9 @@ import { SyncComponent } from "./settings/sync.component";
import { VaultTimeoutInputComponent } from "./settings/vault-timeout-input.component";
import { TabsComponent } from "./tabs.component";
// Register the locales for the application
import "./locales";
@NgModule({
imports: [
A11yModule,
@@ -96,6 +95,7 @@ import { TabsComponent } from "./tabs.component";
ReactiveFormsModule,
ScrollingModule,
ServicesModule,
DialogModule,
],
declarations: [
ActionButtonsComponent,

View File

@@ -0,0 +1,79 @@
import { Injectable } from "@angular/core";
import Swal, { SweetAlertIcon } from "sweetalert2";
import {
DialogService,
SimpleDialogOptions,
SimpleDialogType,
} from "@bitwarden/angular/services/dialog";
@Injectable()
export class BrowserDialogService extends DialogService {
async openSimpleDialog(options: SimpleDialogOptions) {
const defaultCancel =
options.cancelButtonText === undefined
? options.acceptButtonText == null
? "no"
: "cancel"
: null;
return this.legacyShowDialog(
this.translate(options.content),
this.translate(options.title),
this.translate(options.acceptButtonText, "yes"),
this.translate(options.cancelButtonText, defaultCancel),
options.type
);
}
private async legacyShowDialog(
body: string,
title?: string,
confirmText?: string,
cancelText?: string,
type?: SimpleDialogType
) {
let iconClasses: string = null;
let icon: SweetAlertIcon = null;
if (type != null) {
// If you add custom types to this part, the type to SweetAlertIcon cast below needs to be changed.
switch (type) {
case "success":
iconClasses = "bwi-check text-success";
icon = "success";
break;
case "warning":
iconClasses = "bwi-exclamation-triangle text-warning";
icon = "warning";
break;
case "danger":
iconClasses = "bwi-error text-danger";
icon = "error";
break;
case "info":
iconClasses = "bwi-info-circle text-info";
icon = "info";
break;
default:
break;
}
}
const confirmed = await Swal.fire({
heightAuto: false,
buttonsStyling: false,
icon: icon,
iconHtml:
iconClasses != null ? `<i class="swal-custom-icon bwi ${iconClasses}"></i>` : undefined,
text: body,
titleText: title,
showCancelButton: cancelText != null,
cancelButtonText: cancelText,
showConfirmButton: true,
confirmButtonText: confirmText == null ? this.i18nService.t("ok") : confirmText,
timer: 300000,
});
return confirmed.value;
}
}

View File

@@ -2,6 +2,7 @@ import { APP_INITIALIZER, LOCALE_ID, NgModule } from "@angular/core";
import { LockGuard as BaseLockGuardService } from "@bitwarden/angular/auth/guards/lock.guard";
import { UnauthGuard as BaseUnauthGuardService } from "@bitwarden/angular/auth/guards/unauth.guard";
import { DialogServiceAbstraction } from "@bitwarden/angular/services/dialog";
import { MEMORY_STORAGE, SECURE_STORAGE } from "@bitwarden/angular/services/injection-tokens";
import { JslibServicesModule } from "@bitwarden/angular/services/jslib-services.module";
import { ThemingService } from "@bitwarden/angular/services/theming/theming.service";
@@ -101,6 +102,7 @@ import { PasswordRepromptService } from "../../vault/popup/services/password-rep
import { BrowserFolderService } from "../../vault/services/browser-folder.service";
import { VaultFilterService } from "../../vault/services/vault-filter.service";
import { BrowserDialogService } from "./browser-dialog.service";
import { DebounceNavigationService } from "./debounceNavigationService";
import { InitService } from "./init.service";
import { PopupSearchService } from "./popup-search.service";
@@ -489,6 +491,10 @@ function getBgService<T>(service: keyof MainBackground) {
useClass: BrowserConfigService,
deps: [StateServiceAbstraction, ConfigApiServiceAbstraction],
},
{
provide: DialogServiceAbstraction,
useClass: BrowserDialogService,
},
],
})
export class ServicesModule {}

View File

@@ -2,6 +2,7 @@ import { Component } from "@angular/core";
import { ActivatedRoute, Router } from "@angular/router";
import { first } from "rxjs/operators";
import { DialogServiceAbstraction } from "@bitwarden/angular/services/dialog";
import { FolderAddEditComponent as BaseFolderAddEditComponent } from "@bitwarden/angular/vault/components/folder-add-edit.component";
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/abstractions/log.service";
@@ -22,9 +23,17 @@ export class FolderAddEditComponent extends BaseFolderAddEditComponent {
platformUtilsService: PlatformUtilsService,
private router: Router,
private route: ActivatedRoute,
logService: LogService
logService: LogService,
dialogService: DialogServiceAbstraction
) {
super(folderService, folderApiService, i18nService, platformUtilsService, logService);
super(
folderService,
folderApiService,
i18nService,
platformUtilsService,
logService,
dialogService
);
}
async ngOnInit() {

View File

@@ -1,6 +1,7 @@
import { CurrencyPipe, Location } from "@angular/common";
import { Component } from "@angular/core";
import { DialogServiceAbstraction } from "@bitwarden/angular/services/dialog";
import { PremiumComponent as BasePremiumComponent } from "@bitwarden/angular/vault/components/premium.component";
import { ApiService } from "@bitwarden/common/abstractions/api.service";
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
@@ -22,9 +23,10 @@ export class PremiumComponent extends BasePremiumComponent {
stateService: StateService,
logService: LogService,
private location: Location,
private currencyPipe: CurrencyPipe
private currencyPipe: CurrencyPipe,
dialogService: DialogServiceAbstraction
) {
super(i18nService, platformUtilsService, apiService, logService, stateService);
super(i18nService, platformUtilsService, apiService, logService, stateService, dialogService);
// Support old price string. Can be removed in future once all translations are properly updated.
const thePrice = this.currencyPipe.transform(this.price, "$");

View File

@@ -4,6 +4,7 @@ import { Router } from "@angular/router";
import { concatMap, debounceTime, filter, map, Observable, Subject, takeUntil, tap } from "rxjs";
import Swal from "sweetalert2";
import { DialogServiceAbstraction, SimpleDialogType } from "@bitwarden/angular/services/dialog";
import { ModalService } from "@bitwarden/angular/services/modal.service";
import { CryptoService } from "@bitwarden/common/abstractions/crypto.service";
import { EnvironmentService } from "@bitwarden/common/abstractions/environment.service";
@@ -82,7 +83,8 @@ export class SettingsComponent implements OnInit {
private stateService: StateService,
private popupUtilsService: PopupUtilsService,
private modalService: ModalService,
private keyConnectorService: KeyConnectorService
private keyConnectorService: KeyConnectorService,
private dialogService: DialogServiceAbstraction
) {}
async ngOnInit() {
@@ -185,13 +187,12 @@ export class SettingsComponent implements OnInit {
async saveVaultTimeout(newValue: number) {
if (newValue == null) {
const confirmed = await this.platformUtilsService.showDialog(
this.i18nService.t("neverLockWarning"),
null,
this.i18nService.t("yes"),
this.i18nService.t("cancel"),
"warning"
);
const confirmed = await this.dialogService.openSimpleDialog({
title: { key: "warning" },
content: { key: "neverLockWarning" },
type: SimpleDialogType.WARNING,
});
if (!confirmed) {
this.form.controls.vaultTimeout.setValue(this.previousVaultTimeout);
return;
@@ -222,13 +223,12 @@ export class SettingsComponent implements OnInit {
async saveVaultTimeoutAction(newValue: VaultTimeoutAction) {
if (newValue === VaultTimeoutAction.LogOut) {
const confirmed = await this.platformUtilsService.showDialog(
this.i18nService.t("vaultTimeoutLogOutConfirmation"),
this.i18nService.t("vaultTimeoutLogOutConfirmationTitle"),
this.i18nService.t("yes"),
this.i18nService.t("cancel"),
"warning"
);
const confirmed = await this.dialogService.openSimpleDialog({
title: { key: "vaultTimeoutLogOutConfirmationTitle" },
content: { key: "vaultTimeoutLogOutConfirmation" },
type: SimpleDialogType.WARNING,
});
if (!confirmed) {
this.vaultTimeoutActionOptions.forEach((option: any, i) => {
if (option.value === this.form.value.vaultTimeoutAction) {
@@ -284,24 +284,28 @@ export class SettingsComponent implements OnInit {
console.error(e);
if (this.platformUtilsService.isFirefox() && this.popupUtilsService.inSidebar(window)) {
await this.platformUtilsService.showDialog(
this.i18nService.t("nativeMessaginPermissionSidebarDesc"),
this.i18nService.t("nativeMessaginPermissionSidebarTitle"),
this.i18nService.t("ok"),
null
);
await this.dialogService.openSimpleDialog({
title: { key: "nativeMessaginPermissionSidebarTitle" },
content: { key: "nativeMessaginPermissionSidebarDesc" },
acceptButtonText: { key: "ok" },
cancelButtonText: null,
type: SimpleDialogType.INFO,
});
this.form.controls.biometric.setValue(false);
return;
}
}
if (!granted) {
await this.platformUtilsService.showDialog(
this.i18nService.t("nativeMessaginPermissionErrorDesc"),
this.i18nService.t("nativeMessaginPermissionErrorTitle"),
this.i18nService.t("ok"),
null
);
await this.dialogService.openSimpleDialog({
title: { key: "nativeMessaginPermissionErrorTitle" },
content: { key: "nativeMessaginPermissionErrorDesc" },
acceptButtonText: { key: "ok" },
cancelButtonText: null,
type: SimpleDialogType.DANGER,
});
this.form.controls.biometric.setValue(false);
return;
}
@@ -349,13 +353,13 @@ export class SettingsComponent implements OnInit {
const error = BiometricErrors[e as BiometricErrorTypes];
this.platformUtilsService.showDialog(
this.i18nService.t(error.description),
this.i18nService.t(error.title),
this.i18nService.t("ok"),
null,
"error"
);
this.dialogService.openSimpleDialog({
title: { key: error.title },
content: { key: error.description },
acceptButtonText: { key: "ok" },
cancelButtonText: null,
type: SimpleDialogType.DANGER,
});
}),
]);
} else {
@@ -375,24 +379,23 @@ export class SettingsComponent implements OnInit {
}
async logOut() {
const confirmed = await this.platformUtilsService.showDialog(
this.i18nService.t("logOutConfirmation"),
this.i18nService.t(VaultTimeoutAction.LogOut),
this.i18nService.t("yes"),
this.i18nService.t("cancel")
);
const confirmed = await this.dialogService.openSimpleDialog({
title: { key: "logOut" },
content: { key: "logOutConfirmation" },
type: SimpleDialogType.INFO,
});
if (confirmed) {
this.messagingService.send("logout");
}
}
async changePassword() {
const confirmed = await this.platformUtilsService.showDialog(
this.i18nService.t("changeMasterPasswordConfirmation"),
this.i18nService.t("changeMasterPassword"),
this.i18nService.t("yes"),
this.i18nService.t("cancel")
);
const confirmed = await this.dialogService.openSimpleDialog({
title: { key: "changeMasterPassword" },
content: { key: "changeMasterPasswordConfirmation" },
type: SimpleDialogType.INFO,
});
if (confirmed) {
BrowserApi.createNewTab(
"https://bitwarden.com/help/master-password/#change-your-master-password"
@@ -401,24 +404,22 @@ export class SettingsComponent implements OnInit {
}
async twoStep() {
const confirmed = await this.platformUtilsService.showDialog(
this.i18nService.t("twoStepLoginConfirmation"),
this.i18nService.t("twoStepLogin"),
this.i18nService.t("yes"),
this.i18nService.t("cancel")
);
const confirmed = await this.dialogService.openSimpleDialog({
title: { key: "twoStepLogin" },
content: { key: "twoStepLoginConfirmation" },
type: SimpleDialogType.INFO,
});
if (confirmed) {
BrowserApi.createNewTab("https://bitwarden.com/help/setup-two-step-login/");
}
}
async share() {
const confirmed = await this.platformUtilsService.showDialog(
this.i18nService.t("learnOrgConfirmation"),
this.i18nService.t("learnOrg"),
this.i18nService.t("yes"),
this.i18nService.t("cancel")
);
const confirmed = await this.dialogService.openSimpleDialog({
title: { key: "learnOrg" },
content: { key: "learnOrgConfirmation" },
type: SimpleDialogType.INFO,
});
if (confirmed) {
BrowserApi.createNewTab("https://bitwarden.com/help/about-organizations/");
}

View File

@@ -5,14 +5,7 @@ import { ClientType, DeviceType } from "@bitwarden/common/enums";
import { BrowserApi } from "../browser/browserApi";
import { SafariApp } from "../browser/safariApp";
const DialogPromiseExpiration = 600000; // 10 minutes
export default class BrowserPlatformUtilsService implements PlatformUtilsService {
private showDialogResolves = new Map<number, { resolve: (value: boolean) => void; date: Date }>();
private passwordDialogResolves = new Map<
number,
{ tryResolve: (canceled: boolean, password: string) => Promise<boolean>; date: Date }
>();
private static deviceCache: DeviceType = null;
constructor(
@@ -215,29 +208,6 @@ export default class BrowserPlatformUtilsService implements PlatformUtilsService
});
}
showDialog(
body: string,
title?: string,
confirmText?: string,
cancelText?: string,
type?: string,
bodyIsHtml = false
) {
const dialogId = Math.floor(Math.random() * Number.MAX_SAFE_INTEGER);
this.messagingService.send("showDialog", {
text: bodyIsHtml ? null : body,
html: bodyIsHtml ? body : null,
title: title,
confirmText: confirmText,
cancelText: cancelText,
type: type,
dialogId: dialogId,
});
return new Promise<boolean>((resolve) => {
this.showDialogResolves.set(dialogId, { resolve: resolve, date: new Date() });
});
}
isDev(): boolean {
return process.env.ENV === "development";
}
@@ -339,47 +309,6 @@ export default class BrowserPlatformUtilsService implements PlatformUtilsService
return null;
}
resolveDialogPromise(dialogId: number, confirmed: boolean) {
if (this.showDialogResolves.has(dialogId)) {
const resolveObj = this.showDialogResolves.get(dialogId);
resolveObj.resolve(confirmed);
this.showDialogResolves.delete(dialogId);
}
// Clean up old promises
this.showDialogResolves.forEach((val, key) => {
const age = new Date().getTime() - val.date.getTime();
if (age > DialogPromiseExpiration) {
this.showDialogResolves.delete(key);
}
});
}
async resolvePasswordDialogPromise(
dialogId: number,
canceled: boolean,
password: string
): Promise<boolean> {
let result = false;
if (this.passwordDialogResolves.has(dialogId)) {
const resolveObj = this.passwordDialogResolves.get(dialogId);
if (await resolveObj.tryResolve(canceled, password)) {
this.passwordDialogResolves.delete(dialogId);
result = true;
}
}
// Clean up old promises
this.passwordDialogResolves.forEach((val, key) => {
const age = new Date().getTime() - val.date.getTime();
if (age > DialogPromiseExpiration) {
this.passwordDialogResolves.delete(key);
}
});
return result;
}
async supportsBiometric() {
const platformInfo = await BrowserApi.getPlatformInfo();
if (platformInfo.os === "android") {

View File

@@ -3,6 +3,7 @@ import { Component } from "@angular/core";
import { ActivatedRoute, Router } from "@angular/router";
import { first } from "rxjs/operators";
import { DialogServiceAbstraction } from "@bitwarden/angular/services/dialog";
import { AddEditComponent as BaseAddEditComponent } from "@bitwarden/angular/tools/send/add-edit.component";
import { EnvironmentService } from "@bitwarden/common/abstractions/environment.service";
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
@@ -45,7 +46,8 @@ export class SendAddEditComponent extends BaseAddEditComponent {
private location: Location,
private popupUtilsService: PopupUtilsService,
logService: LogService,
sendApiService: SendApiService
sendApiService: SendApiService,
dialogService: DialogServiceAbstraction
) {
super(
i18nService,
@@ -57,7 +59,8 @@ export class SendAddEditComponent extends BaseAddEditComponent {
policyService,
logService,
stateService,
sendApiService
sendApiService,
dialogService
);
}

View File

@@ -1,6 +1,7 @@
import { ChangeDetectorRef, Component, NgZone } from "@angular/core";
import { Router } from "@angular/router";
import { DialogServiceAbstraction } from "@bitwarden/angular/services/dialog";
import { SendComponent as BaseSendComponent } from "@bitwarden/angular/tools/send/send.component";
import { BroadcasterService } from "@bitwarden/common/abstractions/broadcaster.service";
import { EnvironmentService } from "@bitwarden/common/abstractions/environment.service";
@@ -49,7 +50,8 @@ export class SendGroupingsComponent extends BaseSendComponent {
private changeDetectorRef: ChangeDetectorRef,
private broadcasterService: BroadcasterService,
logService: LogService,
sendApiService: SendApiService
sendApiService: SendApiService,
dialogService: DialogServiceAbstraction
) {
super(
sendService,
@@ -60,7 +62,8 @@ export class SendGroupingsComponent extends BaseSendComponent {
searchService,
policyService,
logService,
sendApiService
sendApiService,
dialogService
);
super.onSuccessfulLoad = async () => {
this.calculateTypeCounts();

View File

@@ -3,6 +3,7 @@ import { ChangeDetectorRef, Component, NgZone } from "@angular/core";
import { ActivatedRoute, Router } from "@angular/router";
import { first } from "rxjs/operators";
import { DialogServiceAbstraction } from "@bitwarden/angular/services/dialog";
import { SendComponent as BaseSendComponent } from "@bitwarden/angular/tools/send/send.component";
import { BroadcasterService } from "@bitwarden/common/abstractions/broadcaster.service";
import { EnvironmentService } from "@bitwarden/common/abstractions/environment.service";
@@ -49,7 +50,8 @@ export class SendTypeComponent extends BaseSendComponent {
private broadcasterService: BroadcasterService,
private router: Router,
logService: LogService,
sendApiService: SendApiService
sendApiService: SendApiService,
dialogService: DialogServiceAbstraction
) {
super(
sendService,
@@ -60,7 +62,8 @@ export class SendTypeComponent extends BaseSendComponent {
searchService,
policyService,
logService,
sendApiService
sendApiService,
dialogService
);
super.onSuccessfulLoad = async () => {
this.selectType(this.type);

View File

@@ -2,6 +2,7 @@ import { Component } from "@angular/core";
import { UntypedFormBuilder } from "@angular/forms";
import { Router } from "@angular/router";
import { DialogServiceAbstraction } from "@bitwarden/angular/services/dialog";
import { ExportComponent as BaseExportComponent } from "@bitwarden/angular/tools/export/components/export.component";
import { CryptoService } from "@bitwarden/common/abstractions/crypto.service";
import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service";
@@ -29,7 +30,8 @@ export class ExportComponent extends BaseExportComponent {
logService: LogService,
userVerificationService: UserVerificationService,
formBuilder: UntypedFormBuilder,
fileDownloadService: FileDownloadService
fileDownloadService: FileDownloadService,
dialogService: DialogServiceAbstraction
) {
super(
cryptoService,
@@ -42,7 +44,8 @@ export class ExportComponent extends BaseExportComponent {
logService,
userVerificationService,
formBuilder,
fileDownloadService
fileDownloadService,
dialogService
);
}

View File

@@ -3,6 +3,7 @@ import { Component } from "@angular/core";
import { ActivatedRoute, Router } from "@angular/router";
import { first } from "rxjs/operators";
import { DialogServiceAbstraction } from "@bitwarden/angular/services/dialog";
import { AddEditComponent as BaseAddEditComponent } from "@bitwarden/angular/vault/components/add-edit.component";
import { AuditService } from "@bitwarden/common/abstractions/audit.service";
import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service";
@@ -53,7 +54,8 @@ export class AddEditComponent extends BaseAddEditComponent {
organizationService: OrganizationService,
passwordRepromptService: PasswordRepromptService,
logService: LogService,
sendApiService: SendApiService
sendApiService: SendApiService,
dialogService: DialogServiceAbstraction
) {
super(
cipherService,
@@ -69,7 +71,8 @@ export class AddEditComponent extends BaseAddEditComponent {
logService,
passwordRepromptService,
organizationService,
sendApiService
sendApiService,
dialogService
);
}

View File

@@ -3,6 +3,7 @@ import { Component } from "@angular/core";
import { ActivatedRoute } from "@angular/router";
import { first } from "rxjs/operators";
import { DialogServiceAbstraction } from "@bitwarden/angular/services/dialog";
import { AttachmentsComponent as BaseAttachmentsComponent } from "@bitwarden/angular/vault/components/attachments.component";
import { ApiService } from "@bitwarden/common/abstractions/api.service";
import { CryptoService } from "@bitwarden/common/abstractions/crypto.service";
@@ -31,7 +32,8 @@ export class AttachmentsComponent extends BaseAttachmentsComponent {
private route: ActivatedRoute,
stateService: StateService,
logService: LogService,
fileDownloadService: FileDownloadService
fileDownloadService: FileDownloadService,
dialogService: DialogServiceAbstraction
) {
super(
cipherService,
@@ -42,7 +44,8 @@ export class AttachmentsComponent extends BaseAttachmentsComponent {
window,
logService,
stateService,
fileDownloadService
fileDownloadService,
dialogService
);
}

View File

@@ -3,6 +3,7 @@ import { ChangeDetectorRef, Component, NgZone } from "@angular/core";
import { ActivatedRoute, Router } from "@angular/router";
import { first } from "rxjs/operators";
import { DialogServiceAbstraction } from "@bitwarden/angular/services/dialog";
import { ViewComponent as BaseViewComponent } from "@bitwarden/angular/vault/components/view.component";
import { ApiService } from "@bitwarden/common/abstractions/api.service";
import { AuditService } from "@bitwarden/common/abstractions/audit.service";
@@ -65,7 +66,8 @@ export class ViewComponent extends BaseViewComponent {
apiService: ApiService,
passwordRepromptService: PasswordRepromptService,
logService: LogService,
fileDownloadService: FileDownloadService
fileDownloadService: FileDownloadService,
dialogService: DialogServiceAbstraction
) {
super(
cipherService,
@@ -85,7 +87,8 @@ export class ViewComponent extends BaseViewComponent {
passwordRepromptService,
logService,
stateService,
fileDownloadService
fileDownloadService,
dialogService
);
}