Suggested changes from CR

This commit is contained in:
CarleyDiaz-Bitwarden 2022-06-21 16:17:57 -04:00
parent 85e327ab7d
commit 568537af19
18 changed files with 329 additions and 186 deletions

View File

@ -49,7 +49,7 @@
</div>
</div>
</div>
<div class="modal-top-padding-sm">
<div class="tw-mt-4">
<button type="submit" class="btn btn-primary btn-submit" appBlurClick>
<span>{{ "importData" | i18n }}</span>
</button>

View File

@ -0,0 +1,36 @@
<div class="modal fade" 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="tw-text-center bwi-3x">
<i class="bwi bwi-exclamation-triangle text-warning"></i>
</div>
<h2 class="tw-text-center tw-font-semibold" id="confirmUserTitle">
{{ modalTitle | i18n }}
</h2>
<div class="modal-body">
<div>
{{ confirmDescription | i18n }}
</div>
</div>
<div class="modal-footer">
<div class="modal-footer-content">
<div [formGroup]="myGroup">
<div class="form-group">
<app-user-verification ngDefaultControl formControlName="secret" name="secret">
</app-user-verification>
</div>
</div>
</div>
<button type="submit" class="btn btn-primary btn-submit" appBlurClick>
<span>{{ confirmButtonText | 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 { UserVerificationPromptComponent as BaseUserVerificationPrompt } from "@bitwarden/angular/components/user-verification-prompt.component";
@Component({
templateUrl: "user-verification-prompt.component.html",
})
export class UserVerificationPromptComponent extends BaseUserVerificationPrompt {}

View File

@ -25,7 +25,7 @@ import { OrganizationSwitcherComponent } from "../components/organization-switch
import { PasswordRepromptComponent } from "../components/password-reprompt.component";
import { PasswordStrengthComponent } from "../components/password-strength.component";
import { PremiumBadgeComponent } from "../components/premium-badge.component";
import { UserSecretPromptComponent } from "../components/user-secret-prompt.component";
import { UserVerificationPromptComponent } from "../components/user-verification-prompt.component";
import { FooterComponent } from "../layouts/footer.component";
import { FrontendLayoutComponent } from "../layouts/frontend-layout.component";
import { NavbarComponent } from "../layouts/navbar.component";
@ -272,7 +272,7 @@ import { OrganizationBadgeModule } from "./vault/modules/organization-badge/orga
PasswordGeneratorPolicyComponent,
PasswordRepromptComponent,
FilePasswordPromptComponent,
UserSecretPromptComponent,
UserVerificationPromptComponent,
PasswordStrengthComponent,
PaymentComponent,
PaymentMethodComponent,

View File

@ -3,7 +3,7 @@ import { FormBuilder } from "@angular/forms";
import { ActivatedRoute } from "@angular/router";
import { ModalConfig, ModalService } from "@bitwarden/angular/services/modal.service";
import { UserSecretPromptService } from "@bitwarden/angular/services/userSecretPrompt.service";
import { UserVerificationPromptService } from "@bitwarden/angular/services/userVerificationPrompt.service";
import { ApiService } from "@bitwarden/common/abstractions/api.service";
import { CryptoService } from "@bitwarden/common/abstractions/crypto.service";
import { EventService } from "@bitwarden/common/abstractions/event.service";
@ -36,7 +36,7 @@ export class ExportComponent extends BaseExportComponent {
modalService: ModalService,
apiService: ApiService,
stateService: StateService,
userSecretPromptService: UserSecretPromptService,
userVerificationPromptService: UserVerificationPromptService,
modalConfig: ModalConfig
) {
super(
@ -52,7 +52,7 @@ export class ExportComponent extends BaseExportComponent {
modalService,
apiService,
stateService,
userSecretPromptService,
userVerificationPromptService,
modalConfig
);
this.confirmDescription = modalConfig.data.confirmDescription;

View File

@ -31,7 +31,7 @@ import { PlatformUtilsService as PlatformUtilsServiceAbstraction } from "@bitwar
import { StateService as BaseStateServiceAbstraction } from "@bitwarden/common/abstractions/state.service";
import { StateMigrationService as StateMigrationServiceAbstraction } from "@bitwarden/common/abstractions/stateMigration.service";
import { StorageService as StorageServiceAbstraction } from "@bitwarden/common/abstractions/storage.service";
import { UserSecretPromptService as UserSecretPromptServiceAbstraction } from "@bitwarden/common/abstractions/userSecretPrompt.service";
import { UserVerificationPromptService as UserVerificationPromptServiceAbstraction } from "@bitwarden/common/abstractions/userVerificationPrompt.service";
import { StateFactory } from "@bitwarden/common/factories/stateFactory";
import { ExportService } from "@bitwarden/common/services/export.service";
import { ImportService } from "@bitwarden/common/services/import.service";
@ -47,7 +47,7 @@ import { MemoryStorageService } from "../../services/memoryStorage.service";
import { PasswordRepromptService } from "../../services/passwordReprompt.service";
import { StateService } from "../../services/state.service";
import { StateMigrationService } from "../../services/stateMigration.service";
import { UserSecretPromptService } from "../../services/userSecretPrompt.service";
import { UserVerificationPromptService } from "../../services/userVerificationPrompt.service";
import { WebPlatformUtilsService } from "../../services/webPlatformUtils.service";
import { HomeGuard } from "../guards/home.guard";
import { PermissionsGuard as OrgPermissionsGuard } from "../organizations/guards/permissions.guard";
@ -156,8 +156,8 @@ import { RouterService } from "./router.service";
useClass: FilePasswordPromptService,
},
{
provide: UserSecretPromptServiceAbstraction,
useClass: UserSecretPromptService,
provide: UserVerificationPromptServiceAbstraction,
useClass: UserVerificationPromptService,
},
HomeGuard,
],

View File

@ -1,6 +1,6 @@
<form
#form
(ngSubmit)="promptUserForSecret(encryptionType)"
(ngSubmit)="submit()"
ngNativeValidate
[appApiAction]="formPromise"
[formGroup]="exportForm"
@ -25,28 +25,21 @@
name="format"
formControlName="format"
[(ngModel)]="formatControl"
(change)="encryptionType = '0'"
(change)="encryptionType = 0"
>
<option *ngFor="let f of formatOptions" [value]="f.value">{{ f.name }}</option>
</select>
</div>
</div>
<div class="row">
<div class="box form-group col-6">
<input formControlName="secret" name="secret" style="display: none" />
<ng-container class="box-content condensed" *ngIf="formatControl === 'encrypted_json'">
<div
class="box-content-row box-content-row-radio"
role="radiogroup"
aria-labelledby="fileTypeHeading"
>
<div class="form-group col-6">
<ng-container *ngIf="formatControl === 'encrypted_json'">
<div role="radiogroup" aria-labelledby="fileTypeHeading">
<label id="fileTypeHeading" class="radio-header">
{{ "fileTypeHeading" | i18n }}
</label>
<!-- First Item -- Account Backup Option -->
<div class="radio-group align-start text-default" appBoxRow name="FileTypeOptions">
<div appBoxRow name="FileTypeOptions">
<input
type="radio"
class="radio"
@ -54,9 +47,9 @@
id="1"
[value]="1"
[(ngModel)]="encryptionType"
(change)="encryptionType = '1'"
(change)="encryptionType = 0"
/>
<label class="unstyled"> Account Backup </label>
<label class="unstyled"> {{ "accountBackup" | i18n }} </label>
<div class="small text-muted" style="margin-left: 1.25em">
{{ "accountBackupOptionDescription" | i18n }}
</div>
@ -67,87 +60,84 @@
id="2"
[value]="2"
[(ngModel)]="encryptionType"
(change)="encryptionType = '2'"
(change)="encryptionType = 1"
/>
<input formControlName="fileEncryptionType" [ngModel]="encryptionType" hidden="true" />
<label class="unstyled"> Password Protected </label>
<label class="unstyled">{{ "passwordProtected" | i18n }}</label>
<div class="small text-muted" style="margin-left: 1.25em">
{{ "passwordProtectedOptionDescription" | i18n }}
</div>
</div>
<br />
</div>
</ng-container>
<ng-container
class="row"
*ngIf="encryptionType === '2' && formatControl === 'encrypted_json'"
>
<label for="format">{{ "filePassword" | i18n }}</label>
<ng-container *ngIf="encryptionType == 1">
<label for="format">{{ "filePassword" | i18n }}</label>
<div class="input-group">
<input
type="{{ showPassword ? 'text' : 'password' }}"
formControlName="password"
class="form-control"
/>
<div class="input-group-append">
<button
type="button"
class="btn btn-outline-secondary"
appStopClick
appA11yTitle="{{ 'toggleVisibility' | i18n }}"
[attr.aria-pressed]="showPassword"
(click)="togglePassword()"
>
<i
class="bwi bwi-lg"
aria-hidden="true"
[ngClass]="{ 'bwi-eye': !showPassword, 'bwi-eye-slash': showPassword }"
></i>
</button>
</div>
</div>
<div class="small text-muted">
{{ "exportPasswordDescription" | i18n }}
</div>
<br />
<label for="format">{{ "confirmFilePassword" | i18n }}</label>
<div class="input-group">
<input
formControlName="confirmPassword"
[(ngModel)]="encryptionPassword"
(change)="encryptionPassword = $event.target.value"
class="form-control"
type="{{ showConfirmPassword ? 'text' : 'password' }}"
/>
<div class="input-group-append">
<div class="action-buttons">
<div class="input-group">
<input
type="{{ showPassword ? 'text' : 'password' }}"
formControlName="password"
class="form-control"
/>
<div class="input-group-append">
<button
type="button"
class="btn btn-outline-secondary"
appStopClick
appA11yTitle="{{ 'toggleVisibility' | i18n }}"
[attr.aria-pressed]="showConfirmPassword"
(click)="toggleConfirmPassword()"
[attr.aria-pressed]="showPassword"
(click)="togglePassword()"
>
<i
class="bwi bwi-lg"
aria-hidden="true"
[ngClass]="{
'bwi-eye': !showConfirmPassword,
'bwi-eye-slash': showConfirmPassword
}"
[ngClass]="{ 'bwi-eye': !showPassword, 'bwi-eye-slash': showPassword }"
></i>
</button>
</div>
</div>
</div>
<br />
<div class="small text-muted">
{{ "exportPasswordDescription" | i18n }}
</div>
<br />
<label for="format">{{ "confirmFilePassword" | i18n }}</label>
<div class="input-group">
<input
formControlName="confirmPassword"
[(ngModel)]="encryptionPassword"
(change)="encryptionPassword = $event.target.value"
class="form-control"
type="{{ showConfirmPassword ? 'text' : 'password' }}"
/>
<div class="input-group-append">
<div class="action-buttons">
<button
type="button"
class="btn btn-outline-secondary"
appStopClick
appA11yTitle="{{ 'toggleVisibility' | i18n }}"
[attr.aria-pressed]="showConfirmPassword"
(click)="toggleConfirmPassword()"
>
<i
class="bwi bwi-lg"
aria-hidden="true"
[ngClass]="{
'bwi-eye': !showConfirmPassword,
'bwi-eye-slash': showConfirmPassword
}"
></i>
</button>
</div>
</div>
</div>
<br />
</ng-container>
</ng-container>
<button
type="submit"

View File

@ -12,8 +12,9 @@ import { LogService } from "@bitwarden/common/abstractions/log.service";
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
import { PolicyService } from "@bitwarden/common/abstractions/policy.service";
import { StateService } from "@bitwarden/common/abstractions/state.service";
import { UserSecretPromptService } from "@bitwarden/common/abstractions/userSecretPrompt.service";
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification.service";
import { UserVerificationPromptService } from "@bitwarden/common/abstractions/userVerificationPrompt.service";
import { EncryptedExportType } from "@bitwarden/common/enums/EncryptedExportType";
@Component({
selector: "app-export",
@ -22,7 +23,7 @@ import { UserVerificationService } from "@bitwarden/common/abstractions/userVeri
export class ExportComponent extends BaseExportComponent {
organizationId: string;
formatControl: string;
encryptionType: string;
encryptionType: EncryptedExportType;
showPassword: boolean;
showConfirmPassword: boolean;
secretValue: string;
@ -31,9 +32,6 @@ export class ExportComponent extends BaseExportComponent {
confirmButtonText: string;
modalTitle: string;
@ViewChild("viewUserApiKeyModalRef", { read: ViewContainerRef, static: true })
viewUserApiKeyModalRef: ViewContainerRef;
constructor(
cryptoService: CryptoService,
i18nService: I18nService,
@ -47,7 +45,7 @@ export class ExportComponent extends BaseExportComponent {
modalService: ModalService,
apiService: ApiService,
stateService: StateService,
userSecretPromptService: UserSecretPromptService,
userVerificationPromptService: UserVerificationPromptService,
modalConfig: ModalConfig
) {
super(
@ -64,44 +62,30 @@ export class ExportComponent extends BaseExportComponent {
modalService,
apiService,
stateService,
userSecretPromptService,
userVerificationPromptService,
modalConfig
);
}
async promptUserForSecret(encryptionType: string) {
//Default text values
let confirmDescription = "encExportKeyWarningDesc";
let confirmButtonText = "exportVault";
let modalTitle = "confirmVaultExport";
//Password encrypted export
if (encryptionType == "2") {
confirmDescription = "confirmVaultExportDesc";
confirmButtonText = "exportVault";
modalTitle = "confirmVaultExport";
}
async submit() {
const confirmDescription =
this.encryptionType == EncryptedExportType.FileEncrypted
? "confirmVaultExportDesc"
: "encExportKeyWarningDesc";
const confirmButtonText = "exportVault";
const modalTitle = "confirmVaultExport";
try {
if (
await this.userSecretPromptService.showPasswordPrompt(
await this.userVerificationPromptService.showUserVerificationPrompt(
confirmDescription,
confirmButtonText,
modalTitle
)
) {
//successful
} else {
//failed
this.platformUtilsService.showToast(
"error",
this.i18nService.t("error"),
this.i18nService.t("invalidMasterPassword")
);
return;
this.submitWithSecretAlreadyVerified();
}
this.submitWithSecretAlreadyVerified();
} catch {
this.platformUtilsService.showToast(
"error",

View File

@ -119,11 +119,6 @@ export class ImportComponent implements OnInit {
} else {
//failed - File Password issues
this.loading = false;
this.platformUtilsService.showToast(
"error",
this.i18nService.t("error"),
this.i18nService.t("invalidMasterPassword")
);
return;
}
} else {

View File

@ -896,15 +896,24 @@
"confirmFilePassword": {
"message": "Confirm File Password"
},
"passwordProtectedOptionDescription": {
"message": "Leverages your bitwarden account encryption not master password, to protect the export. This export can only be imported into the current account. Use this to create a backup that cannot be used elsewhere."
},
"accountBackupOptionDescription": {
"message": "Leverages your Bitwarden account encryption not master password, to protect the export. This export can only be imported into the current account. Use this to create a backup that cannot be used elsewhere."
},
"passwordProtectedOptionDescription": {
"message": "Create a user-generated password to protect the export. Use this to create an export that can be used in other accounts."
},
"fileTypeHeading": {
"message": "File Type"
},
"accountBackup": {
"message": "Account Backup"
},
"passwordProtected": {
"message": "Password Protected"
},
"filePasswordAndConfirmFilePasswordDoNotMatch": {
"message": "File Password and Confirm File Password do not match."
},
"confirmVaultImport": {
"message": "Confirm Vault Import"
},

View File

@ -875,30 +875,6 @@
"exportVault": {
"message": "Export vault"
},
"confirmFormat": {
"message": "Confirm Format"
},
"filePassword": {
"message": "File Password"
},
"confirmFilePassword": {
"message": "Confirm File Password"
},
"passwordProtectedOptionDescription": {
"message": "Leverages your bitwarden account encryption not master password, to protect the export. This export can only be imported into the current account. Use this to create a backup that cannot be used elsewhere."
},
"accountBackupOptionDescription": {
"message": "Create a user-generated password to protect the export. Use this to create an export that can be used in other accounts."
},
"fileTypeHeading": {
"message": "File Type"
},
"confirmVaultImport": {
"message": "Confirm Vault Import"
},
"confirmVaultImportDesc": {
"message": "This file is password protected. Please enter the file password to import data."
},
"fileFormat": {
"message": "File format"
},
@ -4725,9 +4701,6 @@
"confirmIdentity": {
"message": "Confirm your identity to continue."
},
"exportPasswordDescription" : {
"message": "This password will be used to export and import this file"
},
"verificationCodeRequired": {
"message": "Verification code is required."
},

View File

@ -6,6 +6,21 @@
}
}
.modal-footer-content {
border: none;
border-radius: none;
@include themify($themes) {
background-color: themed("footerBackgroundColor");
}
position: relative;
display: flex;
flex-direction: column;
width: 100%;
pointer-events: auto;
background-clip: padding-box;
outline: 0;
}
.modal-dialog {
border: 1px solid rgba(0, 0, 0, 0.2);
border-radius: 0.3rem;
@ -75,10 +90,6 @@
}
}
.modal-top-padding-sm {
padding-top: 1.5em;
}
.close {
@include themify($themes) {
color: themed("textColor");

View File

@ -0,0 +1,10 @@
import { Injectable } from "@angular/core";
import { UserVerificationPromptService as BaseUserVerificationPrompt } from "@bitwarden/angular/services/userVerificationPrompt.service";
import { UserVerificationPromptComponent } from "../app/components/user-verification-prompt.component";
@Injectable()
export class UserVerificationPromptService extends BaseUserVerificationPrompt {
component = UserVerificationPromptComponent;
}

View File

@ -18,8 +18,9 @@ import { LogService } from "@bitwarden/common/abstractions/log.service";
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
import { PolicyService } from "@bitwarden/common/abstractions/policy.service";
import { StateService } from "@bitwarden/common/abstractions/state.service";
import { UserSecretPromptService } from "@bitwarden/common/abstractions/userSecretPrompt.service";
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification.service";
import { UserVerificationPromptService } from "@bitwarden/common/abstractions/userVerificationPrompt.service";
import { EncryptedExportType } from "@bitwarden/common/enums/EncryptedExportType";
import { EventType } from "@bitwarden/common/enums/eventType";
import { PolicyType } from "@bitwarden/common/enums/policyType";
@ -29,7 +30,6 @@ export class ExportComponent implements OnInit {
formPromise: Promise<string>;
disabledByPolicy = false;
private alreadyVerified = false;
@ViewChild("viewUserApiKeyTemplate", { read: ViewContainerRef, static: true })
viewUserApiKeyModalRef: ViewContainerRef;
@ -64,7 +64,7 @@ export class ExportComponent implements OnInit {
protected modalService: ModalService,
protected apiService: ApiService,
protected stateService: StateService,
protected userSecretPromptService: UserSecretPromptService,
protected userVerificationPromptService: UserVerificationPromptService,
protected modalConfig: ModalConfig
) {}
@ -86,12 +86,29 @@ export class ExportComponent implements OnInit {
}
async submitWithSecretAlreadyVerified() {
if (this.disabledByPolicy) {
this.platformUtilsService.showToast(
"error",
null,
this.i18nService.t("personalVaultExportPolicyInEffect")
);
return;
}
if (!this.validForm) {
return;
}
this.alreadyVerified = true;
this.submit();
try {
this.formPromise = this.getExportData();
const data = await this.formPromise;
this.downloadFile(data);
this.saved();
await this.collectEvent();
this.exportForm.get("secret").setValue("");
} catch (e) {
this.logService.error(e);
}
}
async submit() {
@ -104,24 +121,22 @@ export class ExportComponent implements OnInit {
return;
}
if (!this.alreadyVerified) {
const acceptedWarning = await this.warningDialog();
if (!acceptedWarning) {
return;
}
const secret = this.exportForm.get("secret").value;
try {
await this.userVerificationService.verifyUser(secret);
} catch (e) {
this.platformUtilsService.showToast(
"error",
this.i18nService.t("errorOccurred"),
e.message
);
return;
}
const acceptedWarning = await this.warningDialog();
if (!acceptedWarning) {
return;
}
const secret = this.exportForm.get("secret").value;
const successfulVerification = await this.userVerificationService.verifyUser(secret);
if (!successfulVerification) {
this.platformUtilsService.showToast(
"error",
this.i18nService.t("error"),
this.i18nService.t("invalidMasterPassword")
);
return;
}
try {
this.formPromise = this.getExportData();
const data = await this.formPromise;
@ -184,22 +199,21 @@ export class ExportComponent implements OnInit {
}
get validForm() {
//fileEncryptionType 2 = file requires a user entered password, specific to the file
if (this.fileEncryptionType == 2 && this.format == "encrypted_json") {
const password = this.password;
const confirmPassword = this.confirmPassword;
if (password.length > 0 || confirmPassword.length > 0) {
if (password != confirmPassword) {
if (
this.fileEncryptionType == EncryptedExportType.FileEncrypted &&
this.format == "encrypted_json"
) {
if (this.password.length > 0 || this.confirmPassword.length > 0) {
if (this.password != this.confirmPassword) {
this.platformUtilsService.showToast(
"error",
this.i18nService.t("errorOccurred"),
"File Password and Confirm File Password do not match."
this.i18nService.t("filePasswordAndConfirmFilePasswordDoNotMatch")
);
return false;
}
this.encryptionPassword = password;
this.encryptionPassword = this.password;
return true;
}
} else {

View File

@ -1,6 +1,5 @@
import { Directive } from "@angular/core";
import { CryptoService } from "@bitwarden/common/abstractions/crypto.service";
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
import { ImportService } from "@bitwarden/common/abstractions/import.service";
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
@ -21,7 +20,6 @@ export class FilePasswordPromptComponent {
constructor(
private modalRef: ModalRef,
private cryptoService: CryptoService,
private platformUtilsService: PlatformUtilsService,
private i18nService: I18nService,
private importService: ImportService,
@ -50,7 +48,11 @@ export class FilePasswordPromptComponent {
const passwordError = await formPromise;
if (passwordError != null) {
this.modalRef.close(false);
this.platformUtilsService.showToast(
"error",
this.i18nService.t("error"),
this.i18nService.t("invalidMasterPassword")
);
} else {
this.modalRef.close(true);
}

View File

@ -0,0 +1,56 @@
import { Directive } from "@angular/core";
import { FormBuilder, FormControl } from "@angular/forms";
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification.service";
import { ModalConfig } from "../services/modal.service";
import { ModalRef } from "./modal/modal.ref";
/**
* Used to verify the user's secret, you can customize all of the text in the modal.
*/
@Directive()
export class UserVerificationPromptComponent {
showPassword = false;
organizationId = "";
confirmDescription = this.config.data.confirmDescription;
confirmButtonText = this.config.data.confirmButtonText;
modalTitle = this.config.data.modalTitle;
myGroup = this.formBuilder.group({
secret: new FormControl(),
});
constructor(
private modalRef: ModalRef,
protected config: ModalConfig,
protected userVerificationService: UserVerificationService,
private formBuilder: FormBuilder,
private platformUtilsService: PlatformUtilsService,
private i18nService: I18nService
) {}
togglePassword() {
this.showPassword = !this.showPassword;
}
async submit() {
const secret = this.myGroup.get("secret").value;
try {
//Incorrect secret will throw an invalid password error.
await this.userVerificationService.verifyUser(secret);
} catch (e) {
this.platformUtilsService.showToast(
"error",
this.i18nService.t("error"),
this.i18nService.t("invalidMasterPassword")
);
return;
}
this.modalRef.close(true);
}
}

View File

@ -3,7 +3,6 @@ import { Injectable } from "@angular/core";
import { FilePasswordPromptService as FilePasswordPromptServiceAbstraction } from "@bitwarden/common/abstractions/filePasswordPrompt.service";
import { KeyConnectorService } from "@bitwarden/common/abstractions/keyConnector.service";
import { FilePasswordPromptComponent } from "../components/file-password-prompt.component";
import { ModalService } from "./modal.service";
@ -29,7 +28,7 @@ export class FilePasswordPromptService implements FilePasswordPromptServiceAbstr
return true;
}
const ref = this.modalService.open(this.component, {
const ref = await this.modalService.open(this.component, {
allowMultipleModals: true,
data: {
fileContents: fcontents,

View File

@ -0,0 +1,56 @@
import { Injectable } from "@angular/core";
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
import { KeyConnectorService } from "@bitwarden/common/abstractions/keyConnector.service";
import { UserVerificationPromptService as UserVerificationPromptServiceAbstraction } from "@bitwarden/common/abstractions/userVerificationPrompt.service";
import { UserVerificationPromptComponent } from "../components/user-verification-prompt.component";
import { ModalService } from "./modal.service";
/**
* Used to verify the user's File Password for the "Import passwords using File Password" feature only.
*/
@Injectable()
export class UserVerificationPromptService implements UserVerificationPromptServiceAbstraction {
protected component = UserVerificationPromptComponent;
constructor(
private modalService: ModalService,
private keyConnectorService: KeyConnectorService,
protected i18nService: I18nService
) {}
protectedFields() {
return ["TOTP", "Password", "H_Field", "Card Number", "Security Code"];
}
async showUserVerificationPrompt(
confirmDescription?: string,
confirmButtonText?: string,
modalTitle?: string
) {
if (!(await this.enabled())) {
return true;
}
const ref = await this.modalService.open(this.component, {
allowMultipleModals: true,
data: {
confirmDescription: confirmDescription ? confirmDescription : "passwordConfirmationDesc",
confirmButtonText: confirmButtonText ? confirmButtonText : "ok",
modalTitle: modalTitle ? modalTitle : "passwordConfirmation",
},
});
if (ref == null) {
return false;
}
return (await ref.onClosedPromise()) === true;
}
async enabled() {
return !(await this.keyConnectorService.getUsesKeyConnector());
}
}