diff --git a/apps/browser/src/tools/popup/settings/export.component.ts b/apps/browser/src/tools/popup/settings/export.component.ts index 7c0a294ec5..b45e99a59b 100644 --- a/apps/browser/src/tools/popup/settings/export.component.ts +++ b/apps/browser/src/tools/popup/settings/export.component.ts @@ -4,9 +4,9 @@ import { Router } from "@angular/router"; import { ExportComponent as BaseExportComponent } from "@bitwarden/angular/tools/export/components/export.component"; 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 { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction"; -import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; 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"; @@ -20,7 +20,6 @@ import { VaultExportServiceAbstraction } from "@bitwarden/exporter/vault-export" }) export class ExportComponent extends BaseExportComponent { constructor( - cryptoService: CryptoService, i18nService: I18nService, platformUtilsService: PlatformUtilsService, exportService: VaultExportServiceAbstraction, @@ -32,20 +31,20 @@ export class ExportComponent extends BaseExportComponent { formBuilder: UntypedFormBuilder, fileDownloadService: FileDownloadService, dialogService: DialogService, + organizationService: OrganizationService, ) { super( - cryptoService, i18nService, platformUtilsService, exportService, eventCollectionService, policyService, - window, logService, userVerificationService, formBuilder, fileDownloadService, dialogService, + organizationService, ); } diff --git a/apps/desktop/src/app/tools/export/export.component.ts b/apps/desktop/src/app/tools/export/export.component.ts index 4f87a9f149..b44453cb57 100644 --- a/apps/desktop/src/app/tools/export/export.component.ts +++ b/apps/desktop/src/app/tools/export/export.component.ts @@ -3,10 +3,9 @@ import { UntypedFormBuilder } from "@angular/forms"; import { ExportComponent as BaseExportComponent } from "@bitwarden/angular/tools/export/components/export.component"; 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 { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction"; -import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.service"; -import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; 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"; @@ -14,15 +13,12 @@ import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/pl import { DialogService } from "@bitwarden/components"; import { VaultExportServiceAbstraction } from "@bitwarden/exporter/vault-export"; -const BroadcasterSubscriptionId = "ExportComponent"; - @Component({ selector: "app-export", templateUrl: "export.component.html", }) export class ExportComponent extends BaseExportComponent implements OnInit { constructor( - cryptoService: CryptoService, i18nService: I18nService, platformUtilsService: PlatformUtilsService, exportService: VaultExportServiceAbstraction, @@ -30,28 +26,23 @@ export class ExportComponent extends BaseExportComponent implements OnInit { policyService: PolicyService, userVerificationService: UserVerificationService, formBuilder: UntypedFormBuilder, - private broadcasterService: BroadcasterService, logService: LogService, fileDownloadService: FileDownloadService, dialogService: DialogService, + organizationService: OrganizationService, ) { super( - cryptoService, i18nService, platformUtilsService, exportService, eventCollectionService, policyService, - window, logService, userVerificationService, formBuilder, fileDownloadService, dialogService, + organizationService, ); } - - ngOnDestroy() { - this.broadcasterService.unsubscribe(BroadcasterSubscriptionId); - } } diff --git a/apps/web/src/app/admin-console/organizations/tools/vault-export/org-vault-export.component.ts b/apps/web/src/app/admin-console/organizations/tools/vault-export/org-vault-export.component.ts index 7ffd4c3c1d..a10c7253a6 100644 --- a/apps/web/src/app/admin-console/organizations/tools/vault-export/org-vault-export.component.ts +++ b/apps/web/src/app/admin-console/organizations/tools/vault-export/org-vault-export.component.ts @@ -3,10 +3,11 @@ import { UntypedFormBuilder } from "@angular/forms"; import { ActivatedRoute } 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 { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction"; import { EventType } from "@bitwarden/common/enums"; -import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; +import { ConfigServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config.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"; @@ -23,7 +24,6 @@ import { ExportComponent } from "../../../../tools/vault-export/export.component // eslint-disable-next-line rxjs-angular/prefer-takeuntil export class OrganizationVaultExportComponent extends ExportComponent { constructor( - cryptoService: CryptoService, i18nService: I18nService, platformUtilsService: PlatformUtilsService, exportService: VaultExportServiceAbstraction, @@ -35,9 +35,10 @@ export class OrganizationVaultExportComponent extends ExportComponent { formBuilder: UntypedFormBuilder, fileDownloadService: FileDownloadService, dialogService: DialogService, + organizationService: OrganizationService, + configService: ConfigServiceAbstraction, ) { super( - cryptoService, i18nService, platformUtilsService, exportService, @@ -48,6 +49,8 @@ export class OrganizationVaultExportComponent extends ExportComponent { formBuilder, fileDownloadService, dialogService, + organizationService, + configService, ); } diff --git a/apps/web/src/app/tools/vault-export/export.component.html b/apps/web/src/app/tools/vault-export/export.component.html index 9d885ba398..7e68becfd2 100644 --- a/apps/web/src/app/tools/vault-export/export.component.html +++ b/apps/web/src/app/tools/vault-export/export.component.html @@ -1,5 +1,3 @@ - -
- +

{{ "exportVault" | i18n }}

- + {{ "personalVaultExportPolicyInEffect" | i18n }} - + -
-
- - {{ "fileFormat" | i18n }} - - -
-
-
-
- -
- + + {{ "exportFrom" | i18n }} + + + + + -
-
- -
-
- -
-
+ + {{ "fileFormat" | i18n }} + + + + -
- {{ "accountRestrictedOptionDescription" | i18n }} -
+ + + {{ "exportTypeHeading" | i18n }} -
-
- -
-
- -
-
- -
- {{ "passwordProtectedOptionDescription" | i18n }} -
-
-
- - -
- - {{ "filePassword" | i18n }} - - - {{ "exportPasswordDescription" | i18n }} - - - -
- - - {{ "confirmFilePassword" | i18n }} - - - -
-
- - -
-
+ {{ "accountRestricted" | i18n }} + {{ "accountRestrictedOptionDescription" | i18n }} + + + + {{ "passwordProtected" | i18n }} + {{ "passwordProtectedOptionDescription" | i18n }} + + + + +
+ + {{ "filePassword" | i18n }} + + + {{ "exportPasswordDescription" | i18n }} + + +
+ + {{ "confirmFilePassword" | i18n }} + + + +
+ + +
diff --git a/apps/web/src/app/tools/vault-export/export.component.ts b/apps/web/src/app/tools/vault-export/export.component.ts index ae0acfad20..138a190da3 100644 --- a/apps/web/src/app/tools/vault-export/export.component.ts +++ b/apps/web/src/app/tools/vault-export/export.component.ts @@ -4,9 +4,11 @@ import { firstValueFrom } from "rxjs"; import { ExportComponent as BaseExportComponent } from "@bitwarden/angular/tools/export/components/export.component"; 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 { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction"; -import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; +import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; +import { ConfigServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config.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"; @@ -22,12 +24,15 @@ import { openUserVerificationPrompt } from "../../auth/shared/components/user-ve templateUrl: "export.component.html", }) export class ExportComponent extends BaseExportComponent { - organizationId: string; encryptedExportType = EncryptedExportType; protected showFilePassword: boolean; + protected flexibleCollectionsEnabled$ = this.configService.getFeatureFlag$( + FeatureFlag.FlexibleCollections, + false, + ); + constructor( - cryptoService: CryptoService, i18nService: I18nService, platformUtilsService: PlatformUtilsService, exportService: VaultExportServiceAbstraction, @@ -38,20 +43,21 @@ export class ExportComponent extends BaseExportComponent { formBuilder: UntypedFormBuilder, fileDownloadService: FileDownloadService, dialogService: DialogService, + organizationService: OrganizationService, + protected configService: ConfigServiceAbstraction, ) { super( - cryptoService, i18nService, platformUtilsService, exportService, eventCollectionService, policyService, - window, logService, userVerificationService, formBuilder, fileDownloadService, dialogService, + organizationService, ); } diff --git a/apps/web/src/locales/en/messages.json b/apps/web/src/locales/en/messages.json index 4b423bd955..f21f0ab985 100644 --- a/apps/web/src/locales/en/messages.json +++ b/apps/web/src/locales/en/messages.json @@ -1074,6 +1074,9 @@ "export": { "message": "Export" }, + "exportFrom": { + "message": "Export from" + }, "exportVault": { "message": "Export vault" }, diff --git a/libs/angular/src/tools/export/components/export-scope-callout.component.ts b/libs/angular/src/tools/export/components/export-scope-callout.component.ts index cf15b10134..1653f8013b 100644 --- a/libs/angular/src/tools/export/components/export-scope-callout.component.ts +++ b/libs/angular/src/tools/export/components/export-scope-callout.component.ts @@ -8,8 +8,6 @@ import { StateService } from "@bitwarden/common/platform/abstractions/state.serv templateUrl: "export-scope-callout.component.html", }) export class ExportScopeCalloutComponent implements OnInit { - @Input() organizationId: string = null; - show = false; scopeConfig: { title: string; @@ -17,6 +15,17 @@ export class ExportScopeCalloutComponent implements OnInit { scopeIdentifier: string; }; + private _organizationId: string; + + get organizationId(): string { + return this._organizationId; + } + + @Input() set organizationId(value: string) { + this._organizationId = value; + this.getScopeMessage(this._organizationId); + } + constructor( protected organizationService: OrganizationService, protected stateService: StateService, @@ -26,18 +35,23 @@ export class ExportScopeCalloutComponent implements OnInit { if (!this.organizationService.hasOrganizations()) { return; } + + await this.getScopeMessage(this.organizationId); + this.show = true; + } + + private async getScopeMessage(organizationId: string) { this.scopeConfig = - this.organizationId != null + organizationId != null ? { title: "exportingOrganizationVaultTitle", description: "exportingOrganizationVaultDesc", - scopeIdentifier: this.organizationService.get(this.organizationId).name, + scopeIdentifier: this.organizationService.get(organizationId).name, } : { title: "exportingPersonalVaultTitle", description: "exportingIndividualVaultDescription", scopeIdentifier: await this.stateService.getEmail(), }; - this.show = true; } } diff --git a/libs/angular/src/tools/export/components/export.component.ts b/libs/angular/src/tools/export/components/export.component.ts index 78d0f605e1..b24759c821 100644 --- a/libs/angular/src/tools/export/components/export.component.ts +++ b/libs/angular/src/tools/export/components/export.component.ts @@ -1,17 +1,22 @@ import { Directive, EventEmitter, OnDestroy, OnInit, Output, ViewChild } from "@angular/core"; import { UntypedFormBuilder, Validators } from "@angular/forms"; -import { merge, startWith, Subject, takeUntil } from "rxjs"; +import { concat, map, merge, Observable, startWith, Subject, takeUntil } from "rxjs"; import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service"; +import { + OrganizationService, + canAccessImportExport, +} from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { PolicyType } from "@bitwarden/common/admin-console/enums"; +import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction"; import { EventType } from "@bitwarden/common/enums"; -import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; 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 { Utils } from "@bitwarden/common/platform/misc/utils"; import { EncryptedExportType } from "@bitwarden/common/tools/enums/encrypted-export-type.enum"; import { DialogService } from "@bitwarden/components"; import { VaultExportServiceAbstraction } from "@bitwarden/exporter/vault-export"; @@ -26,13 +31,22 @@ export class ExportComponent implements OnInit, OnDestroy { filePasswordValue: string = null; formPromise: Promise; private _disabledByPolicy = false; + protected organizationId: string = null; + organizations$: Observable; protected get disabledByPolicy(): boolean { return this._disabledByPolicy; } exportForm = this.formBuilder.group({ - format: ["json"], + vaultSelector: [ + "myVault", + { + nonNullable: true, + validators: [Validators.required], + }, + ], + format: ["json", Validators.required], secret: [""], filePassword: ["", Validators.required], confirmFilePassword: ["", Validators.required], @@ -48,21 +62,27 @@ export class ExportComponent implements OnInit, OnDestroy { private destroy$ = new Subject(); constructor( - protected cryptoService: CryptoService, protected i18nService: I18nService, protected platformUtilsService: PlatformUtilsService, protected exportService: VaultExportServiceAbstraction, protected eventCollectionService: EventCollectionService, private policyService: PolicyService, - protected win: Window, private logService: LogService, private userVerificationService: UserVerificationService, private formBuilder: UntypedFormBuilder, protected fileDownloadService: FileDownloadService, protected dialogService: DialogService, + protected organizationService: OrganizationService, ) {} async ngOnInit() { + this.organizations$ = concat( + this.organizationService.memberOrganizations$.pipe( + canAccessImportExport(this.i18nService), + map((orgs) => orgs.sort(Utils.getSortFunction(this.i18nService, "name"))), + ), + ); + this.policyService .policyAppliesToActiveUser$(PolicyType.DisablePersonalVaultExport) .pipe(takeUntil(this.destroy$)) @@ -73,6 +93,19 @@ export class ExportComponent implements OnInit, OnDestroy { } }); + if (this.organizationId) { + this.exportForm.controls.vaultSelector.patchValue(this.organizationId); + this.exportForm.controls.vaultSelector.disable(); + } else { + this.exportForm.controls.vaultSelector.valueChanges + .pipe(takeUntil(this.destroy$)) + .subscribe((value) => { + this.organizationId = value != "myVault" ? value : undefined; + }); + + this.exportForm.controls.vaultSelector.setValue("myVault"); + } + merge( this.exportForm.get("format").valueChanges, this.exportForm.get("fileEncryptionType").valueChanges,