mirror of
https://github.com/bitwarden/browser
synced 2025-12-15 15:53:27 +00:00
[AC-1492] Split export service (#7462)
* Split export service into vault and org export service * Changed CLI logic to use split export logic * correct unit tests * Created individual export service, export service making the calls for org and ind vault * Improved code readability * Merged PasswordProtectedExport with Export methods to simplify calls * Some small refactor * [AC-1492] Managed collections export (#7556) * Added managed collections export method Added logic to show orgs on export that the user can export from * Merge branch 'tools/AC-1492/split-export-services' into tools/AC-1492/export-flexible-collections # Conflicts: # apps/web/src/app/admin-console/organizations/tools/vault-export/org-vault-export.component.ts # apps/web/src/app/tools/vault-export/export.component.ts * Change export to use new organization.flexiblecollection flag * Little refactor changing parameter names and reduzing the size of export.component.ts ngOnInit * Removed unused service from export constructor and removed unnecessary default value from org export service parameter * Simplified organizations selection for vault export to only verify if it has flexiblecollections * removed unecessary services from ExportComponent constructor on popup * Fixed possible race condition on managed export
This commit is contained in:
@@ -123,6 +123,10 @@ import { SyncNotifierService } from "@bitwarden/common/vault/services/sync/sync-
|
||||
import { SyncService } from "@bitwarden/common/vault/services/sync/sync.service";
|
||||
import { TotpService } from "@bitwarden/common/vault/services/totp.service";
|
||||
import {
|
||||
IndividualVaultExportService,
|
||||
IndividualVaultExportServiceAbstraction,
|
||||
OrganizationVaultExportService,
|
||||
OrganizationVaultExportServiceAbstraction,
|
||||
VaultExportService,
|
||||
VaultExportServiceAbstraction,
|
||||
} from "@bitwarden/exporter/vault-export";
|
||||
@@ -253,6 +257,8 @@ export default class MainBackground {
|
||||
derivedStateProvider: DerivedStateProvider;
|
||||
stateProvider: StateProvider;
|
||||
fido2Service: Fido2ServiceAbstraction;
|
||||
individualVaultExportService: IndividualVaultExportServiceAbstraction;
|
||||
organizationVaultExportService: OrganizationVaultExportServiceAbstraction;
|
||||
|
||||
// Passed to the popup for Safari to workaround issues with theming, downloading, etc.
|
||||
backgroundWindow = window;
|
||||
@@ -635,14 +641,28 @@ export default class MainBackground {
|
||||
this.cryptoService,
|
||||
);
|
||||
|
||||
this.exportService = new VaultExportService(
|
||||
this.individualVaultExportService = new IndividualVaultExportService(
|
||||
this.folderService,
|
||||
this.cipherService,
|
||||
this.cryptoService,
|
||||
this.cryptoFunctionService,
|
||||
this.stateService,
|
||||
);
|
||||
|
||||
this.organizationVaultExportService = new OrganizationVaultExportService(
|
||||
this.cipherService,
|
||||
this.apiService,
|
||||
this.cryptoService,
|
||||
this.cryptoFunctionService,
|
||||
this.stateService,
|
||||
this.collectionService,
|
||||
);
|
||||
|
||||
this.exportService = new VaultExportService(
|
||||
this.individualVaultExportService,
|
||||
this.organizationVaultExportService,
|
||||
);
|
||||
|
||||
this.notificationsService = new NotificationsService(
|
||||
this.logService,
|
||||
this.syncService,
|
||||
|
||||
@@ -88,6 +88,10 @@ import { SyncNotifierService } from "@bitwarden/common/vault/services/sync/sync-
|
||||
import { SyncService } from "@bitwarden/common/vault/services/sync/sync.service";
|
||||
import { TotpService } from "@bitwarden/common/vault/services/totp.service";
|
||||
import {
|
||||
IndividualVaultExportService,
|
||||
IndividualVaultExportServiceAbstraction,
|
||||
OrganizationVaultExportService,
|
||||
OrganizationVaultExportServiceAbstraction,
|
||||
VaultExportService,
|
||||
VaultExportServiceAbstraction,
|
||||
} from "@bitwarden/exporter/vault-export";
|
||||
@@ -146,6 +150,8 @@ export class Main {
|
||||
importService: ImportServiceAbstraction;
|
||||
importApiService: ImportApiServiceAbstraction;
|
||||
exportService: VaultExportServiceAbstraction;
|
||||
individualExportService: IndividualVaultExportServiceAbstraction;
|
||||
organizationExportService: OrganizationVaultExportServiceAbstraction;
|
||||
searchService: SearchService;
|
||||
cryptoFunctionService: NodeCryptoFunctionService;
|
||||
encryptService: EncryptServiceImplementation;
|
||||
@@ -509,13 +515,27 @@ export class Main {
|
||||
this.collectionService,
|
||||
this.cryptoService,
|
||||
);
|
||||
this.exportService = new VaultExportService(
|
||||
|
||||
this.individualExportService = new IndividualVaultExportService(
|
||||
this.folderService,
|
||||
this.cipherService,
|
||||
this.cryptoService,
|
||||
this.cryptoFunctionService,
|
||||
this.stateService,
|
||||
);
|
||||
|
||||
this.organizationExportService = new OrganizationVaultExportService(
|
||||
this.cipherService,
|
||||
this.apiService,
|
||||
this.cryptoService,
|
||||
this.cryptoFunctionService,
|
||||
this.stateService,
|
||||
this.collectionService,
|
||||
);
|
||||
|
||||
this.exportService = new VaultExportService(
|
||||
this.individualExportService,
|
||||
this.organizationExportService,
|
||||
);
|
||||
|
||||
this.auditService = new AuditService(this.cryptoFunctionService, this.apiService);
|
||||
|
||||
@@ -32,7 +32,14 @@ export class ExportCommand {
|
||||
);
|
||||
}
|
||||
|
||||
const format = options.format ?? "csv";
|
||||
let password = options.password;
|
||||
|
||||
// has password and format is 'json' => should have the same behaviour as 'encrypted_json'
|
||||
// format is 'undefined' => Defaults to 'csv'
|
||||
// Any other case => returns the options.format
|
||||
const format =
|
||||
password && options.format == "json" ? "encrypted_json" : options.format ?? "csv";
|
||||
|
||||
if (!this.isSupportedExportFormat(format)) {
|
||||
return Response.badRequest(
|
||||
`'${format}' is not a supported export format. Supported formats: ${EXPORT_FORMATS.join(
|
||||
@@ -47,10 +54,18 @@ export class ExportCommand {
|
||||
|
||||
let exportContent: string = null;
|
||||
try {
|
||||
if (format === "encrypted_json") {
|
||||
password = await this.promptPassword(password);
|
||||
}
|
||||
|
||||
exportContent =
|
||||
format === "encrypted_json"
|
||||
? await this.getProtectedExport(options.password, options.organizationid)
|
||||
: await this.getUnprotectedExport(format, options.organizationid);
|
||||
options.organizationid == null
|
||||
? await this.exportService.getExport(format, password)
|
||||
: await this.exportService.getOrganizationExport(
|
||||
options.organizationid,
|
||||
format,
|
||||
password,
|
||||
);
|
||||
|
||||
const eventType = options.organizationid
|
||||
? EventType.Organization_ClientExportedVault
|
||||
@@ -62,17 +77,6 @@ export class ExportCommand {
|
||||
return await this.saveFile(exportContent, options, format);
|
||||
}
|
||||
|
||||
private async getProtectedExport(passwordOption: string | boolean, organizationId?: string) {
|
||||
const password = await this.promptPassword(passwordOption);
|
||||
return password == null
|
||||
? await this.exportService.getExport("encrypted_json", organizationId)
|
||||
: await this.exportService.getPasswordProtectedExport(password, organizationId);
|
||||
}
|
||||
|
||||
private async getUnprotectedExport(format: ExportFormat, organizationId?: string) {
|
||||
return this.exportService.getExport(format, organizationId);
|
||||
}
|
||||
|
||||
private async saveFile(
|
||||
exportContent: string,
|
||||
options: program.OptionValues,
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { Component } from "@angular/core";
|
||||
import { UntypedFormBuilder } from "@angular/forms";
|
||||
import { ActivatedRoute } from "@angular/router";
|
||||
import { map, switchMap } from "rxjs";
|
||||
|
||||
import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
@@ -62,20 +61,15 @@ export class OrganizationVaultExportComponent extends ExportComponent {
|
||||
this.organizationId = params.organizationId;
|
||||
});
|
||||
|
||||
this.flexibleCollectionsEnabled$ = this.route.parent.parent.params.pipe(
|
||||
switchMap((params) => this.organizationService.get$(params.organizationId)),
|
||||
map((organization) => organization.flexibleCollections),
|
||||
);
|
||||
|
||||
await super.ngOnInit();
|
||||
}
|
||||
|
||||
getExportData() {
|
||||
if (this.isFileEncryptedExport) {
|
||||
return this.exportService.getPasswordProtectedExport(this.filePassword, this.organizationId);
|
||||
} else {
|
||||
return this.exportService.getOrganizationExport(this.organizationId, this.format);
|
||||
}
|
||||
return this.exportService.getOrganizationExport(
|
||||
this.organizationId,
|
||||
this.format,
|
||||
this.filePassword,
|
||||
);
|
||||
}
|
||||
|
||||
getFileName() {
|
||||
|
||||
@@ -15,18 +15,20 @@
|
||||
*ngIf="!disabledByPolicy"
|
||||
></app-export-scope-callout>
|
||||
|
||||
<bit-form-field *ngIf="flexibleCollectionsEnabled$ | async">
|
||||
<bit-label>{{ "exportFrom" | i18n }}</bit-label>
|
||||
<bit-select formControlName="vaultSelector">
|
||||
<bit-option [label]="'myVault' | i18n" value="myVault" icon="bwi-user" />
|
||||
<bit-option
|
||||
*ngFor="let o of organizations$ | async"
|
||||
[value]="o.id"
|
||||
[label]="o.name"
|
||||
icon="bwi-business"
|
||||
/>
|
||||
</bit-select>
|
||||
</bit-form-field>
|
||||
<ng-container *ngIf="organizations$ | async as organizations">
|
||||
<bit-form-field *ngIf="organizations.length > 0">
|
||||
<bit-label>{{ "exportFrom" | i18n }}</bit-label>
|
||||
<bit-select formControlName="vaultSelector">
|
||||
<bit-option [label]="'myVault' | i18n" value="myVault" icon="bwi-user" />
|
||||
<bit-option
|
||||
*ngFor="let o of organizations$ | async"
|
||||
[value]="o.id"
|
||||
[label]="o.name"
|
||||
icon="bwi-business"
|
||||
/>
|
||||
</bit-select>
|
||||
</bit-form-field>
|
||||
</ng-container>
|
||||
|
||||
<bit-form-field>
|
||||
<bit-label>{{ "fileFormat" | i18n }}</bit-label>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Component } from "@angular/core";
|
||||
import { UntypedFormBuilder } from "@angular/forms";
|
||||
import { Observable, firstValueFrom } from "rxjs";
|
||||
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";
|
||||
@@ -25,9 +25,6 @@ export class ExportComponent extends BaseExportComponent {
|
||||
encryptedExportType = EncryptedExportType;
|
||||
protected showFilePassword: boolean;
|
||||
|
||||
// Used in the OrganizationVaultExport subclass
|
||||
protected flexibleCollectionsEnabled$ = new Observable<boolean>();
|
||||
|
||||
constructor(
|
||||
i18nService: I18nService,
|
||||
platformUtilsService: PlatformUtilsService,
|
||||
|
||||
Reference in New Issue
Block a user