From 192bb5a7b3cb430ba42238543738cc7ec9c969f9 Mon Sep 17 00:00:00 2001 From: Daniel James Smith Date: Wed, 19 Apr 2023 11:30:46 +0200 Subject: [PATCH] [PM-328] Move exporter to tools (#5070) * Create and register new libs/exporter Create package.json Create tsconfig Create jest.config Extend shared and root tsconfig and jest.configs Register with eslint * Migrate exportService to libs/exporter Move exportService (abstraction and impl) into libs/exporter Refactored exportService to be split into vault-export and event-export Created barrel-files for both exports Moved export.service.spec.ts into vault-export Created an export-helper, which helps build the filename (extract method refactor from ExportService) * Move components in libs/angular into tools-subfolder Moved components Updated imports in jslib-services.module and jslib.module * Register libs/exporter with browser and fix imports Move export.component into tools-subfolder * Register libs/exporter with cli and fix imports Move export.command into tools-subfolder * Register libs/exporter with desktop and fix imports Move export.component into tools-subfolder * Move export models to libs/exporter * Update web imports * Update package-lock.json * Move export models back as it would create circular dependency Reponse models in common rely on export models which are in libs/exporter, which relies on common * Fix up web for event-export * Update CODEOWNERS * Add export-models to team-tools-dev * Simplify domain import * Moving EventExport into web --- .eslintrc.json | 10 ++ .github/CODEOWNERS | 4 +- .../browser/src/background/main.background.ts | 10 +- apps/browser/src/popup/app-routing.module.ts | 2 +- apps/browser/src/popup/app.module.ts | 2 +- .../src/popup/services/services.module.ts | 8 +- .../popup/settings/export.component.html | 0 .../popup/settings/export.component.ts | 6 +- apps/browser/tsconfig.json | 3 +- apps/cli/src/bw.ts | 9 +- .../src/{commands => tools}/export.command.ts | 15 +-- apps/cli/src/vault.program.ts | 2 +- apps/cli/src/vault/models/folder.response.ts | 2 +- apps/cli/tsconfig.json | 1 + apps/desktop/src/app/app.component.ts | 2 +- apps/desktop/src/app/app.module.ts | 2 +- .../export}/export.component.html | 0 .../export}/export.component.ts | 6 +- apps/desktop/tsconfig.json | 3 +- .../organizations/manage/events.component.ts | 4 +- .../import-export/org-export.component.ts | 4 +- .../src/app/common/base.events.component.ts | 4 +- .../event-export/event-export.service.ts | 20 ++++ .../app/tools/event-export}/event.export.ts | 4 +- apps/web/src/app/tools/event-export/index.ts | 1 + .../tools/import-export/export.component.ts | 6 +- apps/web/tsconfig.json | 3 +- .../providers/manage/events.component.ts | 4 +- bitwarden_license/bit-web/tsconfig.json | 3 +- jest.config.js | 1 + libs/angular/src/jslib.module.ts | 2 +- .../src/services/jslib-services.module.ts | 10 +- .../export-scope-callout.component.html | 0 .../export-scope-callout.component.ts | 0 .../export}/components/export.component.ts | 4 +- libs/common/src/models/export/index.ts | 11 ++ libs/exporter/jest.config.js | 14 +++ libs/exporter/package.json | 23 ++++ libs/exporter/src/export-helper.ts | 24 +++++ .../bitwarden-password-protected-types.ts | 0 libs/exporter/src/vault-export/index.ts | 2 + .../vault-export.service.abstraction.ts} | 6 +- .../services/vault-export.service.spec.ts} | 17 +-- .../services/vault-export.service.ts} | 100 +++++++----------- libs/exporter/tsconfig.json | 5 + libs/exporter/tsconfig.spec.json | 3 + libs/importer/package.json | 3 +- .../bitwarden/bitwarden-json-importer.ts | 8 +- .../bitwarden-password-protected-importer.ts | 2 +- libs/shared/tsconfig.libs.json | 3 +- package-lock.json | 17 +++ tsconfig.eslint.json | 3 +- tsconfig.json | 1 + 53 files changed, 266 insertions(+), 133 deletions(-) rename apps/browser/src/{ => tools}/popup/settings/export.component.html (100%) rename apps/browser/src/{ => tools}/popup/settings/export.component.ts (91%) rename apps/cli/src/{commands => tools}/export.command.ts (94%) rename apps/desktop/src/app/{vault => tools/export}/export.component.html (100%) rename apps/desktop/src/app/{vault => tools/export}/export.component.ts (93%) create mode 100644 apps/web/src/app/tools/event-export/event-export.service.ts rename {libs/common/src/models/export => apps/web/src/app/tools/event-export}/event.export.ts (83%) create mode 100644 apps/web/src/app/tools/event-export/index.ts rename libs/angular/src/{ => tools/export}/components/export-scope-callout.component.html (100%) rename libs/angular/src/{ => tools/export}/components/export-scope-callout.component.ts (100%) rename libs/angular/src/{ => tools/export}/components/export.component.ts (97%) create mode 100644 libs/common/src/models/export/index.ts create mode 100644 libs/exporter/jest.config.js create mode 100644 libs/exporter/package.json create mode 100644 libs/exporter/src/export-helper.ts rename libs/{importer/src/importers/bitwarden => exporter/src/vault-export}/bitwarden-password-protected-types.ts (100%) create mode 100644 libs/exporter/src/vault-export/index.ts rename libs/{common/src/abstractions/export.service.ts => exporter/src/vault-export/services/vault-export.service.abstraction.ts} (75%) rename libs/{common/spec/services/export.service.spec.ts => exporter/src/vault-export/services/vault-export.service.spec.ts} (95%) rename libs/{common/src/services/export.service.ts => exporter/src/vault-export/services/vault-export.service.ts} (77%) create mode 100644 libs/exporter/tsconfig.json create mode 100644 libs/exporter/tsconfig.spec.json diff --git a/.eslintrc.json b/.eslintrc.json index 39f292e530..5b431ff274 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -102,6 +102,10 @@ { "target": "./libs/common/**/*", "from": "./libs/importer/**/*" + }, + { + "target": "./libs/common/**/*", + "from": "./libs/exporter/**/*" } ] } @@ -160,6 +164,12 @@ "rules": { "no-restricted-imports": ["error", { "patterns": ["@bitwarden/importer/*", "src/**/*"] }] } + }, + { + "files": ["libs/exporter/src/**/*.ts"], + "rules": { + "no-restricted-imports": ["error", { "patterns": ["@bitwarden/exporter/*", "src/**/*"] }] + } } ] } diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 86b58baa2a..3537f96947 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -25,7 +25,9 @@ apps/cli/src/app/tools @bitwarden/team-tools-dev apps/desktop/src/app/tools @bitwarden/team-tools-dev apps/web/src/app/tools @bitwarden/team-tools-dev libs/angular/src/tools @bitwarden/team-tools-dev +libs/common/src/models/export @bitwarden/team-tools-dev libs/common/src/tools @bitwarden/team-tools-dev +libs/exporter @bitwarden/team-tools-dev libs/importer @bitwarden/team-tools-dev ## Vault team files ## @@ -49,4 +51,4 @@ libs/common/src/admin-console @bitwarden/team-admin-console-dev ## Billing team files ## apps/web/src/app/billing @bitwarden/team-billing-dev libs/angular/src/billing @bitwarden/team-billing-dev -libs/common/src/billing @bitwarden/team-billing-dev \ No newline at end of file +libs/common/src/billing @bitwarden/team-billing-dev diff --git a/apps/browser/src/background/main.background.ts b/apps/browser/src/background/main.background.ts index 612d16b557..0fe16cd0ab 100644 --- a/apps/browser/src/background/main.background.ts +++ b/apps/browser/src/background/main.background.ts @@ -7,7 +7,6 @@ import { CryptoFunctionService as CryptoFunctionServiceAbstraction } from "@bitw import { EncryptService } from "@bitwarden/common/abstractions/encrypt.service"; import { EventCollectionService as EventCollectionServiceAbstraction } from "@bitwarden/common/abstractions/event/event-collection.service"; import { EventUploadService as EventUploadServiceAbstraction } from "@bitwarden/common/abstractions/event/event-upload.service"; -import { ExportService as ExportServiceAbstraction } from "@bitwarden/common/abstractions/export.service"; import { FileUploadService as FileUploadServiceAbstraction } from "@bitwarden/common/abstractions/file-upload/file-upload.service"; import { I18nService as I18nServiceAbstraction } from "@bitwarden/common/abstractions/i18n.service"; import { LogService as LogServiceAbstraction } from "@bitwarden/common/abstractions/log.service"; @@ -56,7 +55,6 @@ import { EncryptServiceImplementation } from "@bitwarden/common/services/cryptog import { MultithreadEncryptServiceImplementation } from "@bitwarden/common/services/cryptography/multithread-encrypt.service.implementation"; import { EventCollectionService } from "@bitwarden/common/services/event/event-collection.service"; import { EventUploadService } from "@bitwarden/common/services/event/event-upload.service"; -import { ExportService } from "@bitwarden/common/services/export.service"; import { FileUploadService } from "@bitwarden/common/services/file-upload/file-upload.service"; import { MemoryStorageService } from "@bitwarden/common/services/memoryStorage.service"; import { NotificationsService } from "@bitwarden/common/services/notifications.service"; @@ -89,6 +87,10 @@ import { CipherFileUploadService } from "@bitwarden/common/vault/services/file-u import { FolderApiService } from "@bitwarden/common/vault/services/folder/folder-api.service"; import { SyncNotifierService } from "@bitwarden/common/vault/services/sync/sync-notifier.service"; import { SyncService } from "@bitwarden/common/vault/services/sync/sync.service"; +import { + VaultExportService, + VaultExportServiceAbstraction, +} from "@bitwarden/exporter/vault-export"; import { BrowserOrganizationService } from "../admin-console/services/browser-organization.service"; import { BrowserPolicyService } from "../admin-console/services/browser-policy.service"; @@ -155,7 +157,7 @@ export default class MainBackground { containerService: ContainerService; auditService: AuditServiceAbstraction; authService: AuthServiceAbstraction; - exportService: ExportServiceAbstraction; + exportService: VaultExportServiceAbstraction; searchService: SearchServiceAbstraction; notificationsService: NotificationsServiceAbstraction; stateService: StateServiceAbstraction; @@ -463,7 +465,7 @@ export default class MainBackground { this.settingsService ); this.auditService = new AuditService(this.cryptoFunctionService, this.apiService); - this.exportService = new ExportService( + this.exportService = new VaultExportService( this.folderService, this.cipherService, this.apiService, diff --git a/apps/browser/src/popup/app-routing.module.ts b/apps/browser/src/popup/app-routing.module.ts index be6b0c4328..2fd71557f5 100644 --- a/apps/browser/src/popup/app-routing.module.ts +++ b/apps/browser/src/popup/app-routing.module.ts @@ -23,6 +23,7 @@ import { PasswordGeneratorHistoryComponent } from "../tools/popup/generator/pass import { SendAddEditComponent } from "../tools/popup/send/send-add-edit.component"; import { SendGroupingsComponent } from "../tools/popup/send/send-groupings.component"; import { SendTypeComponent } from "../tools/popup/send/send-type.component"; +import { ExportComponent } from "../tools/popup/settings/export.component"; import { AddEditComponent } from "../vault/popup/components/vault/add-edit.component"; import { AttachmentsComponent } from "../vault/popup/components/vault/attachments.component"; import { CollectionsComponent } from "../vault/popup/components/vault/collections.component"; @@ -36,7 +37,6 @@ import { ViewComponent } from "../vault/popup/components/vault/view.component"; import { DebounceNavigationService } from "./services/debounceNavigationService"; import { AutofillComponent } from "./settings/autofill.component"; import { ExcludedDomainsComponent } from "./settings/excluded-domains.component"; -import { ExportComponent } from "./settings/export.component"; import { FolderAddEditComponent } from "./settings/folder-add-edit.component"; import { FoldersComponent } from "./settings/folders.component"; import { HelpAndFeedbackComponent } from "./settings/help-and-feedback.component"; diff --git a/apps/browser/src/popup/app.module.ts b/apps/browser/src/popup/app.module.ts index c23d785d28..b809a63a58 100644 --- a/apps/browser/src/popup/app.module.ts +++ b/apps/browser/src/popup/app.module.ts @@ -39,6 +39,7 @@ import { EffluxDatesComponent as SendEffluxDatesComponent } from "../tools/popup import { SendAddEditComponent } from "../tools/popup/send/send-add-edit.component"; import { SendGroupingsComponent } from "../tools/popup/send/send-groupings.component"; import { SendTypeComponent } from "../tools/popup/send/send-type.component"; +import { ExportComponent } from "../tools/popup/settings/export.component"; import { ActionButtonsComponent } from "../vault/popup/components/action-buttons.component"; import { CipherRowComponent } from "../vault/popup/components/cipher-row.component"; import { PasswordRepromptComponent } from "../vault/popup/components/password-reprompt.component"; @@ -65,7 +66,6 @@ import { ServicesModule } from "./services/services.module"; import { AboutComponent } from "./settings/about.component"; import { AutofillComponent } from "./settings/autofill.component"; import { ExcludedDomainsComponent } from "./settings/excluded-domains.component"; -import { ExportComponent } from "./settings/export.component"; import { FolderAddEditComponent } from "./settings/folder-add-edit.component"; import { FoldersComponent } from "./settings/folders.component"; import { HelpAndFeedbackComponent } from "./settings/help-and-feedback.component"; diff --git a/apps/browser/src/popup/services/services.module.ts b/apps/browser/src/popup/services/services.module.ts index 044ebaa943..2103a014a3 100644 --- a/apps/browser/src/popup/services/services.module.ts +++ b/apps/browser/src/popup/services/services.module.ts @@ -17,7 +17,6 @@ import { EncryptService } from "@bitwarden/common/abstractions/encrypt.service"; import { EnvironmentService } from "@bitwarden/common/abstractions/environment.service"; import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service"; import { EventUploadService } from "@bitwarden/common/abstractions/event/event-upload.service"; -import { ExportService } from "@bitwarden/common/abstractions/export.service"; import { FileUploadService } from "@bitwarden/common/abstractions/file-upload/file-upload.service"; import { FileDownloadService } from "@bitwarden/common/abstractions/fileDownload/fileDownload.service"; import { I18nService as I18nServiceAbstraction } from "@bitwarden/common/abstractions/i18n.service"; @@ -79,6 +78,7 @@ import { import { PasswordRepromptService as PasswordRepromptServiceAbstraction } from "@bitwarden/common/vault/abstractions/password-reprompt.service"; import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction"; import { FolderApiService } from "@bitwarden/common/vault/services/folder/folder-api.service"; +import { VaultExportServiceAbstraction } from "@bitwarden/exporter/vault-export"; import { BrowserOrganizationService } from "../../admin-console/services/browser-organization.service"; import { BrowserPolicyService } from "../../admin-console/services/browser-policy.service"; @@ -342,7 +342,11 @@ function getBgService(service: keyof MainBackground) { useFactory: getBgService("autofillService"), deps: [], }, - { provide: ExportService, useFactory: getBgService("exportService"), deps: [] }, + { + provide: VaultExportServiceAbstraction, + useFactory: getBgService("exportService"), + deps: [], + }, { provide: KeyConnectorService, useFactory: getBgService("keyConnectorService"), diff --git a/apps/browser/src/popup/settings/export.component.html b/apps/browser/src/tools/popup/settings/export.component.html similarity index 100% rename from apps/browser/src/popup/settings/export.component.html rename to apps/browser/src/tools/popup/settings/export.component.html diff --git a/apps/browser/src/popup/settings/export.component.ts b/apps/browser/src/tools/popup/settings/export.component.ts similarity index 91% rename from apps/browser/src/popup/settings/export.component.ts rename to apps/browser/src/tools/popup/settings/export.component.ts index eb87917263..2235ff2340 100644 --- a/apps/browser/src/popup/settings/export.component.ts +++ b/apps/browser/src/tools/popup/settings/export.component.ts @@ -2,16 +2,16 @@ import { Component } from "@angular/core"; import { UntypedFormBuilder } from "@angular/forms"; import { Router } from "@angular/router"; -import { ExportComponent as BaseExportComponent } from "@bitwarden/angular/components/export.component"; +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"; -import { ExportService } from "@bitwarden/common/abstractions/export.service"; import { FileDownloadService } from "@bitwarden/common/abstractions/fileDownload/fileDownload.service"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/abstractions/log.service"; import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification/userVerification.service.abstraction"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; +import { VaultExportServiceAbstraction } from "@bitwarden/exporter/vault-export"; @Component({ selector: "app-export", @@ -22,7 +22,7 @@ export class ExportComponent extends BaseExportComponent { cryptoService: CryptoService, i18nService: I18nService, platformUtilsService: PlatformUtilsService, - exportService: ExportService, + exportService: VaultExportServiceAbstraction, eventCollectionService: EventCollectionService, policyService: PolicyService, private router: Router, diff --git a/apps/browser/tsconfig.json b/apps/browser/tsconfig.json index 3712393982..fa3df30d13 100644 --- a/apps/browser/tsconfig.json +++ b/apps/browser/tsconfig.json @@ -11,7 +11,8 @@ "baseUrl": ".", "paths": { "@bitwarden/common/*": ["../../libs/common/src/*"], - "@bitwarden/angular/*": ["../../libs/angular/src/*"] + "@bitwarden/angular/*": ["../../libs/angular/src/*"], + "@bitwarden/exporter/*": ["../../libs/exporter/src/*"] }, "useDefineForClassFields": false }, diff --git a/apps/cli/src/bw.ts b/apps/cli/src/bw.ts index 68c419920f..b3696db0c2 100644 --- a/apps/cli/src/bw.ts +++ b/apps/cli/src/bw.ts @@ -30,7 +30,6 @@ import { ContainerService } from "@bitwarden/common/services/container.service"; import { CryptoService } from "@bitwarden/common/services/crypto.service"; import { EncryptServiceImplementation } from "@bitwarden/common/services/cryptography/encrypt.service.implementation"; import { EnvironmentService } from "@bitwarden/common/services/environment.service"; -import { ExportService } from "@bitwarden/common/services/export.service"; import { FileUploadService } from "@bitwarden/common/services/file-upload/file-upload.service"; import { MemoryStorageService } from "@bitwarden/common/services/memoryStorage.service"; import { NoopMessagingService } from "@bitwarden/common/services/noopMessaging.service"; @@ -55,6 +54,10 @@ import { FolderApiService } from "@bitwarden/common/vault/services/folder/folder import { FolderService } from "@bitwarden/common/vault/services/folder/folder.service"; import { SyncNotifierService } from "@bitwarden/common/vault/services/sync/sync-notifier.service"; import { SyncService } from "@bitwarden/common/vault/services/sync/sync.service"; +import { + VaultExportService, + VaultExportServiceAbstraction, +} from "@bitwarden/exporter/vault-export"; import { ImportApiService, ImportApiServiceAbstraction, @@ -105,7 +108,7 @@ export class Main { auditService: AuditService; importService: ImportServiceAbstraction; importApiService: ImportApiServiceAbstraction; - exportService: ExportService; + exportService: VaultExportServiceAbstraction; searchService: SearchService; cryptoFunctionService: NodeCryptoFunctionService; encryptService: EncryptServiceImplementation; @@ -381,7 +384,7 @@ export class Main { this.collectionService, this.cryptoService ); - this.exportService = new ExportService( + this.exportService = new VaultExportService( this.folderService, this.cipherService, this.apiService, diff --git a/apps/cli/src/commands/export.command.ts b/apps/cli/src/tools/export.command.ts similarity index 94% rename from apps/cli/src/commands/export.command.ts rename to apps/cli/src/tools/export.command.ts index c41d1aad69..161086c2ea 100644 --- a/apps/cli/src/commands/export.command.ts +++ b/apps/cli/src/tools/export.command.ts @@ -1,20 +1,23 @@ import * as program from "commander"; import * as inquirer from "inquirer"; -import { - ExportFormat, - ExportService, - EXPORT_FORMATS, -} from "@bitwarden/common/abstractions/export.service"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { PolicyType } from "@bitwarden/common/admin-console/enums"; import { Utils } from "@bitwarden/common/misc/utils"; +import { + ExportFormat, + EXPORT_FORMATS, + VaultExportServiceAbstraction, +} from "@bitwarden/exporter/vault-export"; import { Response } from "../models/response"; import { CliUtils } from "../utils"; export class ExportCommand { - constructor(private exportService: ExportService, private policyService: PolicyService) {} + constructor( + private exportService: VaultExportServiceAbstraction, + private policyService: PolicyService + ) {} async run(options: program.OptionValues): Promise { if ( diff --git a/apps/cli/src/vault.program.ts b/apps/cli/src/vault.program.ts index 307d3b552f..767893d5ee 100644 --- a/apps/cli/src/vault.program.ts +++ b/apps/cli/src/vault.program.ts @@ -4,12 +4,12 @@ import { ConfirmCommand } from "./admin-console/commands/confirm.command"; import { ShareCommand } from "./admin-console/commands/share.command"; import { Main } from "./bw"; import { EditCommand } from "./commands/edit.command"; -import { ExportCommand } from "./commands/export.command"; import { GetCommand } from "./commands/get.command"; import { ListCommand } from "./commands/list.command"; import { RestoreCommand } from "./commands/restore.command"; import { Response } from "./models/response"; import { Program } from "./program"; +import { ExportCommand } from "./tools/export.command"; import { ImportCommand } from "./tools/import.command"; import { CliUtils } from "./utils"; import { CreateCommand } from "./vault/create.command"; diff --git a/apps/cli/src/vault/models/folder.response.ts b/apps/cli/src/vault/models/folder.response.ts index 7b1b204deb..6d6405bc40 100644 --- a/apps/cli/src/vault/models/folder.response.ts +++ b/apps/cli/src/vault/models/folder.response.ts @@ -1,4 +1,4 @@ -import { FolderWithIdExport } from "@bitwarden/common/models/export/folder-with-id.export"; +import { FolderWithIdExport } from "@bitwarden/common/models/export"; import { FolderView } from "@bitwarden/common/vault/models/view/folder.view"; import { BaseResponse } from "../../models/response/base.response"; diff --git a/apps/cli/tsconfig.json b/apps/cli/tsconfig.json index 2517566d1d..d516b5ee6c 100644 --- a/apps/cli/tsconfig.json +++ b/apps/cli/tsconfig.json @@ -15,6 +15,7 @@ "@bitwarden/common/spec/*": ["../../libs/common/spec/*"], "@bitwarden/common/*": ["../../libs/common/src/*"], "@bitwarden/importer": ["../../libs/importer/src"], + "@bitwarden/exporter/*": ["../../libs/exporter/src/*"], "@bitwarden/node/*": ["../../libs/node/src/*"] } }, diff --git a/apps/desktop/src/app/app.component.ts b/apps/desktop/src/app/app.component.ts index b7dad40eac..0f1c2ae583 100644 --- a/apps/desktop/src/app/app.component.ts +++ b/apps/desktop/src/app/app.component.ts @@ -48,9 +48,9 @@ import { PremiumComponent } from "../vault/app/accounts/premium.component"; import { FolderAddEditComponent } from "../vault/app/vault/folder-add-edit.component"; import { SettingsComponent } from "./accounts/settings.component"; +import { ExportComponent } from "./tools/export/export.component"; import { GeneratorComponent } from "./tools/generator.component"; import { PasswordGeneratorHistoryComponent } from "./tools/password-generator-history.component"; -import { ExportComponent } from "./vault/export.component"; const BroadcasterSubscriptionId = "AppComponent"; const IdleTimeout = 60000 * 10; // 10 minutes diff --git a/apps/desktop/src/app/app.module.ts b/apps/desktop/src/app/app.module.ts index 036ce8b7d8..0dae52319a 100644 --- a/apps/desktop/src/app/app.module.ts +++ b/apps/desktop/src/app/app.module.ts @@ -48,12 +48,12 @@ import { HeaderComponent } from "./layout/header.component"; import { NavComponent } from "./layout/nav.component"; import { SearchComponent } from "./layout/search/search.component"; import { SharedModule } from "./shared/shared.module"; +import { ExportComponent } from "./tools/export/export.component"; import { GeneratorComponent } from "./tools/generator.component"; import { PasswordGeneratorHistoryComponent } from "./tools/password-generator-history.component"; import { AddEditComponent as SendAddEditComponent } from "./tools/send/add-edit.component"; import { EffluxDatesComponent as SendEffluxDatesComponent } from "./tools/send/efflux-dates.component"; import { SendComponent } from "./tools/send/send.component"; -import { ExportComponent } from "./vault/export.component"; @NgModule({ imports: [SharedModule, AppRoutingModule, VaultFilterModule, LoginModule], diff --git a/apps/desktop/src/app/vault/export.component.html b/apps/desktop/src/app/tools/export/export.component.html similarity index 100% rename from apps/desktop/src/app/vault/export.component.html rename to apps/desktop/src/app/tools/export/export.component.html diff --git a/apps/desktop/src/app/vault/export.component.ts b/apps/desktop/src/app/tools/export/export.component.ts similarity index 93% rename from apps/desktop/src/app/vault/export.component.ts rename to apps/desktop/src/app/tools/export/export.component.ts index ed712f4c06..511710f058 100644 --- a/apps/desktop/src/app/vault/export.component.ts +++ b/apps/desktop/src/app/tools/export/export.component.ts @@ -3,17 +3,17 @@ import * as os from "os"; import { Component, OnInit } from "@angular/core"; import { UntypedFormBuilder } from "@angular/forms"; -import { ExportComponent as BaseExportComponent } from "@bitwarden/angular/components/export.component"; +import { ExportComponent as BaseExportComponent } from "@bitwarden/angular/tools/export/components/export.component"; import { BroadcasterService } from "@bitwarden/common/abstractions/broadcaster.service"; import { CryptoService } from "@bitwarden/common/abstractions/crypto.service"; import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service"; -import { ExportService } from "@bitwarden/common/abstractions/export.service"; import { FileDownloadService } from "@bitwarden/common/abstractions/fileDownload/fileDownload.service"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/abstractions/log.service"; import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification/userVerification.service.abstraction"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; +import { VaultExportServiceAbstraction } from "@bitwarden/exporter/vault-export"; const BroadcasterSubscriptionId = "ExportComponent"; @@ -26,7 +26,7 @@ export class ExportComponent extends BaseExportComponent implements OnInit { cryptoService: CryptoService, i18nService: I18nService, platformUtilsService: PlatformUtilsService, - exportService: ExportService, + exportService: VaultExportServiceAbstraction, eventCollectionService: EventCollectionService, policyService: PolicyService, userVerificationService: UserVerificationService, diff --git a/apps/desktop/tsconfig.json b/apps/desktop/tsconfig.json index 54acad29f5..3d01b5ba6f 100644 --- a/apps/desktop/tsconfig.json +++ b/apps/desktop/tsconfig.json @@ -11,7 +11,8 @@ "baseUrl": ".", "paths": { "@bitwarden/common/*": ["../../libs/common/src/*"], - "@bitwarden/angular/*": ["../../libs/angular/src/*"] + "@bitwarden/angular/*": ["../../libs/angular/src/*"], + "@bitwarden/exporter/*": ["../../libs/exporter/src/*"] }, "useDefineForClassFields": false }, diff --git a/apps/web/src/app/admin-console/organizations/manage/events.component.ts b/apps/web/src/app/admin-console/organizations/manage/events.component.ts index 4215bcc9c0..df10e3c7e3 100644 --- a/apps/web/src/app/admin-console/organizations/manage/events.component.ts +++ b/apps/web/src/app/admin-console/organizations/manage/events.component.ts @@ -4,7 +4,6 @@ import { concatMap, Subject, takeUntil } from "rxjs"; import { UserNamePipe } from "@bitwarden/angular/pipes/user-name.pipe"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; -import { ExportService } from "@bitwarden/common/abstractions/export.service"; import { FileDownloadService } from "@bitwarden/common/abstractions/fileDownload/fileDownload.service"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/abstractions/log.service"; @@ -18,6 +17,7 @@ import { EventResponse } from "@bitwarden/common/models/response/event.response" import { BaseEventsComponent } from "../../../common/base.events.component"; import { EventService } from "../../../core"; +import { EventExportService } from "../../../tools/event-export"; const EVENT_SYSTEM_USER_TO_TRANSLATION: Record = { [EventSystemUser.SCIM]: null, // SCIM acronym not able to be translated so just display SCIM @@ -41,7 +41,7 @@ export class EventsComponent extends BaseEventsComponent implements OnInit, OnDe private route: ActivatedRoute, eventService: EventService, i18nService: I18nService, - exportService: ExportService, + exportService: EventExportService, platformUtilsService: PlatformUtilsService, private router: Router, logService: LogService, diff --git a/apps/web/src/app/admin-console/organizations/tools/import-export/org-export.component.ts b/apps/web/src/app/admin-console/organizations/tools/import-export/org-export.component.ts index e49341ec3f..02dcec83e3 100644 --- a/apps/web/src/app/admin-console/organizations/tools/import-export/org-export.component.ts +++ b/apps/web/src/app/admin-console/organizations/tools/import-export/org-export.component.ts @@ -5,7 +5,6 @@ import { ActivatedRoute } from "@angular/router"; import { ModalService } from "@bitwarden/angular/services/modal.service"; import { CryptoService } from "@bitwarden/common/abstractions/crypto.service"; import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service"; -import { ExportService } from "@bitwarden/common/abstractions/export.service"; import { FileDownloadService } from "@bitwarden/common/abstractions/fileDownload/fileDownload.service"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/abstractions/log.service"; @@ -13,6 +12,7 @@ import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUti import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification/userVerification.service.abstraction"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { EventType } from "@bitwarden/common/enums"; +import { VaultExportServiceAbstraction } from "@bitwarden/exporter/vault-export"; import { ExportComponent } from "../../../../tools/import-export/export.component"; @@ -26,7 +26,7 @@ export class OrganizationExportComponent extends ExportComponent { cryptoService: CryptoService, i18nService: I18nService, platformUtilsService: PlatformUtilsService, - exportService: ExportService, + exportService: VaultExportServiceAbstraction, eventCollectionService: EventCollectionService, private route: ActivatedRoute, policyService: PolicyService, diff --git a/apps/web/src/app/common/base.events.component.ts b/apps/web/src/app/common/base.events.component.ts index c3bcb24cae..ddd384a249 100644 --- a/apps/web/src/app/common/base.events.component.ts +++ b/apps/web/src/app/common/base.events.component.ts @@ -1,6 +1,5 @@ import { Directive } from "@angular/core"; -import { ExportService } from "@bitwarden/common/abstractions/export.service"; import { FileDownloadService } from "@bitwarden/common/abstractions/fileDownload/fileDownload.service"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/abstractions/log.service"; @@ -10,6 +9,7 @@ import { ListResponse } from "@bitwarden/common/models/response/list.response"; import { EventView } from "@bitwarden/common/models/view/event.view"; import { EventService } from "../core"; +import { EventExportService } from "../tools/event-export"; @Directive() export abstract class BaseEventsComponent { @@ -29,7 +29,7 @@ export abstract class BaseEventsComponent { constructor( protected eventService: EventService, protected i18nService: I18nService, - protected exportService: ExportService, + protected exportService: EventExportService, protected platformUtilsService: PlatformUtilsService, protected logService: LogService, protected fileDownloadService: FileDownloadService diff --git a/apps/web/src/app/tools/event-export/event-export.service.ts b/apps/web/src/app/tools/event-export/event-export.service.ts new file mode 100644 index 0000000000..a96dc8e59c --- /dev/null +++ b/apps/web/src/app/tools/event-export/event-export.service.ts @@ -0,0 +1,20 @@ +import { Injectable } from "@angular/core"; +import * as papa from "papaparse"; + +import { EventView } from "@bitwarden/common/models/view/event.view"; +import { ExportHelper } from "@bitwarden/exporter/export-helper"; + +import { EventExport } from "./event.export"; + +@Injectable({ + providedIn: "root", +}) +export class EventExportService { + async getEventExport(events: EventView[]): Promise { + return papa.unparse(events.map((e) => new EventExport(e))); + } + + getFileName(prefix: string = null, extension = "csv"): string { + return ExportHelper.getFileName(prefix, extension); + } +} diff --git a/libs/common/src/models/export/event.export.ts b/apps/web/src/app/tools/event-export/event.export.ts similarity index 83% rename from libs/common/src/models/export/event.export.ts rename to apps/web/src/app/tools/event-export/event.export.ts index b1214b109d..b68f67d3d8 100644 --- a/libs/common/src/models/export/event.export.ts +++ b/apps/web/src/app/tools/event-export/event.export.ts @@ -1,5 +1,5 @@ -import { EventType } from "../../enums"; -import { EventView } from "../view/event.view"; +import { EventType } from "@bitwarden/common/enums"; +import { EventView } from "@bitwarden/common/models/view/event.view"; export class EventExport { message: string; diff --git a/apps/web/src/app/tools/event-export/index.ts b/apps/web/src/app/tools/event-export/index.ts new file mode 100644 index 0000000000..f32901c2b3 --- /dev/null +++ b/apps/web/src/app/tools/event-export/index.ts @@ -0,0 +1 @@ +export * from "./event-export.service"; diff --git a/apps/web/src/app/tools/import-export/export.component.ts b/apps/web/src/app/tools/import-export/export.component.ts index b4fbbf576b..2f7dce6d13 100644 --- a/apps/web/src/app/tools/import-export/export.component.ts +++ b/apps/web/src/app/tools/import-export/export.component.ts @@ -1,11 +1,10 @@ import { Component } from "@angular/core"; import { UntypedFormBuilder } from "@angular/forms"; -import { ExportComponent as BaseExportComponent } from "@bitwarden/angular/components/export.component"; import { ModalService } from "@bitwarden/angular/services/modal.service"; +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"; -import { ExportService } from "@bitwarden/common/abstractions/export.service"; import { FileDownloadService } from "@bitwarden/common/abstractions/fileDownload/fileDownload.service"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/abstractions/log.service"; @@ -13,6 +12,7 @@ import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUti import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification/userVerification.service.abstraction"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { EncryptedExportType } from "@bitwarden/common/enums"; +import { VaultExportServiceAbstraction } from "@bitwarden/exporter/vault-export"; import { UserVerificationPromptComponent } from "../../components/user-verification-prompt.component"; @@ -29,7 +29,7 @@ export class ExportComponent extends BaseExportComponent { cryptoService: CryptoService, i18nService: I18nService, platformUtilsService: PlatformUtilsService, - exportService: ExportService, + exportService: VaultExportServiceAbstraction, eventCollectionService: EventCollectionService, policyService: PolicyService, logService: LogService, diff --git a/apps/web/tsconfig.json b/apps/web/tsconfig.json index d60b55efe3..9ead7d5a8c 100644 --- a/apps/web/tsconfig.json +++ b/apps/web/tsconfig.json @@ -9,7 +9,8 @@ "@bitwarden/common/*": ["../../libs/common/src/*"], "@bitwarden/angular/*": ["../../libs/angular/src/*"], "@bitwarden/components": ["../../libs/components/src"], - "@bitwarden/importer": ["../../libs/importer/src"] + "@bitwarden/importer": ["../../libs/importer/src"], + "@bitwarden/exporter/*": ["../../libs/exporter/src/*"] } }, "angularCompilerOptions": { diff --git a/bitwarden_license/bit-web/src/app/admin-console/providers/manage/events.component.ts b/bitwarden_license/bit-web/src/app/admin-console/providers/manage/events.component.ts index f6316e617d..288685f78a 100644 --- a/bitwarden_license/bit-web/src/app/admin-console/providers/manage/events.component.ts +++ b/bitwarden_license/bit-web/src/app/admin-console/providers/manage/events.component.ts @@ -3,7 +3,6 @@ import { ActivatedRoute, Router } from "@angular/router"; import { UserNamePipe } from "@bitwarden/angular/pipes/user-name.pipe"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; -import { ExportService } from "@bitwarden/common/abstractions/export.service"; import { FileDownloadService } from "@bitwarden/common/abstractions/fileDownload/fileDownload.service"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/abstractions/log.service"; @@ -12,6 +11,7 @@ import { ProviderService } from "@bitwarden/common/admin-console/abstractions/pr import { EventResponse } from "@bitwarden/common/models/response/event.response"; import { BaseEventsComponent } from "@bitwarden/web-vault/app/common/base.events.component"; import { EventService } from "@bitwarden/web-vault/app/core"; +import { EventExportService } from "@bitwarden/web-vault/app/tools/event-export"; @Component({ selector: "provider-events", @@ -31,7 +31,7 @@ export class EventsComponent extends BaseEventsComponent implements OnInit { eventService: EventService, i18nService: I18nService, private providerService: ProviderService, - exportService: ExportService, + exportService: EventExportService, platformUtilsService: PlatformUtilsService, private router: Router, logService: LogService, diff --git a/bitwarden_license/bit-web/tsconfig.json b/bitwarden_license/bit-web/tsconfig.json index 34d5213e1c..9f3a822488 100644 --- a/bitwarden_license/bit-web/tsconfig.json +++ b/bitwarden_license/bit-web/tsconfig.json @@ -5,7 +5,8 @@ "@bitwarden/web-vault/*": ["../../apps/web/src/*"], "@bitwarden/common/*": ["../../libs/common/src/*"], "@bitwarden/angular/*": ["../../libs/angular/src/*"], - "@bitwarden/components": ["../../libs/components/src"] + "@bitwarden/components": ["../../libs/components/src"], + "@bitwarden/exporter/*": ["../../libs/exporter/src/*"] } }, "include": ["src/**/*.stories.ts"] diff --git a/jest.config.js b/jest.config.js index 2016478f00..ec58fe0c01 100644 --- a/jest.config.js +++ b/jest.config.js @@ -22,6 +22,7 @@ module.exports = { "/libs/common/jest.config.js", "/libs/components/jest.config.js", "/libs/importer/jest.config.js", + "/libs/exporter/jest.config.js", "/libs/node/jest.config.js", ], diff --git a/libs/angular/src/jslib.module.ts b/libs/angular/src/jslib.module.ts index 3c08b4a77f..dac7a0779e 100644 --- a/libs/angular/src/jslib.module.ts +++ b/libs/angular/src/jslib.module.ts @@ -3,7 +3,6 @@ import { NgModule } from "@angular/core"; import { FormsModule, ReactiveFormsModule } from "@angular/forms"; import { CalloutComponent } from "./components/callout.component"; -import { ExportScopeCalloutComponent } from "./components/export-scope-callout.component"; import { BitwardenToastModule } from "./components/toastr.component"; import { A11yInvalidDirective } from "./directives/a11y-invalid.directive"; import { A11yTitleDirective } from "./directives/a11y-title.directive"; @@ -28,6 +27,7 @@ import { SearchPipe } from "./pipes/search.pipe"; import { UserNamePipe } from "./pipes/user-name.pipe"; import { UserTypePipe } from "./pipes/user-type.pipe"; import { PasswordStrengthComponent } from "./shared/components/password-strength/password-strength.component"; +import { ExportScopeCalloutComponent } from "./tools/export/components/export-scope-callout.component"; import { IconComponent } from "./vault/components/icon.component"; @NgModule({ diff --git a/libs/angular/src/services/jslib-services.module.ts b/libs/angular/src/services/jslib-services.module.ts index fcff4f8055..46e6932d9f 100644 --- a/libs/angular/src/services/jslib-services.module.ts +++ b/libs/angular/src/services/jslib-services.module.ts @@ -14,7 +14,6 @@ import { EncryptService } from "@bitwarden/common/abstractions/encrypt.service"; import { EnvironmentService as EnvironmentServiceAbstraction } from "@bitwarden/common/abstractions/environment.service"; import { EventCollectionService as EventCollectionServiceAbstraction } from "@bitwarden/common/abstractions/event/event-collection.service"; import { EventUploadService as EventUploadServiceAbstraction } from "@bitwarden/common/abstractions/event/event-upload.service"; -import { ExportService as ExportServiceAbstraction } from "@bitwarden/common/abstractions/export.service"; import { FileUploadService as FileUploadServiceAbstraction } from "@bitwarden/common/abstractions/file-upload/file-upload.service"; import { FormValidationErrorsService as FormValidationErrorsServiceAbstraction } from "@bitwarden/common/abstractions/formValidationErrors.service"; import { I18nService as I18nServiceAbstraction } from "@bitwarden/common/abstractions/i18n.service"; @@ -94,7 +93,6 @@ import { MultithreadEncryptServiceImplementation } from "@bitwarden/common/servi import { EnvironmentService } from "@bitwarden/common/services/environment.service"; import { EventCollectionService } from "@bitwarden/common/services/event/event-collection.service"; import { EventUploadService } from "@bitwarden/common/services/event/event-upload.service"; -import { ExportService } from "@bitwarden/common/services/export.service"; import { FileUploadService } from "@bitwarden/common/services/file-upload/file-upload.service"; import { FormValidationErrorsService } from "@bitwarden/common/services/formValidationErrors.service"; import { NotificationsService } from "@bitwarden/common/services/notifications.service"; @@ -138,6 +136,10 @@ import { FolderApiService } from "@bitwarden/common/vault/services/folder/folder import { FolderService } from "@bitwarden/common/vault/services/folder/folder.service"; import { SyncNotifierService } from "@bitwarden/common/vault/services/sync/sync-notifier.service"; import { SyncService } from "@bitwarden/common/vault/services/sync/sync.service"; +import { + VaultExportService, + VaultExportServiceAbstraction, +} from "@bitwarden/exporter/vault-export"; import { AuthGuard } from "../auth/guards/auth.guard"; import { LockGuard } from "../auth/guards/lock.guard"; @@ -464,8 +466,8 @@ import { AbstractThemingService } from "./theming/theming.service.abstraction"; deps: [AbstractStorageService, SECURE_STORAGE, STATE_FACTORY], }, { - provide: ExportServiceAbstraction, - useClass: ExportService, + provide: VaultExportServiceAbstraction, + useClass: VaultExportService, deps: [ FolderServiceAbstraction, CipherServiceAbstraction, diff --git a/libs/angular/src/components/export-scope-callout.component.html b/libs/angular/src/tools/export/components/export-scope-callout.component.html similarity index 100% rename from libs/angular/src/components/export-scope-callout.component.html rename to libs/angular/src/tools/export/components/export-scope-callout.component.html diff --git a/libs/angular/src/components/export-scope-callout.component.ts b/libs/angular/src/tools/export/components/export-scope-callout.component.ts similarity index 100% rename from libs/angular/src/components/export-scope-callout.component.ts rename to libs/angular/src/tools/export/components/export-scope-callout.component.ts diff --git a/libs/angular/src/components/export.component.ts b/libs/angular/src/tools/export/components/export.component.ts similarity index 97% rename from libs/angular/src/components/export.component.ts rename to libs/angular/src/tools/export/components/export.component.ts index 5bfcd6b9e9..c3c31c27f4 100644 --- a/libs/angular/src/components/export.component.ts +++ b/libs/angular/src/tools/export/components/export.component.ts @@ -4,7 +4,6 @@ import { merge, takeUntil, Subject, startWith } from "rxjs"; import { CryptoService } from "@bitwarden/common/abstractions/crypto.service"; import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service"; -import { ExportService } from "@bitwarden/common/abstractions/export.service"; import { FileDownloadService } from "@bitwarden/common/abstractions/fileDownload/fileDownload.service"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/abstractions/log.service"; @@ -13,6 +12,7 @@ import { UserVerificationService } from "@bitwarden/common/abstractions/userVeri import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { PolicyType } from "@bitwarden/common/admin-console/enums"; import { EncryptedExportType, EventType } from "@bitwarden/common/enums"; +import { VaultExportServiceAbstraction } from "@bitwarden/exporter/vault-export"; @Directive() export class ExportComponent implements OnInit, OnDestroy { @@ -41,7 +41,7 @@ export class ExportComponent implements OnInit, OnDestroy { protected cryptoService: CryptoService, protected i18nService: I18nService, protected platformUtilsService: PlatformUtilsService, - protected exportService: ExportService, + protected exportService: VaultExportServiceAbstraction, protected eventCollectionService: EventCollectionService, private policyService: PolicyService, protected win: Window, diff --git a/libs/common/src/models/export/index.ts b/libs/common/src/models/export/index.ts new file mode 100644 index 0000000000..b92c68d814 --- /dev/null +++ b/libs/common/src/models/export/index.ts @@ -0,0 +1,11 @@ +export { CardExport } from "./card.export"; +export { CipherWithIdExport } from "./cipher-with-ids.export"; +export { CipherExport } from "./cipher.export"; +export { CollectionWithIdExport } from "./collection-with-id.export"; +export { CollectionExport } from "./collection.export"; +export { FieldExport } from "./field.export"; +export { FolderWithIdExport } from "./folder-with-id.export"; +export { FolderExport } from "./folder.export"; +export { IdentityExport } from "./identity.export"; +export { LoginUriExport } from "./login-uri.export"; +export { SecureNoteExport } from "./secure-note.export"; diff --git a/libs/exporter/jest.config.js b/libs/exporter/jest.config.js new file mode 100644 index 0000000000..2eeeefad62 --- /dev/null +++ b/libs/exporter/jest.config.js @@ -0,0 +1,14 @@ +const { pathsToModuleNameMapper } = require("ts-jest"); + +const { compilerOptions } = require("../shared/tsconfig.libs"); + +const sharedConfig = require("../shared/jest.config.base"); + +module.exports = { + ...sharedConfig, + preset: "ts-jest", + testEnvironment: "jsdom", + moduleNameMapper: pathsToModuleNameMapper(compilerOptions?.paths || {}, { + prefix: "/", + }), +}; diff --git a/libs/exporter/package.json b/libs/exporter/package.json new file mode 100644 index 0000000000..aefbcc1c1d --- /dev/null +++ b/libs/exporter/package.json @@ -0,0 +1,23 @@ +{ + "name": "@bitwarden/exporter", + "version": "0.0.0", + "description": "Home for all Bitwarden exporters.", + "keywords": [ + "bitwarden" + ], + "author": "Bitwarden Inc.", + "homepage": "https://bitwarden.com", + "repository": { + "type": "git", + "url": "https://github.com/bitwarden/clients" + }, + "license": "GPL-3.0", + "scripts": { + "clean": "rimraf dist/**/*", + "build": "npm run clean && tsc", + "build:watch": "npm run clean && tsc -watch" + }, + "dependencies": { + "@bitwarden/common": "file:../common" + } +} diff --git a/libs/exporter/src/export-helper.ts b/libs/exporter/src/export-helper.ts new file mode 100644 index 0000000000..85cc924d69 --- /dev/null +++ b/libs/exporter/src/export-helper.ts @@ -0,0 +1,24 @@ +export class ExportHelper { + static getFileName(prefix: string = null, extension = "csv"): string { + const now = new Date(); + const dateString = + now.getFullYear() + + "" + + this.padNumber(now.getMonth() + 1, 2) + + "" + + this.padNumber(now.getDate(), 2) + + this.padNumber(now.getHours(), 2) + + "" + + this.padNumber(now.getMinutes(), 2) + + this.padNumber(now.getSeconds(), 2); + + return "bitwarden" + (prefix ? "_" + prefix : "") + "_export_" + dateString + "." + extension; + } + + private static padNumber(num: number, width: number, padCharacter = "0"): string { + const numString = num.toString(); + return numString.length >= width + ? numString + : new Array(width - numString.length + 1).join(padCharacter) + numString; + } +} diff --git a/libs/importer/src/importers/bitwarden/bitwarden-password-protected-types.ts b/libs/exporter/src/vault-export/bitwarden-password-protected-types.ts similarity index 100% rename from libs/importer/src/importers/bitwarden/bitwarden-password-protected-types.ts rename to libs/exporter/src/vault-export/bitwarden-password-protected-types.ts diff --git a/libs/exporter/src/vault-export/index.ts b/libs/exporter/src/vault-export/index.ts new file mode 100644 index 0000000000..c7bc4a957a --- /dev/null +++ b/libs/exporter/src/vault-export/index.ts @@ -0,0 +1,2 @@ +export * from "./services/vault-export.service.abstraction"; +export * from "./services/vault-export.service"; diff --git a/libs/common/src/abstractions/export.service.ts b/libs/exporter/src/vault-export/services/vault-export.service.abstraction.ts similarity index 75% rename from libs/common/src/abstractions/export.service.ts rename to libs/exporter/src/vault-export/services/vault-export.service.abstraction.ts index 92ed7fec69..68da83bfae 100644 --- a/libs/common/src/abstractions/export.service.ts +++ b/libs/exporter/src/vault-export/services/vault-export.service.abstraction.ts @@ -1,11 +1,9 @@ -import { EventView } from "../models/view/event.view"; - export const EXPORT_FORMATS = ["csv", "json", "encrypted_json"] as const; export type ExportFormat = (typeof EXPORT_FORMATS)[number]; -export abstract class ExportService { + +export abstract class VaultExportServiceAbstraction { getExport: (format?: ExportFormat, organizationId?: string) => Promise; getPasswordProtectedExport: (password: string, organizationId?: string) => Promise; getOrganizationExport: (organizationId: string, format?: ExportFormat) => Promise; - getEventExport: (events: EventView[]) => Promise; getFileName: (prefix?: string, extension?: string) => string; } diff --git a/libs/common/spec/services/export.service.spec.ts b/libs/exporter/src/vault-export/services/vault-export.service.spec.ts similarity index 95% rename from libs/common/spec/services/export.service.spec.ts rename to libs/exporter/src/vault-export/services/vault-export.service.spec.ts index 92d7254282..1dea90a29d 100644 --- a/libs/common/spec/services/export.service.spec.ts +++ b/libs/exporter/src/vault-export/services/vault-export.service.spec.ts @@ -8,8 +8,7 @@ import { KdfConfig } from "@bitwarden/common/auth/models/domain/kdf-config"; import { KdfType, DEFAULT_PBKDF2_ITERATIONS } from "@bitwarden/common/enums"; import { Utils } from "@bitwarden/common/misc/utils"; import { EncString } from "@bitwarden/common/models/domain/enc-string"; -import { CipherWithIdExport as CipherExport } from "@bitwarden/common/models/export/cipher-with-ids.export"; -import { ExportService } from "@bitwarden/common/services/export.service"; +import { CipherWithIdExport } from "@bitwarden/common/models/export/cipher-with-ids.export"; import { StateService } from "@bitwarden/common/services/state.service"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction"; @@ -21,7 +20,9 @@ import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; import { FolderView } from "@bitwarden/common/vault/models/view/folder.view"; import { LoginView } from "@bitwarden/common/vault/models/view/login.view"; -import { BuildTestObject, GetUniqueString } from "../utils"; +import { BuildTestObject, GetUniqueString } from "../../../../common/spec/utils"; + +import { VaultExportService } from "./vault-export.service"; const UserCipherViews = [ generateCipherView(false), @@ -101,9 +102,9 @@ function generateFolder() { function expectEqualCiphers(ciphers: CipherView[] | Cipher[], jsonResult: string) { const actual = JSON.stringify(JSON.parse(jsonResult).items); - const items: CipherExport[] = []; + const items: CipherWithIdExport[] = []; ciphers.forEach((c: CipherView | Cipher) => { - const item = new CipherExport(); + const item = new CipherWithIdExport(); item.build(c); items.push(item); }); @@ -139,8 +140,8 @@ function expectEqualFolders(folders: Folder[], jsonResult: string) { expect(actual).toEqual(JSON.stringify(items)); } -describe("ExportService", () => { - let exportService: ExportService; +describe("VaultExportService", () => { + let exportService: VaultExportService; let apiService: SubstituteOf; let cryptoFunctionService: SubstituteOf; let cipherService: SubstituteOf; @@ -161,7 +162,7 @@ describe("ExportService", () => { stateService.getKdfType().resolves(KdfType.PBKDF2_SHA256); stateService.getKdfConfig().resolves(new KdfConfig(DEFAULT_PBKDF2_ITERATIONS)); - exportService = new ExportService( + exportService = new VaultExportService( folderService, cipherService, apiService, diff --git a/libs/common/src/services/export.service.ts b/libs/exporter/src/vault-export/services/vault-export.service.ts similarity index 77% rename from libs/common/src/services/export.service.ts rename to libs/exporter/src/vault-export/services/vault-export.service.ts index a562e8b3fa..bfb8f4160f 100644 --- a/libs/common/src/services/export.service.ts +++ b/libs/exporter/src/vault-export/services/vault-export.service.ts @@ -1,37 +1,36 @@ import * as papa from "papaparse"; -import { BitwardenPasswordProtectedFileFormat } from "@bitwarden/importer/src/importers/bitwarden/bitwarden-password-protected-types"; - -import { ApiService } from "../abstractions/api.service"; -import { CryptoService } from "../abstractions/crypto.service"; -import { CryptoFunctionService } from "../abstractions/cryptoFunction.service"; +import { ApiService } from "@bitwarden/common/abstractions/api.service"; +import { CryptoService } from "@bitwarden/common/abstractions/crypto.service"; +import { CryptoFunctionService } from "@bitwarden/common/abstractions/cryptoFunction.service"; +import { StateService } from "@bitwarden/common/abstractions/state.service"; +import { CollectionData } from "@bitwarden/common/admin-console/models/data/collection.data"; +import { Collection } from "@bitwarden/common/admin-console/models/domain/collection"; +import { CollectionDetailsResponse } from "@bitwarden/common/admin-console/models/response/collection.response"; +import { CollectionView } from "@bitwarden/common/admin-console/models/view/collection.view"; +import { KdfConfig } from "@bitwarden/common/auth/models/domain/kdf-config"; +import { KdfType } from "@bitwarden/common/enums"; +import { Utils } from "@bitwarden/common/misc/utils"; import { - ExportFormat, - ExportService as ExportServiceAbstraction, -} from "../abstractions/export.service"; -import { StateService } from "../abstractions/state.service"; -import { CollectionData } from "../admin-console/models/data/collection.data"; -import { Collection } from "../admin-console/models/domain/collection"; -import { CollectionDetailsResponse } from "../admin-console/models/response/collection.response"; -import { CollectionView } from "../admin-console/models/view/collection.view"; -import { KdfConfig } from "../auth/models/domain/kdf-config"; -import { KdfType } from "../enums"; -import { Utils } from "../misc/utils"; -import { CipherWithIdExport as CipherExport } from "../models/export/cipher-with-ids.export"; -import { CollectionWithIdExport as CollectionExport } from "../models/export/collection-with-id.export"; -import { EventExport } from "../models/export/event.export"; -import { FolderWithIdExport as FolderExport } from "../models/export/folder-with-id.export"; -import { EventView } from "../models/view/event.view"; -import { CipherService } from "../vault/abstractions/cipher.service"; -import { FolderService } from "../vault/abstractions/folder/folder.service.abstraction"; -import { CipherType } from "../vault/enums/cipher-type"; -import { CipherData } from "../vault/models/data/cipher.data"; -import { Cipher } from "../vault/models/domain/cipher"; -import { Folder } from "../vault/models/domain/folder"; -import { CipherView } from "../vault/models/view/cipher.view"; -import { FolderView } from "../vault/models/view/folder.view"; + CipherWithIdExport, + CollectionWithIdExport, + FolderWithIdExport, +} from "@bitwarden/common/models/export"; +import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; +import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction"; +import { CipherType } from "@bitwarden/common/vault/enums/cipher-type"; +import { CipherData } from "@bitwarden/common/vault/models/data/cipher.data"; +import { Cipher } from "@bitwarden/common/vault/models/domain/cipher"; +import { Folder } from "@bitwarden/common/vault/models/domain/folder"; +import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; +import { FolderView } from "@bitwarden/common/vault/models/view/folder.view"; -export class ExportService implements ExportServiceAbstraction { +import { ExportHelper } from "../../export-helper"; +import { BitwardenPasswordProtectedFileFormat } from "../bitwarden-password-protected-types"; + +import { ExportFormat, VaultExportServiceAbstraction } from "./vault-export.service.abstraction"; + +export class VaultExportService implements VaultExportServiceAbstraction { constructor( private folderService: FolderService, private cipherService: CipherService, @@ -93,24 +92,8 @@ export class ExportService implements ExportServiceAbstraction { } } - async getEventExport(events: EventView[]): Promise { - return papa.unparse(events.map((e) => new EventExport(e))); - } - getFileName(prefix: string = null, extension = "csv"): string { - const now = new Date(); - const dateString = - now.getFullYear() + - "" + - this.padNumber(now.getMonth() + 1, 2) + - "" + - this.padNumber(now.getDate(), 2) + - this.padNumber(now.getHours(), 2) + - "" + - this.padNumber(now.getMinutes(), 2) + - this.padNumber(now.getSeconds(), 2); - - return "bitwarden" + (prefix ? "_" + prefix : "") + "_export_" + dateString + "." + extension; + return ExportHelper.getFileName(prefix, extension); } private async getDecryptedExport(format: "json" | "csv"): Promise { @@ -170,7 +153,7 @@ export class ExportService implements ExportServiceAbstraction { if (f.id == null) { return; } - const folder = new FolderExport(); + const folder = new FolderWithIdExport(); folder.build(f); jsonDoc.folders.push(folder); }); @@ -179,7 +162,7 @@ export class ExportService implements ExportServiceAbstraction { if (c.organizationId != null) { return; } - const cipher = new CipherExport(); + const cipher = new CipherWithIdExport(); cipher.build(c); cipher.collectionIds = null; jsonDoc.items.push(cipher); @@ -221,7 +204,7 @@ export class ExportService implements ExportServiceAbstraction { if (f.id == null) { return; } - const folder = new FolderExport(); + const folder = new FolderWithIdExport(); folder.build(f); jsonDoc.folders.push(folder); }); @@ -230,7 +213,7 @@ export class ExportService implements ExportServiceAbstraction { if (c.organizationId != null) { return; } - const cipher = new CipherExport(); + const cipher = new CipherWithIdExport(); cipher.build(c); cipher.collectionIds = null; jsonDoc.items.push(cipher); @@ -313,13 +296,13 @@ export class ExportService implements ExportServiceAbstraction { }; decCollections.forEach((c) => { - const collection = new CollectionExport(); + const collection = new CollectionWithIdExport(); collection.build(c); jsonDoc.collections.push(collection); }); decCiphers.forEach((c) => { - const cipher = new CipherExport(); + const cipher = new CipherWithIdExport(); cipher.build(c); jsonDoc.items.push(cipher); }); @@ -373,26 +356,19 @@ export class ExportService implements ExportServiceAbstraction { }; collections.forEach((c) => { - const collection = new CollectionExport(); + const collection = new CollectionWithIdExport(); collection.build(c); jsonDoc.collections.push(collection); }); ciphers.forEach((c) => { - const cipher = new CipherExport(); + const cipher = new CipherWithIdExport(); cipher.build(c); jsonDoc.items.push(cipher); }); return JSON.stringify(jsonDoc, null, " "); } - private padNumber(num: number, width: number, padCharacter = "0"): string { - const numString = num.toString(); - return numString.length >= width - ? numString - : new Array(width - numString.length + 1).join(padCharacter) + numString; - } - private buildCommonCipher(cipher: any, c: CipherView) { cipher.type = null; cipher.name = c.name; diff --git a/libs/exporter/tsconfig.json b/libs/exporter/tsconfig.json new file mode 100644 index 0000000000..4952ed5adb --- /dev/null +++ b/libs/exporter/tsconfig.json @@ -0,0 +1,5 @@ +{ + "extends": "../shared/tsconfig.libs", + "include": ["src"], + "exclude": ["node_modules", "dist"] +} diff --git a/libs/exporter/tsconfig.spec.json b/libs/exporter/tsconfig.spec.json new file mode 100644 index 0000000000..fc8520e737 --- /dev/null +++ b/libs/exporter/tsconfig.spec.json @@ -0,0 +1,3 @@ +{ + "extends": "./tsconfig.json" +} diff --git a/libs/importer/package.json b/libs/importer/package.json index 7817996b5a..49ca76d16d 100644 --- a/libs/importer/package.json +++ b/libs/importer/package.json @@ -18,6 +18,7 @@ "build:watch": "npm run clean && tsc -watch" }, "dependencies": { - "@bitwarden/common": "file:../common" + "@bitwarden/common": "file:../common", + "@bitwarden/exporter": "file:../exporter" } } diff --git a/libs/importer/src/importers/bitwarden/bitwarden-json-importer.ts b/libs/importer/src/importers/bitwarden/bitwarden-json-importer.ts index 5958c7e5c0..816082f07f 100644 --- a/libs/importer/src/importers/bitwarden/bitwarden-json-importer.ts +++ b/libs/importer/src/importers/bitwarden/bitwarden-json-importer.ts @@ -1,9 +1,11 @@ import { CryptoService } from "@bitwarden/common/abstractions/crypto.service"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; import { EncString } from "@bitwarden/common/models/domain/enc-string"; -import { CipherWithIdExport } from "@bitwarden/common/models/export/cipher-with-ids.export"; -import { CollectionWithIdExport } from "@bitwarden/common/models/export/collection-with-id.export"; -import { FolderWithIdExport } from "@bitwarden/common/models/export/folder-with-id.export"; +import { + CipherWithIdExport, + CollectionWithIdExport, + FolderWithIdExport, +} from "@bitwarden/common/models/export"; import { ImportResult } from "../../models/import-result"; import { BaseImporter } from "../base-importer"; diff --git a/libs/importer/src/importers/bitwarden/bitwarden-password-protected-importer.ts b/libs/importer/src/importers/bitwarden/bitwarden-password-protected-importer.ts index 5baa34cb72..4b83aa3ea5 100644 --- a/libs/importer/src/importers/bitwarden/bitwarden-password-protected-importer.ts +++ b/libs/importer/src/importers/bitwarden/bitwarden-password-protected-importer.ts @@ -4,12 +4,12 @@ import { KdfConfig } from "@bitwarden/common/auth/models/domain/kdf-config"; import { KdfType } from "@bitwarden/common/enums"; import { EncString } from "@bitwarden/common/models/domain/enc-string"; import { SymmetricCryptoKey } from "@bitwarden/common/models/domain/symmetric-crypto-key"; +import { BitwardenPasswordProtectedFileFormat } from "@bitwarden/exporter/vault-export/bitwarden-password-protected-types"; import { ImportResult } from "../../models/import-result"; import { Importer } from "../importer"; import { BitwardenJsonImporter } from "./bitwarden-json-importer"; -import { BitwardenPasswordProtectedFileFormat } from "./bitwarden-password-protected-types"; export class BitwardenPasswordProtectedImporter extends BitwardenJsonImporter implements Importer { private key: SymmetricCryptoKey; diff --git a/libs/shared/tsconfig.libs.json b/libs/shared/tsconfig.libs.json index 8bcb1bcf06..8eda1dc0d7 100644 --- a/libs/shared/tsconfig.libs.json +++ b/libs/shared/tsconfig.libs.json @@ -5,7 +5,8 @@ "@bitwarden/common/*": ["../common/src/*"], "@bitwarden/angular/*": ["../angular/src/*"], "@bitwarden/node/*": ["../node/src/*"], - "@bitwarden/importer": ["../importer/src"] + "@bitwarden/importer": ["../importer/src"], + "@bitwarden/exporter/*": ["../exporter/src/*"] } } } diff --git a/package-lock.json b/package-lock.json index 61c7bceb1f..0e5bf1eb7f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -258,6 +258,13 @@ "name": "@bitwarden/components", "version": "0.0.0" }, + "libs/exporter": { + "version": "0.0.0", + "license": "GPL-3.0", + "dependencies": { + "@bitwarden/common": "file:../common" + } + }, "libs/importer": { "name": "@bitwarden/importer", "version": "0.0.0", @@ -3320,6 +3327,10 @@ "resolved": "apps/desktop/desktop_native", "link": true }, + "node_modules/@bitwarden/exporter": { + "resolved": "libs/exporter", + "link": true + }, "node_modules/@bitwarden/importer": { "resolved": "libs/importer", "link": true @@ -46979,6 +46990,12 @@ "@napi-rs/cli": "^2.6.2" } }, + "@bitwarden/exporter": { + "version": "file:libs/exporter", + "requires": { + "@bitwarden/common": "file:../common" + } + }, "@bitwarden/importer": { "version": "file:libs/importer", "requires": { diff --git a/tsconfig.eslint.json b/tsconfig.eslint.json index 6988851dbc..3398efa9fd 100644 --- a/tsconfig.eslint.json +++ b/tsconfig.eslint.json @@ -18,7 +18,8 @@ "@bitwarden/common/*": ["./libs/common/src/*"], "@bitwarden/angular/*": ["./libs/angular/src/*"], "@bitwarden/node/*": ["./libs/node/src/*"], - "@bitwarden/components": ["./libs/components/src"] + "@bitwarden/components": ["./libs/components/src"], + "@bitwarden/exporter/*": ["./libs/exporter/src/*"] }, "plugins": [ { diff --git a/tsconfig.json b/tsconfig.json index 09805a4012..649052c152 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -20,6 +20,7 @@ "@bitwarden/node/*": ["./libs/node/src/*"], "@bitwarden/components": ["./libs/components/src"], "@bitwarden/importer": ["./libs/importer/src"], + "@bitwarden/exporter/*": ["./libs/exporter/src/*"], "@bitwarden/web-vault/*": ["./apps/web/src/*"] }, "plugins": [