[PM-2516][PM-8298] Add password protected export on browser/Export managed collection (#9284)
* Move/replace submit and userVerification logic from web into the BaseExportComponent Add "@bitwarden/auth" as dependency to the vault-export-ui package New submit logic also checks for password-encrypted exports which will be need for future UI updates on browser and desktop * Create export-browser component using shared recipe - Create new export component that uses the shared export.component from @bitwarden/vault-export-ui * Update imports within AppModule * Switch to route to the new component * Add missing entries to messages.json * Delete old export.component * Remove duplicate verifyUser-method * Change placeholder example * Add documentation to protected members of ExportBrowserComponent --------- Co-authored-by: Daniel James Smith <djsmith85@users.noreply.github.com>
This commit is contained in:
parent
828e26f93c
commit
e318ac0ddf
|
@ -799,12 +799,39 @@
|
||||||
"message": "Solarized dark",
|
"message": "Solarized dark",
|
||||||
"description": "'Solarized' is a noun and the name of a color scheme. It should not be translated."
|
"description": "'Solarized' is a noun and the name of a color scheme. It should not be translated."
|
||||||
},
|
},
|
||||||
|
"exportFrom": {
|
||||||
|
"message": "Export from"
|
||||||
|
},
|
||||||
"exportVault": {
|
"exportVault": {
|
||||||
"message": "Export vault"
|
"message": "Export vault"
|
||||||
},
|
},
|
||||||
"fileFormat": {
|
"fileFormat": {
|
||||||
"message": "File format"
|
"message": "File format"
|
||||||
},
|
},
|
||||||
|
"fileEncryptedExportWarningDesc": {
|
||||||
|
"message": "This file export will be password protected and require the file password to decrypt."
|
||||||
|
},
|
||||||
|
"filePassword": {
|
||||||
|
"message": "File password"
|
||||||
|
},
|
||||||
|
"exportPasswordDescription": {
|
||||||
|
"message": "This password will be used to export and import this file"
|
||||||
|
},
|
||||||
|
"accountRestrictedOptionDescription": {
|
||||||
|
"message": "Use your account encryption key, derived from your account's username and Master Password, to encrypt the export and restrict import to only the current Bitwarden account."
|
||||||
|
},
|
||||||
|
"passwordProtectedOptionDescription": {
|
||||||
|
"message": "Set a file password to encrypt the export and import it to any Bitwarden account using the password for decryption."
|
||||||
|
},
|
||||||
|
"exportTypeHeading": {
|
||||||
|
"message": "Export type"
|
||||||
|
},
|
||||||
|
"accountRestricted": {
|
||||||
|
"message": "Account restricted"
|
||||||
|
},
|
||||||
|
"filePasswordAndConfirmFilePasswordDoNotMatch": {
|
||||||
|
"message": "“File password” and “Confirm file password“ do not match."
|
||||||
|
},
|
||||||
"warning": {
|
"warning": {
|
||||||
"message": "WARNING",
|
"message": "WARNING",
|
||||||
"description": "WARNING (should stay in capitalized letters if the language permits)"
|
"description": "WARNING (should stay in capitalized letters if the language permits)"
|
||||||
|
@ -2182,6 +2209,18 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"exportingOrganizationVaultTitle": {
|
||||||
|
"message": "Exporting organization vault"
|
||||||
|
},
|
||||||
|
"exportingOrganizationVaultDesc": {
|
||||||
|
"message": "Only the organization vault associated with $ORGANIZATION$ will be exported. Items in individual vaults or other organizations will not be included.",
|
||||||
|
"placeholders": {
|
||||||
|
"organization": {
|
||||||
|
"content": "$1",
|
||||||
|
"example": "ACME Moving Co."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"error": {
|
"error": {
|
||||||
"message": "Error"
|
"message": "Error"
|
||||||
},
|
},
|
||||||
|
|
|
@ -40,7 +40,7 @@ import { AboutPageV2Component } from "../tools/popup/settings/about-page/about-p
|
||||||
import { AboutPageComponent } from "../tools/popup/settings/about-page/about-page.component";
|
import { AboutPageComponent } from "../tools/popup/settings/about-page/about-page.component";
|
||||||
import { MoreFromBitwardenPageV2Component } from "../tools/popup/settings/about-page/more-from-bitwarden-page-v2.component";
|
import { MoreFromBitwardenPageV2Component } from "../tools/popup/settings/about-page/more-from-bitwarden-page-v2.component";
|
||||||
import { MoreFromBitwardenPageComponent } from "../tools/popup/settings/about-page/more-from-bitwarden-page.component";
|
import { MoreFromBitwardenPageComponent } from "../tools/popup/settings/about-page/more-from-bitwarden-page.component";
|
||||||
import { ExportComponent } from "../tools/popup/settings/export.component";
|
import { ExportBrowserComponent } from "../tools/popup/settings/export/export-browser.component";
|
||||||
import { ImportBrowserV2Component } from "../tools/popup/settings/import/import-browser-v2.component";
|
import { ImportBrowserV2Component } from "../tools/popup/settings/import/import-browser-v2.component";
|
||||||
import { ImportBrowserComponent } from "../tools/popup/settings/import/import-browser.component";
|
import { ImportBrowserComponent } from "../tools/popup/settings/import/import-browser.component";
|
||||||
import { SettingsV2Component } from "../tools/popup/settings/settings-v2.component";
|
import { SettingsV2Component } from "../tools/popup/settings/settings-v2.component";
|
||||||
|
@ -246,7 +246,7 @@ const routes: Routes = [
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
path: "export",
|
path: "export",
|
||||||
component: ExportComponent,
|
component: ExportBrowserComponent,
|
||||||
canActivate: [AuthGuard],
|
canActivate: [AuthGuard],
|
||||||
data: { state: "export" },
|
data: { state: "export" },
|
||||||
},
|
},
|
||||||
|
|
|
@ -16,7 +16,6 @@ import { ColorPasswordCountPipe } from "@bitwarden/angular/pipes/color-password-
|
||||||
import { ColorPasswordPipe } from "@bitwarden/angular/pipes/color-password.pipe";
|
import { ColorPasswordPipe } from "@bitwarden/angular/pipes/color-password.pipe";
|
||||||
import { UserVerificationDialogComponent } from "@bitwarden/auth/angular";
|
import { UserVerificationDialogComponent } from "@bitwarden/auth/angular";
|
||||||
import { AvatarModule, ButtonModule, ToastModule } from "@bitwarden/components";
|
import { AvatarModule, ButtonModule, ToastModule } from "@bitwarden/components";
|
||||||
import { ExportScopeCalloutComponent } from "@bitwarden/vault-export-ui";
|
|
||||||
|
|
||||||
import { AccountSwitcherComponent } from "../auth/popup/account-switching/account-switcher.component";
|
import { AccountSwitcherComponent } from "../auth/popup/account-switching/account-switcher.component";
|
||||||
import { AccountComponent } from "../auth/popup/account-switching/account.component";
|
import { AccountComponent } from "../auth/popup/account-switching/account.component";
|
||||||
|
@ -55,7 +54,6 @@ import { SendListComponent } from "../tools/popup/send/components/send-list.comp
|
||||||
import { SendAddEditComponent } from "../tools/popup/send/send-add-edit.component";
|
import { SendAddEditComponent } from "../tools/popup/send/send-add-edit.component";
|
||||||
import { SendGroupingsComponent } from "../tools/popup/send/send-groupings.component";
|
import { SendGroupingsComponent } from "../tools/popup/send/send-groupings.component";
|
||||||
import { SendTypeComponent } from "../tools/popup/send/send-type.component";
|
import { SendTypeComponent } from "../tools/popup/send/send-type.component";
|
||||||
import { ExportComponent } from "../tools/popup/settings/export.component";
|
|
||||||
import { SettingsComponent } from "../tools/popup/settings/settings.component";
|
import { SettingsComponent } from "../tools/popup/settings/settings.component";
|
||||||
import { ActionButtonsComponent } from "../vault/popup/components/action-buttons.component";
|
import { ActionButtonsComponent } from "../vault/popup/components/action-buttons.component";
|
||||||
import { CipherRowComponent } from "../vault/popup/components/cipher-row.component";
|
import { CipherRowComponent } from "../vault/popup/components/cipher-row.component";
|
||||||
|
@ -116,7 +114,6 @@ import "../platform/popup/locales";
|
||||||
AvatarModule,
|
AvatarModule,
|
||||||
AccountComponent,
|
AccountComponent,
|
||||||
ButtonModule,
|
ButtonModule,
|
||||||
ExportScopeCalloutComponent,
|
|
||||||
PopOutComponent,
|
PopOutComponent,
|
||||||
PopupPageComponent,
|
PopupPageComponent,
|
||||||
PopupTabNavigationComponent,
|
PopupTabNavigationComponent,
|
||||||
|
@ -140,7 +137,6 @@ import "../platform/popup/locales";
|
||||||
CurrentTabComponent,
|
CurrentTabComponent,
|
||||||
EnvironmentComponent,
|
EnvironmentComponent,
|
||||||
ExcludedDomainsComponent,
|
ExcludedDomainsComponent,
|
||||||
ExportComponent,
|
|
||||||
Fido2CipherRowComponent,
|
Fido2CipherRowComponent,
|
||||||
Fido2UseBrowserLinkComponent,
|
Fido2UseBrowserLinkComponent,
|
||||||
FolderAddEditComponent,
|
FolderAddEditComponent,
|
||||||
|
|
|
@ -1,35 +0,0 @@
|
||||||
<form (ngSubmit)="submit()" [formGroup]="exportForm">
|
|
||||||
<header>
|
|
||||||
<div class="left">
|
|
||||||
<button type="button" routerLink="/vault-settings">
|
|
||||||
<span class="header-icon" aria-hidden="true"><i class="bwi bwi-angle-left"></i></span>
|
|
||||||
<span>{{ "back" | i18n }}</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<h1 class="center">
|
|
||||||
<span class="title">{{ "exportVault" | i18n }}</span>
|
|
||||||
</h1>
|
|
||||||
<div class="right">
|
|
||||||
<button type="submit" [disabled]="!exportForm.enabled">
|
|
||||||
{{ "submit" | i18n }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
<main tabindex="-1">
|
|
||||||
<app-callout type="warning" title="{{ 'vaultExportDisabled' | i18n }}" *ngIf="disabledByPolicy">
|
|
||||||
{{ "personalVaultExportPolicyInEffect" | i18n }}
|
|
||||||
</app-callout>
|
|
||||||
<tools-export-scope-callout *ngIf="!disabledByPolicy"></tools-export-scope-callout>
|
|
||||||
|
|
||||||
<div class="box">
|
|
||||||
<div class="box-content">
|
|
||||||
<div class="box-content-row" appBoxRow>
|
|
||||||
<label for="format">{{ "fileFormat" | i18n }}</label>
|
|
||||||
<select id="format" name="Format" formControlName="format">
|
|
||||||
<option *ngFor="let f of formatOptions" [value]="f.value">{{ f.name }}</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</main>
|
|
||||||
</form>
|
|
|
@ -1,54 +0,0 @@
|
||||||
import { Component } from "@angular/core";
|
|
||||||
import { UntypedFormBuilder } from "@angular/forms";
|
|
||||||
import { Router } from "@angular/router";
|
|
||||||
|
|
||||||
import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service";
|
|
||||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
|
||||||
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
|
||||||
import { FileDownloadService } from "@bitwarden/common/platform/abstractions/file-download/file-download.service";
|
|
||||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
|
||||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
|
||||||
import { DialogService } from "@bitwarden/components";
|
|
||||||
import { VaultExportServiceAbstraction } from "@bitwarden/vault-export-core";
|
|
||||||
import { ExportComponent as BaseExportComponent } from "@bitwarden/vault-export-ui";
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: "app-export",
|
|
||||||
templateUrl: "export.component.html",
|
|
||||||
})
|
|
||||||
export class ExportComponent extends BaseExportComponent {
|
|
||||||
constructor(
|
|
||||||
i18nService: I18nService,
|
|
||||||
platformUtilsService: PlatformUtilsService,
|
|
||||||
exportService: VaultExportServiceAbstraction,
|
|
||||||
eventCollectionService: EventCollectionService,
|
|
||||||
policyService: PolicyService,
|
|
||||||
private router: Router,
|
|
||||||
logService: LogService,
|
|
||||||
formBuilder: UntypedFormBuilder,
|
|
||||||
fileDownloadService: FileDownloadService,
|
|
||||||
dialogService: DialogService,
|
|
||||||
organizationService: OrganizationService,
|
|
||||||
) {
|
|
||||||
super(
|
|
||||||
i18nService,
|
|
||||||
platformUtilsService,
|
|
||||||
exportService,
|
|
||||||
eventCollectionService,
|
|
||||||
policyService,
|
|
||||||
logService,
|
|
||||||
formBuilder,
|
|
||||||
fileDownloadService,
|
|
||||||
dialogService,
|
|
||||||
organizationService,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected saved() {
|
|
||||||
super.saved();
|
|
||||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
||||||
this.router.navigate(["/tabs/settings"]);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
<header>
|
||||||
|
<div class="left">
|
||||||
|
<button type="button" routerLink="/vault-settings">
|
||||||
|
<span class="header-icon" aria-hidden="true"><i class="bwi bwi-angle-left"></i></span>
|
||||||
|
<span>{{ "back" | i18n }}</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<h1 class="center">
|
||||||
|
<span class="title">{{ "exportVault" | i18n }}</span>
|
||||||
|
</h1>
|
||||||
|
<div class="right">
|
||||||
|
<button form="export_form_exportForm" type="submit" [disabled]="disabled">
|
||||||
|
<span [hidden]="loading">{{ "submit" | i18n }}</span>
|
||||||
|
<i class="bwi bwi-spinner bwi-lg bwi-spin" [hidden]="!loading" aria-hidden="true"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<main tabindex="-1">
|
||||||
|
<div class="tw-p-4">
|
||||||
|
<tools-export
|
||||||
|
(formDisabled)="this.disabled = $event"
|
||||||
|
(formLoading)="this.loading = $event"
|
||||||
|
(onSuccessfulExport)="this.onSuccessfulExport($event)"
|
||||||
|
></tools-export>
|
||||||
|
</div>
|
||||||
|
</main>
|
|
@ -0,0 +1,40 @@
|
||||||
|
import { CommonModule } from "@angular/common";
|
||||||
|
import { Component } from "@angular/core";
|
||||||
|
import { Router, RouterLink } from "@angular/router";
|
||||||
|
|
||||||
|
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||||
|
import { AsyncActionsModule, ButtonModule, DialogModule } from "@bitwarden/components";
|
||||||
|
import { ExportComponent } from "@bitwarden/vault-export-ui";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
templateUrl: "export-browser.component.html",
|
||||||
|
standalone: true,
|
||||||
|
imports: [
|
||||||
|
CommonModule,
|
||||||
|
RouterLink,
|
||||||
|
JslibModule,
|
||||||
|
DialogModule,
|
||||||
|
AsyncActionsModule,
|
||||||
|
ButtonModule,
|
||||||
|
ExportComponent,
|
||||||
|
],
|
||||||
|
})
|
||||||
|
export class ExportBrowserComponent {
|
||||||
|
/**
|
||||||
|
* Used to control the disabled state of the Submit button
|
||||||
|
* Gets set indirectly by the disabled state being emitted from the sub-form when thier form gets disabled or the submit button is clicked
|
||||||
|
*/
|
||||||
|
protected disabled = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to control the disabled state of the Submit button
|
||||||
|
* Gets set indirectly by the loading state being emitted from the sub-form when their form is loading or finished loading
|
||||||
|
*/
|
||||||
|
protected loading = false;
|
||||||
|
|
||||||
|
constructor(private router: Router) {}
|
||||||
|
|
||||||
|
protected async onSuccessfulExport(organizationId: string): Promise<void> {
|
||||||
|
await this.router.navigate(["/vault-settings"]);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue