From adf135265539acbf417e94dc97b8e5e922cd587a Mon Sep 17 00:00:00 2001 From: Hinton Date: Fri, 13 Jan 2023 12:52:13 +0100 Subject: [PATCH] WIP for ciphers --- .../browser/src/background/main.background.ts | 2 +- .../src/background/notification.background.ts | 4 +- .../browser/cipher-context-menu-handler.ts | 2 +- .../context-menu-clicked-handler.spec.ts | 2 +- .../browser/context-menu-clicked-handler.ts | 2 +- .../browser/main-context-menu-handler.spec.ts | 2 +- .../src/browser/main-context-menu-handler.ts | 2 +- .../src/commands/autofill-tab-command.ts | 2 +- .../models/browserGroupingsComponentState.ts | 2 +- .../components/action-buttons.component.ts | 2 +- .../popup/components/cipher-row.component.ts | 2 +- .../popup/generator/generator.component.ts | 2 +- .../src/popup/vault/current-tab.component.ts | 2 +- .../src/popup/vault/vault-filter.component.ts | 2 +- .../src/popup/vault/vault-items.component.ts | 2 +- .../services/abstractions/autofill.service.ts | 2 +- apps/browser/src/services/autofill.service.ts | 2 +- .../src/services/vaultFilter.service.ts | 2 +- apps/cli/src/commands/get.command.ts | 2 +- apps/cli/src/commands/list.command.ts | 2 +- .../src/models/response/cipher.response.ts | 2 +- .../cli/src/models/response/login.response.ts | 2 +- .../response/password-history.response.ts | 2 +- .../src/app/vault/vault-items.component.ts | 2 +- apps/desktop/src/app/vault/vault.component.ts | 2 +- apps/desktop/src/app/vault/view.component.ts | 2 +- .../encrypted-message-handler.service.ts | 3 +- .../settings/delete-organization.component.ts | 2 +- .../exposed-passwords-report.component.ts | 2 +- .../inactive-two-factor-report.component.ts | 2 +- .../reused-passwords-report.component.ts | 2 +- .../unsecured-websites-report.component.ts | 2 +- .../tools/weak-passwords-report.component.ts | 2 +- .../organizations/vault/add-edit.component.ts | 13 +- .../vault/attachments.component.ts | 2 +- .../vault/collections.component.ts | 13 +- .../vault/vault-items.component.ts | 2 +- .../organizations/vault/vault.component.ts | 2 +- .../reports/pages/cipher-report.component.ts | 2 +- .../exposed-passwords-report.component.ts | 2 +- .../inactive-two-factor-report.component.ts | 2 +- .../reused-passwords-report.component.ts | 2 +- .../unsecured-websites-report.component.ts | 2 +- .../pages/weak-passwords-report.component.ts | 2 +- .../app/settings/change-password.component.ts | 2 +- .../emergency-access-attachments.component.ts | 2 +- .../emergency-access-view.component.ts | 12 +- .../settings/emergency-add-edit.component.ts | 7 +- .../src/app/settings/update-key.component.ts | 2 +- apps/web/src/app/vault/add-edit.component.ts | 9 +- .../src/app/vault/attachments.component.ts | 2 +- .../web/src/app/vault/bulk-share.component.ts | 2 +- .../src/app/vault/collections.component.ts | 13 +- apps/web/src/app/vault/share.component.ts | 7 +- .../src/app/vault/vault-items.component.ts | 2 +- apps/web/src/app/vault/vault.component.ts | 2 +- .../add-edit-custom-fields.component.ts | 3 +- .../src/components/add-edit.component.ts | 22 +- .../src/components/attachments.component.ts | 9 +- .../src/components/collections.component.ts | 8 +- libs/angular/src/components/icon.component.ts | 2 +- .../components/password-history.component.ts | 6 +- .../angular/src/components/share.component.ts | 10 +- .../src/components/vault-items.component.ts | 2 +- .../view-custom-fields.component.ts | 2 +- libs/angular/src/components/view.component.ts | 4 +- libs/angular/src/pipes/search-ciphers.pipe.ts | 2 +- .../models/vault-filter.model.spec.ts | 2 +- .../vault-filter/models/vault-filter.model.ts | 2 +- .../importers/chrome-csv-importer.spec.ts | 4 +- .../importers/firefox-csv-importer.spec.ts | 4 +- .../importers/lastpass-csv-importer.spec.ts | 3 +- .../spec/importers/myki-csv-importer.spec.ts | 2 +- .../importers/nordpass-csv-importer.spec.ts | 3 +- .../onepassword-1pux-importer.spec.ts | 2 +- .../onepassword-mac-csv-importer.spec.ts | 2 +- .../onepassword-win-csv-importer.spec.ts | 3 +- .../importers/safari-csv-importer.spec.ts | 4 +- .../spec/models/domain/attachment.spec.ts | 155 -------- .../spec/models/view/attachmentView.spec.ts | 18 - .../spec/models/view/cipherView.spec.ts | 76 ---- .../models/view/passwordHistoryView.spec.ts | 13 - .../spec/services/export.service.spec.ts | 6 +- libs/common/spec/utils.ts | 1 + libs/common/spec/view/login-uri-view.spec.ts | 2 +- .../common/src/abstractions/cipher.service.ts | 14 +- .../common/src/abstractions/crypto.service.ts | 2 +- .../src/abstractions/encrypt.service.ts | 8 +- .../common/src/abstractions/search.service.ts | 2 +- libs/common/src/abstractions/state.service.ts | 2 +- libs/common/src/importers/base-importer.ts | 6 +- .../src/importers/bitwarden-csv-importer.ts | 5 +- .../src/importers/bitwarden-json-importer.ts | 3 +- .../dashlane/dashlane-csv-importer.ts | 5 +- .../dashlane/dashlane-json-importer.ts | 5 +- .../src/importers/encryptr-csv-importer.ts | 2 +- .../src/importers/enpass-csv-importer.ts | 3 +- .../src/importers/enpass-json-importer.ts | 3 +- .../importers/fsecure/fsecure-fsk-importer.ts | 3 +- .../src/importers/lastpass-csv-importer.ts | 6 +- .../src/importers/msecure-csv-importer.ts | 2 +- .../common/src/importers/myki-csv-importer.ts | 5 +- .../src/importers/nordpass-csv-importer.ts | 3 +- .../onepassword/cipher-import-context.ts | 2 +- .../onepassword/onepassword-1pif-importer.ts | 12 +- .../onepassword/onepassword-1pux-importer.ts | 14 +- .../onepassword/onepassword-csv-importer.ts | 2 +- .../onepassword-mac-csv-importer.ts | 4 +- .../onepassword-win-csv-importer.ts | 5 +- .../importers/passwordboss-json-importer.ts | 2 +- .../src/importers/remembear-csv-importer.ts | 2 +- .../src/importers/safeincloud-xml-importer.ts | 4 +- .../src/importers/splashid-csv-importer.ts | 2 +- .../src/importers/truekey-csv-importer.ts | 3 +- .../src/importers/zohovault-csv-importer.ts | 2 +- .../common/src/interfaces/crypto.interface.ts | 1 + .../src/interfaces/decryptable.interface.ts | 13 - libs/common/src/models/domain/account.ts | 2 +- libs/common/src/models/domain/attachment.ts | 109 ------ libs/common/src/models/domain/card.ts | 88 ----- .../models/domain/cipher/attachment.spec.ts | 69 ++++ .../src/models/domain/cipher/attachment.ts | 51 +++ .../models/domain/cipher}/card.spec.ts | 42 +-- libs/common/src/models/domain/cipher/card.ts | 62 ++++ .../models/domain/cipher}/cipher.spec.ts | 255 ++----------- .../src/models/domain/{ => cipher}/cipher.ts | 143 ++------ .../models/domain/cipher}/field.spec.ts | 32 +- libs/common/src/models/domain/cipher/field.ts | 47 +++ .../models/domain/cipher}/identity.spec.ts | 91 ++--- .../src/models/domain/cipher/identity.ts | 103 ++++++ libs/common/src/models/domain/cipher/index.ts | 9 + .../models/domain/cipher/login-uri.spec.ts} | 51 +-- .../src/models/domain/cipher/login-uri.ts | 40 +++ .../models/domain/cipher}/login.spec.ts | 56 +-- libs/common/src/models/domain/cipher/login.ts | 76 ++++ .../models/domain/cipher}/password.spec.ts | 23 +- .../src/models/domain/cipher/password.ts | 39 ++ .../models/domain/cipher/secure-note.spec.ts} | 18 +- .../src/models/domain/cipher/secure-note.ts | 30 ++ libs/common/src/models/domain/field.ts | 78 ---- libs/common/src/models/domain/identity.ts | 161 --------- .../common/src/models/domain/import-result.ts | 2 +- libs/common/src/models/domain/index.ts | 2 + libs/common/src/models/domain/login-uri.ts | 67 ---- libs/common/src/models/domain/login.ts | 111 ------ libs/common/src/models/domain/password.ts | 59 --- libs/common/src/models/domain/secure-note.ts | 39 -- .../src/models/domain/sorted-ciphers-cache.ts | 2 +- libs/common/src/models/export/card.export.ts | 4 +- .../models/export/cipher-with-ids.export.ts | 2 +- .../common/src/models/export/cipher.export.ts | 2 +- libs/common/src/models/export/field.export.ts | 4 +- .../src/models/export/identity.export.ts | 4 +- .../src/models/export/login-uri.export.ts | 4 +- libs/common/src/models/export/login.export.ts | 4 +- .../src/models/export/secure-note.export.ts | 4 +- .../common/src/models/view/attachment.view.ts | 42 --- libs/common/src/models/view/cipher.view.ts | 179 ---------- .../view/cipher/attachment.view.spec.ts | 62 ++++ .../src/models/view/cipher/attachment.view.ts | 61 ++++ .../src/models/view/cipher/card.view.spec.ts | 28 ++ .../src/models/view/{ => cipher}/card.view.ts | 42 ++- .../models/view/cipher/cipher.view.spec.ts | 240 +++++++++++++ .../src/models/view/cipher/cipher.view.ts | 281 +++++++++++++++ .../src/models/view/cipher/field.view.spec.ts | 25 ++ .../src/models/view/cipher/field.view.ts | 53 +++ .../models/view/cipher/identity.view.spec.ts | 53 +++ .../src/models/view/cipher/identity.view.ts | 275 ++++++++++++++ libs/common/src/models/view/cipher/index.ts | 10 + .../src/models/view/{ => cipher}/item.view.ts | 4 +- .../cipher/linked-field-option.decorator.ts} | 5 +- .../view/{ => cipher}/login-uri.view.ts | 29 +- .../models/view/cipher/login.view.spec.ts} | 8 +- .../src/models/view/cipher/login.view.ts | 113 ++++++ .../view/cipher/password-history.view.spec.ts | 29 ++ .../view/cipher/password-history.view.ts | 37 ++ .../view/cipher/secure-note.view.spec.ts | 17 + .../models/view/cipher/secure-note.view.ts | 46 +++ libs/common/src/models/view/field.view.ts | 34 -- libs/common/src/models/view/identity.view.ts | 148 -------- libs/common/src/models/view/index.ts | 1 + libs/common/src/models/view/login.view.ts | 76 ---- .../src/models/view/password-history.view.ts | 26 -- .../src/models/view/secure-note.view.ts | 27 -- libs/common/src/services/cipher.service.ts | 336 +----------------- .../encrypt.service.implementation.ts | 10 +- .../services/cryptography/encrypt.worker.ts | 18 +- .../cryptography/get-class-initializer.ts | 10 +- ...tithread-encrypt.service.implementation.ts | 16 +- libs/common/src/services/export.service.ts | 10 +- libs/common/src/services/import.service.ts | 8 +- libs/common/src/services/search.service.ts | 2 +- libs/common/src/services/state.service.ts | 2 +- 193 files changed, 2344 insertions(+), 2698 deletions(-) delete mode 100644 libs/common/spec/models/domain/attachment.spec.ts delete mode 100644 libs/common/spec/models/view/attachmentView.spec.ts delete mode 100644 libs/common/spec/models/view/cipherView.spec.ts delete mode 100644 libs/common/spec/models/view/passwordHistoryView.spec.ts delete mode 100644 libs/common/src/interfaces/decryptable.interface.ts delete mode 100644 libs/common/src/models/domain/attachment.ts delete mode 100644 libs/common/src/models/domain/card.ts create mode 100644 libs/common/src/models/domain/cipher/attachment.spec.ts create mode 100644 libs/common/src/models/domain/cipher/attachment.ts rename libs/common/{spec/models/domain => src/models/domain/cipher}/card.spec.ts (62%) create mode 100644 libs/common/src/models/domain/cipher/card.ts rename libs/common/{spec/models/domain => src/models/domain/cipher}/cipher.spec.ts (65%) rename libs/common/src/models/domain/{ => cipher}/cipher.ts (54%) rename libs/common/{spec/models/domain => src/models/domain/cipher}/field.spec.ts (62%) create mode 100644 libs/common/src/models/domain/cipher/field.ts rename libs/common/{spec/models/domain => src/models/domain/cipher}/identity.spec.ts (57%) create mode 100644 libs/common/src/models/domain/cipher/identity.ts create mode 100644 libs/common/src/models/domain/cipher/index.ts rename libs/common/{spec/models/domain/loginUri.spec.ts => src/models/domain/cipher/login-uri.spec.ts} (72%) create mode 100644 libs/common/src/models/domain/cipher/login-uri.ts rename libs/common/{spec/models/domain => src/models/domain/cipher}/login.spec.ts (57%) create mode 100644 libs/common/src/models/domain/cipher/login.ts rename libs/common/{spec/models/domain => src/models/domain/cipher}/password.spec.ts (66%) create mode 100644 libs/common/src/models/domain/cipher/password.ts rename libs/common/{spec/models/domain/secureNote.spec.ts => src/models/domain/cipher/secure-note.spec.ts} (62%) create mode 100644 libs/common/src/models/domain/cipher/secure-note.ts delete mode 100644 libs/common/src/models/domain/field.ts delete mode 100644 libs/common/src/models/domain/identity.ts create mode 100644 libs/common/src/models/domain/index.ts delete mode 100644 libs/common/src/models/domain/login-uri.ts delete mode 100644 libs/common/src/models/domain/login.ts delete mode 100644 libs/common/src/models/domain/password.ts delete mode 100644 libs/common/src/models/domain/secure-note.ts delete mode 100644 libs/common/src/models/view/attachment.view.ts delete mode 100644 libs/common/src/models/view/cipher.view.ts create mode 100644 libs/common/src/models/view/cipher/attachment.view.spec.ts create mode 100644 libs/common/src/models/view/cipher/attachment.view.ts create mode 100644 libs/common/src/models/view/cipher/card.view.spec.ts rename libs/common/src/models/view/{ => cipher}/card.view.ts (56%) create mode 100644 libs/common/src/models/view/cipher/cipher.view.spec.ts create mode 100644 libs/common/src/models/view/cipher/cipher.view.ts create mode 100644 libs/common/src/models/view/cipher/field.view.spec.ts create mode 100644 libs/common/src/models/view/cipher/field.view.ts create mode 100644 libs/common/src/models/view/cipher/identity.view.spec.ts create mode 100644 libs/common/src/models/view/cipher/identity.view.ts create mode 100644 libs/common/src/models/view/cipher/index.ts rename libs/common/src/models/view/{ => cipher}/item.view.ts (57%) rename libs/common/src/{misc/linkedFieldOption.decorator.ts => models/view/cipher/linked-field-option.decorator.ts} (90%) rename libs/common/src/models/view/{ => cipher}/login-uri.view.ts (83%) rename libs/common/{spec/models/view/loginView.spec.ts => src/models/view/cipher/login.view.spec.ts} (70%) create mode 100644 libs/common/src/models/view/cipher/login.view.ts create mode 100644 libs/common/src/models/view/cipher/password-history.view.spec.ts create mode 100644 libs/common/src/models/view/cipher/password-history.view.ts create mode 100644 libs/common/src/models/view/cipher/secure-note.view.spec.ts create mode 100644 libs/common/src/models/view/cipher/secure-note.view.ts delete mode 100644 libs/common/src/models/view/field.view.ts delete mode 100644 libs/common/src/models/view/identity.view.ts create mode 100644 libs/common/src/models/view/index.ts delete mode 100644 libs/common/src/models/view/login.view.ts delete mode 100644 libs/common/src/models/view/password-history.view.ts delete mode 100644 libs/common/src/models/view/secure-note.view.ts diff --git a/apps/browser/src/background/main.background.ts b/apps/browser/src/background/main.background.ts index 4abec0c5fea9..79fc713fc883 100644 --- a/apps/browser/src/background/main.background.ts +++ b/apps/browser/src/background/main.background.ts @@ -42,7 +42,7 @@ import { VaultTimeoutService as VaultTimeoutServiceAbstraction } from "@bitwarde import { VaultTimeoutSettingsService as VaultTimeoutSettingsServiceAbstraction } from "@bitwarden/common/abstractions/vaultTimeout/vaultTimeoutSettings.service"; import { StateFactory } from "@bitwarden/common/factories/stateFactory"; import { GlobalState } from "@bitwarden/common/models/domain/global-state"; -import { CipherView } from "@bitwarden/common/models/view/cipher.view"; +import { CipherView } from "@bitwarden/common/models/view"; import { AvatarUpdateService } from "@bitwarden/common/services/account/avatar-update.service"; import { ApiService } from "@bitwarden/common/services/api.service"; import { AppIdService } from "@bitwarden/common/services/appId.service"; diff --git a/apps/browser/src/background/notification.background.ts b/apps/browser/src/background/notification.background.ts index 2da4791857d4..76b15079cbf2 100644 --- a/apps/browser/src/background/notification.background.ts +++ b/apps/browser/src/background/notification.background.ts @@ -9,9 +9,7 @@ import { CipherType } from "@bitwarden/common/enums/cipherType"; import { PolicyType } from "@bitwarden/common/enums/policyType"; import { ThemeType } from "@bitwarden/common/enums/themeType"; import { Utils } from "@bitwarden/common/misc/utils"; -import { CipherView } from "@bitwarden/common/models/view/cipher.view"; -import { LoginUriView } from "@bitwarden/common/models/view/login-uri.view"; -import { LoginView } from "@bitwarden/common/models/view/login.view"; +import { CipherView, LoginView, LoginUriView } from "@bitwarden/common/models/view"; import { BrowserApi } from "../browser/browserApi"; import { AutofillService } from "../services/abstractions/autofill.service"; diff --git a/apps/browser/src/browser/cipher-context-menu-handler.ts b/apps/browser/src/browser/cipher-context-menu-handler.ts index ea87f8da93e9..5f008c873e0e 100644 --- a/apps/browser/src/browser/cipher-context-menu-handler.ts +++ b/apps/browser/src/browser/cipher-context-menu-handler.ts @@ -7,7 +7,7 @@ import { CipherType } from "@bitwarden/common/enums/cipherType"; import { StateFactory } from "@bitwarden/common/factories/stateFactory"; import { Utils } from "@bitwarden/common/misc/utils"; import { GlobalState } from "@bitwarden/common/models/domain/global-state"; -import { CipherView } from "@bitwarden/common/models/view/cipher.view"; +import { CipherView } from "@bitwarden/common/models/view"; import { authServiceFactory, diff --git a/apps/browser/src/browser/context-menu-clicked-handler.spec.ts b/apps/browser/src/browser/context-menu-clicked-handler.spec.ts index a4d84aad1262..aa46b5f7f532 100644 --- a/apps/browser/src/browser/context-menu-clicked-handler.spec.ts +++ b/apps/browser/src/browser/context-menu-clicked-handler.spec.ts @@ -7,7 +7,7 @@ import { TotpService } from "@bitwarden/common/abstractions/totp.service"; import { CipherRepromptType } from "@bitwarden/common/enums/cipherRepromptType"; import { CipherType } from "@bitwarden/common/enums/cipherType"; import { Cipher } from "@bitwarden/common/models/domain/cipher"; -import { CipherView } from "@bitwarden/common/models/view/cipher.view"; +import { CipherView } from "@bitwarden/common/models/view"; import { AutofillTabCommand } from "../commands/autofill-tab-command"; diff --git a/apps/browser/src/browser/context-menu-clicked-handler.ts b/apps/browser/src/browser/context-menu-clicked-handler.ts index c11c6dbb94f8..86aee5ff3989 100644 --- a/apps/browser/src/browser/context-menu-clicked-handler.ts +++ b/apps/browser/src/browser/context-menu-clicked-handler.ts @@ -8,7 +8,7 @@ import { CipherRepromptType } from "@bitwarden/common/enums/cipherRepromptType"; import { EventType } from "@bitwarden/common/enums/eventType"; import { StateFactory } from "@bitwarden/common/factories/stateFactory"; import { GlobalState } from "@bitwarden/common/models/domain/global-state"; -import { CipherView } from "@bitwarden/common/models/view/cipher.view"; +import { CipherView } from "@bitwarden/common/models/view"; import LockedVaultPendingNotificationsItem from "../background/models/lockedVaultPendingNotificationsItem"; import { diff --git a/apps/browser/src/browser/main-context-menu-handler.spec.ts b/apps/browser/src/browser/main-context-menu-handler.spec.ts index 2dd41faf0431..a0b928116776 100644 --- a/apps/browser/src/browser/main-context-menu-handler.spec.ts +++ b/apps/browser/src/browser/main-context-menu-handler.spec.ts @@ -3,7 +3,7 @@ import { mock, MockProxy } from "jest-mock-extended"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; import { CipherType } from "@bitwarden/common/enums/cipherType"; import { Cipher } from "@bitwarden/common/models/domain/cipher"; -import { CipherView } from "@bitwarden/common/models/view/cipher.view"; +import { CipherView } from "@bitwarden/common/models/view"; import { BrowserStateService } from "../services/abstractions/browser-state.service"; diff --git a/apps/browser/src/browser/main-context-menu-handler.ts b/apps/browser/src/browser/main-context-menu-handler.ts index e78fb89023d4..fb4e8147d308 100644 --- a/apps/browser/src/browser/main-context-menu-handler.ts +++ b/apps/browser/src/browser/main-context-menu-handler.ts @@ -3,7 +3,7 @@ import { CipherType } from "@bitwarden/common/enums/cipherType"; import { StateFactory } from "@bitwarden/common/factories/stateFactory"; import { Utils } from "@bitwarden/common/misc/utils"; import { GlobalState } from "@bitwarden/common/models/domain/global-state"; -import { CipherView } from "@bitwarden/common/models/view/cipher.view"; +import { CipherView } from "@bitwarden/common/models/view"; import { CachedServices } from "../background/service_factories/factory-options"; import { diff --git a/apps/browser/src/commands/autofill-tab-command.ts b/apps/browser/src/commands/autofill-tab-command.ts index cf94dc93ae3c..f33a9cfdabc9 100644 --- a/apps/browser/src/commands/autofill-tab-command.ts +++ b/apps/browser/src/commands/autofill-tab-command.ts @@ -1,4 +1,4 @@ -import { CipherView } from "@bitwarden/common/models/view/cipher.view"; +import { CipherView } from "@bitwarden/common/models/view"; import AutofillPageDetails from "../models/autofillPageDetails"; import { AutofillService } from "../services/abstractions/autofill.service"; diff --git a/apps/browser/src/models/browserGroupingsComponentState.ts b/apps/browser/src/models/browserGroupingsComponentState.ts index f406e3d82715..f8c8664cc555 100644 --- a/apps/browser/src/models/browserGroupingsComponentState.ts +++ b/apps/browser/src/models/browserGroupingsComponentState.ts @@ -1,6 +1,6 @@ import { CipherType } from "@bitwarden/common/enums/cipherType"; import { Utils } from "@bitwarden/common/misc/utils"; -import { CipherView } from "@bitwarden/common/models/view/cipher.view"; +import { CipherView } from "@bitwarden/common/models/view"; import { CollectionView } from "@bitwarden/common/models/view/collection.view"; import { FolderView } from "@bitwarden/common/models/view/folder.view"; import { DeepJsonify } from "@bitwarden/common/types/deep-jsonify"; diff --git a/apps/browser/src/popup/components/action-buttons.component.ts b/apps/browser/src/popup/components/action-buttons.component.ts index 60bc0051fbb2..4e115d200d5c 100644 --- a/apps/browser/src/popup/components/action-buttons.component.ts +++ b/apps/browser/src/popup/components/action-buttons.component.ts @@ -9,7 +9,7 @@ import { TotpService } from "@bitwarden/common/abstractions/totp.service"; import { CipherRepromptType } from "@bitwarden/common/enums/cipherRepromptType"; import { CipherType } from "@bitwarden/common/enums/cipherType"; import { EventType } from "@bitwarden/common/enums/eventType"; -import { CipherView } from "@bitwarden/common/models/view/cipher.view"; +import { CipherView } from "@bitwarden/common/models/view"; @Component({ selector: "app-action-buttons", diff --git a/apps/browser/src/popup/components/cipher-row.component.ts b/apps/browser/src/popup/components/cipher-row.component.ts index bb99316dd25e..e69d6232e774 100644 --- a/apps/browser/src/popup/components/cipher-row.component.ts +++ b/apps/browser/src/popup/components/cipher-row.component.ts @@ -1,6 +1,6 @@ import { Component, EventEmitter, Input, Output } from "@angular/core"; -import { CipherView } from "@bitwarden/common/models/view/cipher.view"; +import { CipherView } from "@bitwarden/common/models/view"; @Component({ selector: "app-cipher-row", diff --git a/apps/browser/src/popup/generator/generator.component.ts b/apps/browser/src/popup/generator/generator.component.ts index cff5e9e3c37b..b5f61f246c61 100644 --- a/apps/browser/src/popup/generator/generator.component.ts +++ b/apps/browser/src/popup/generator/generator.component.ts @@ -9,7 +9,7 @@ import { PasswordGenerationService } from "@bitwarden/common/abstractions/passwo import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; import { StateService } from "@bitwarden/common/abstractions/state.service"; import { UsernameGenerationService } from "@bitwarden/common/abstractions/usernameGeneration.service"; -import { CipherView } from "@bitwarden/common/models/view/cipher.view"; +import { CipherView } from "@bitwarden/common/models/view"; @Component({ selector: "app-generator", diff --git a/apps/browser/src/popup/vault/current-tab.component.ts b/apps/browser/src/popup/vault/current-tab.component.ts index fd0e356476a7..55ff496054e3 100644 --- a/apps/browser/src/popup/vault/current-tab.component.ts +++ b/apps/browser/src/popup/vault/current-tab.component.ts @@ -15,7 +15,7 @@ import { SyncService } from "@bitwarden/common/abstractions/sync/sync.service.ab import { CipherRepromptType } from "@bitwarden/common/enums/cipherRepromptType"; import { CipherType } from "@bitwarden/common/enums/cipherType"; import { Utils } from "@bitwarden/common/misc/utils"; -import { CipherView } from "@bitwarden/common/models/view/cipher.view"; +import { CipherView } from "@bitwarden/common/models/view"; import { BrowserApi } from "../../browser/browserApi"; import { AutofillService } from "../../services/abstractions/autofill.service"; diff --git a/apps/browser/src/popup/vault/vault-filter.component.ts b/apps/browser/src/popup/vault/vault-filter.component.ts index e67fe69f6011..91928d091e53 100644 --- a/apps/browser/src/popup/vault/vault-filter.component.ts +++ b/apps/browser/src/popup/vault/vault-filter.component.ts @@ -12,7 +12,7 @@ import { SearchService } from "@bitwarden/common/abstractions/search.service"; import { SyncService } from "@bitwarden/common/abstractions/sync/sync.service.abstraction"; import { CipherType } from "@bitwarden/common/enums/cipherType"; import { TreeNode } from "@bitwarden/common/models/domain/tree-node"; -import { CipherView } from "@bitwarden/common/models/view/cipher.view"; +import { CipherView } from "@bitwarden/common/models/view"; import { CollectionView } from "@bitwarden/common/models/view/collection.view"; import { FolderView } from "@bitwarden/common/models/view/folder.view"; diff --git a/apps/browser/src/popup/vault/vault-items.component.ts b/apps/browser/src/popup/vault/vault-items.component.ts index b7f63d6d71da..ce7238a13c3d 100644 --- a/apps/browser/src/popup/vault/vault-items.component.ts +++ b/apps/browser/src/popup/vault/vault-items.component.ts @@ -15,7 +15,7 @@ import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUti import { SearchService } from "@bitwarden/common/abstractions/search.service"; import { CipherType } from "@bitwarden/common/enums/cipherType"; import { TreeNode } from "@bitwarden/common/models/domain/tree-node"; -import { CipherView } from "@bitwarden/common/models/view/cipher.view"; +import { CipherView } from "@bitwarden/common/models/view"; import { CollectionView } from "@bitwarden/common/models/view/collection.view"; import { FolderView } from "@bitwarden/common/models/view/folder.view"; diff --git a/apps/browser/src/services/abstractions/autofill.service.ts b/apps/browser/src/services/abstractions/autofill.service.ts index c900875f5e40..bad174da4d6e 100644 --- a/apps/browser/src/services/abstractions/autofill.service.ts +++ b/apps/browser/src/services/abstractions/autofill.service.ts @@ -1,4 +1,4 @@ -import { CipherView } from "@bitwarden/common/models/view/cipher.view"; +import { CipherView } from "@bitwarden/common/models/view"; import AutofillField from "../../models/autofillField"; import AutofillForm from "../../models/autofillForm"; diff --git a/apps/browser/src/services/autofill.service.ts b/apps/browser/src/services/autofill.service.ts index 60bcf3100f8e..c172a449defc 100644 --- a/apps/browser/src/services/autofill.service.ts +++ b/apps/browser/src/services/autofill.service.ts @@ -7,7 +7,7 @@ import { CipherType } from "@bitwarden/common/enums/cipherType"; import { EventType } from "@bitwarden/common/enums/eventType"; import { FieldType } from "@bitwarden/common/enums/fieldType"; import { UriMatchType } from "@bitwarden/common/enums/uriMatchType"; -import { CipherView } from "@bitwarden/common/models/view/cipher.view"; +import { CipherView } from "@bitwarden/common/models/view"; import { FieldView } from "@bitwarden/common/models/view/field.view"; import { BrowserApi } from "../browser/browserApi"; diff --git a/apps/browser/src/services/vaultFilter.service.ts b/apps/browser/src/services/vaultFilter.service.ts index f8b2e37d0eaa..c24f63c1d88b 100644 --- a/apps/browser/src/services/vaultFilter.service.ts +++ b/apps/browser/src/services/vaultFilter.service.ts @@ -6,7 +6,7 @@ import { FolderService } from "@bitwarden/common/abstractions/folder/folder.serv import { OrganizationService } from "@bitwarden/common/abstractions/organization/organization.service.abstraction"; import { PolicyService } from "@bitwarden/common/abstractions/policy/policy.service.abstraction"; import { StateService } from "@bitwarden/common/abstractions/state.service"; -import { CipherView } from "@bitwarden/common/models/view/cipher.view"; +import { CipherView } from "@bitwarden/common/models/view"; export class VaultFilterService extends BaseVaultFilterService { vaultFilter: VaultFilter = new VaultFilter(); diff --git a/apps/cli/src/commands/get.command.ts b/apps/cli/src/commands/get.command.ts index 78e254466b28..61b67db6eacb 100644 --- a/apps/cli/src/commands/get.command.ts +++ b/apps/cli/src/commands/get.command.ts @@ -23,7 +23,7 @@ import { LoginUriExport } from "@bitwarden/common/models/export/login-uri.export import { LoginExport } from "@bitwarden/common/models/export/login.export"; import { SecureNoteExport } from "@bitwarden/common/models/export/secure-note.export"; import { ErrorResponse } from "@bitwarden/common/models/response/error.response"; -import { CipherView } from "@bitwarden/common/models/view/cipher.view"; +import { CipherView } from "@bitwarden/common/models/view"; import { CollectionView } from "@bitwarden/common/models/view/collection.view"; import { FolderView } from "@bitwarden/common/models/view/folder.view"; diff --git a/apps/cli/src/commands/list.command.ts b/apps/cli/src/commands/list.command.ts index 7f7793620fc2..3d3862bf59ff 100644 --- a/apps/cli/src/commands/list.command.ts +++ b/apps/cli/src/commands/list.command.ts @@ -13,7 +13,7 @@ import { CollectionResponse as ApiCollectionResponse, } from "@bitwarden/common/models/response/collection.response"; import { ListResponse as ApiListResponse } from "@bitwarden/common/models/response/list.response"; -import { CipherView } from "@bitwarden/common/models/view/cipher.view"; +import { CipherView } from "@bitwarden/common/models/view"; import { Response } from "../models/response"; import { CipherResponse } from "../models/response/cipher.response"; diff --git a/apps/cli/src/models/response/cipher.response.ts b/apps/cli/src/models/response/cipher.response.ts index 182bff6e7f22..61717346d41d 100644 --- a/apps/cli/src/models/response/cipher.response.ts +++ b/apps/cli/src/models/response/cipher.response.ts @@ -1,6 +1,6 @@ import { CipherType } from "@bitwarden/common/enums/cipherType"; import { CipherWithIdExport } from "@bitwarden/common/models/export/cipher-with-ids.export"; -import { CipherView } from "@bitwarden/common/models/view/cipher.view"; +import { CipherView } from "@bitwarden/common/models/view"; import { AttachmentResponse } from "./attachment.response"; import { BaseResponse } from "./base.response"; diff --git a/apps/cli/src/models/response/login.response.ts b/apps/cli/src/models/response/login.response.ts index 7aa6e9184d68..1c8e1bd04bb5 100644 --- a/apps/cli/src/models/response/login.response.ts +++ b/apps/cli/src/models/response/login.response.ts @@ -1,5 +1,5 @@ import { LoginExport } from "@bitwarden/common/models/export/login.export"; -import { LoginView } from "@bitwarden/common/models/view/login.view"; +import { LoginView } from "@bitwarden/common/models/view"; export class LoginResponse extends LoginExport { passwordRevisionDate: Date; diff --git a/apps/cli/src/models/response/password-history.response.ts b/apps/cli/src/models/response/password-history.response.ts index 32f8878a3809..9d1463105c63 100644 --- a/apps/cli/src/models/response/password-history.response.ts +++ b/apps/cli/src/models/response/password-history.response.ts @@ -1,4 +1,4 @@ -import { PasswordHistoryView } from "@bitwarden/common/models/view/password-history.view"; +import { PasswordHistoryView } from "@bitwarden/common/models/view"; export class PasswordHistoryResponse { lastUsedDate: Date; diff --git a/apps/desktop/src/app/vault/vault-items.component.ts b/apps/desktop/src/app/vault/vault-items.component.ts index 1bd039d69948..083a15d93ed6 100644 --- a/apps/desktop/src/app/vault/vault-items.component.ts +++ b/apps/desktop/src/app/vault/vault-items.component.ts @@ -2,7 +2,7 @@ import { Component } from "@angular/core"; import { VaultItemsComponent as BaseVaultItemsComponent } from "@bitwarden/angular/components/vault-items.component"; import { SearchService } from "@bitwarden/common/abstractions/search.service"; -import { CipherView } from "@bitwarden/common/models/view/cipher.view"; +import { CipherView } from "@bitwarden/common/models/view"; import { SearchBarService } from "../layout/search/search-bar.service"; diff --git a/apps/desktop/src/app/vault/vault.component.ts b/apps/desktop/src/app/vault/vault.component.ts index 930e557a890d..49e737b7823c 100644 --- a/apps/desktop/src/app/vault/vault.component.ts +++ b/apps/desktop/src/app/vault/vault.component.ts @@ -25,7 +25,7 @@ import { TotpService } from "@bitwarden/common/abstractions/totp.service"; import { CipherRepromptType } from "@bitwarden/common/enums/cipherRepromptType"; import { CipherType } from "@bitwarden/common/enums/cipherType"; import { EventType } from "@bitwarden/common/enums/eventType"; -import { CipherView } from "@bitwarden/common/models/view/cipher.view"; +import { CipherView } from "@bitwarden/common/models/view"; import { FolderView } from "@bitwarden/common/models/view/folder.view"; import { invokeMenu, RendererMenuItem } from "../../utils"; diff --git a/apps/desktop/src/app/vault/view.component.ts b/apps/desktop/src/app/vault/view.component.ts index 70f55d400a42..26f9e5a1b6e1 100644 --- a/apps/desktop/src/app/vault/view.component.ts +++ b/apps/desktop/src/app/vault/view.component.ts @@ -24,7 +24,7 @@ import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUti import { StateService } from "@bitwarden/common/abstractions/state.service"; import { TokenService } from "@bitwarden/common/abstractions/token.service"; import { TotpService } from "@bitwarden/common/abstractions/totp.service"; -import { CipherView } from "@bitwarden/common/models/view/cipher.view"; +import { CipherView } from "@bitwarden/common/models/view"; const BroadcasterSubscriptionId = "ViewComponent"; diff --git a/apps/desktop/src/services/encrypted-message-handler.service.ts b/apps/desktop/src/services/encrypted-message-handler.service.ts index 5f45118768e0..1fb2322235aa 100644 --- a/apps/desktop/src/services/encrypted-message-handler.service.ts +++ b/apps/desktop/src/services/encrypted-message-handler.service.ts @@ -8,9 +8,8 @@ import { PolicyService } from "@bitwarden/common/abstractions/policy/policy.serv import { AuthenticationStatus } from "@bitwarden/common/enums/authenticationStatus"; import { CipherType } from "@bitwarden/common/enums/cipherType"; import { PolicyType } from "@bitwarden/common/enums/policyType"; -import { CipherView } from "@bitwarden/common/models/view/cipher.view"; +import { CipherView, LoginView } from "@bitwarden/common/models/view"; import { LoginUriView } from "@bitwarden/common/models/view/login-uri.view"; -import { LoginView } from "@bitwarden/common/models/view/login.view"; import { DecryptedCommandData } from "../models/native-messaging/decrypted-command-data"; import { CredentialCreatePayload } from "../models/native-messaging/encrypted-message-payloads/credential-create-payload"; diff --git a/apps/web/src/app/organizations/settings/delete-organization.component.ts b/apps/web/src/app/organizations/settings/delete-organization.component.ts index 1857a94f4c95..05d3cb6ab853 100644 --- a/apps/web/src/app/organizations/settings/delete-organization.component.ts +++ b/apps/web/src/app/organizations/settings/delete-organization.component.ts @@ -9,7 +9,7 @@ import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUti import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification/userVerification.service.abstraction"; import { CipherType } from "@bitwarden/common/enums/cipherType"; import { Utils } from "@bitwarden/common/misc/utils"; -import { CipherView } from "@bitwarden/common/models/view/cipher.view"; +import { CipherView } from "@bitwarden/common/models/view"; import { Verification } from "@bitwarden/common/types/verification"; class CountBasedLocalizationKey { diff --git a/apps/web/src/app/organizations/tools/exposed-passwords-report.component.ts b/apps/web/src/app/organizations/tools/exposed-passwords-report.component.ts index 703ac038d727..e64821a7b0d7 100644 --- a/apps/web/src/app/organizations/tools/exposed-passwords-report.component.ts +++ b/apps/web/src/app/organizations/tools/exposed-passwords-report.component.ts @@ -8,7 +8,7 @@ import { MessagingService } from "@bitwarden/common/abstractions/messaging.servi import { OrganizationService } from "@bitwarden/common/abstractions/organization/organization.service.abstraction"; import { PasswordRepromptService } from "@bitwarden/common/abstractions/passwordReprompt.service"; import { Cipher } from "@bitwarden/common/models/domain/cipher"; -import { CipherView } from "@bitwarden/common/models/view/cipher.view"; +import { CipherView } from "@bitwarden/common/models/view"; // eslint-disable-next-line no-restricted-imports import { ExposedPasswordsReportComponent as BaseExposedPasswordsReportComponent } from "../../reports/pages/exposed-passwords-report.component"; diff --git a/apps/web/src/app/organizations/tools/inactive-two-factor-report.component.ts b/apps/web/src/app/organizations/tools/inactive-two-factor-report.component.ts index 5b6c3be08d24..c170d019d67d 100644 --- a/apps/web/src/app/organizations/tools/inactive-two-factor-report.component.ts +++ b/apps/web/src/app/organizations/tools/inactive-two-factor-report.component.ts @@ -7,7 +7,7 @@ import { LogService } from "@bitwarden/common/abstractions/log.service"; import { MessagingService } from "@bitwarden/common/abstractions/messaging.service"; import { OrganizationService } from "@bitwarden/common/abstractions/organization/organization.service.abstraction"; import { PasswordRepromptService } from "@bitwarden/common/abstractions/passwordReprompt.service"; -import { CipherView } from "@bitwarden/common/models/view/cipher.view"; +import { CipherView } from "@bitwarden/common/models/view"; // eslint-disable-next-line no-restricted-imports import { InactiveTwoFactorReportComponent as BaseInactiveTwoFactorReportComponent } from "../../reports/pages/inactive-two-factor-report.component"; diff --git a/apps/web/src/app/organizations/tools/reused-passwords-report.component.ts b/apps/web/src/app/organizations/tools/reused-passwords-report.component.ts index 1c43c7f748b7..52bfaa975187 100644 --- a/apps/web/src/app/organizations/tools/reused-passwords-report.component.ts +++ b/apps/web/src/app/organizations/tools/reused-passwords-report.component.ts @@ -8,7 +8,7 @@ import { OrganizationService } from "@bitwarden/common/abstractions/organization import { PasswordRepromptService } from "@bitwarden/common/abstractions/passwordReprompt.service"; import { StateService } from "@bitwarden/common/abstractions/state.service"; import { Cipher } from "@bitwarden/common/models/domain/cipher"; -import { CipherView } from "@bitwarden/common/models/view/cipher.view"; +import { CipherView } from "@bitwarden/common/models/view"; // eslint-disable-next-line no-restricted-imports import { ReusedPasswordsReportComponent as BaseReusedPasswordsReportComponent } from "../../reports/pages/reused-passwords-report.component"; diff --git a/apps/web/src/app/organizations/tools/unsecured-websites-report.component.ts b/apps/web/src/app/organizations/tools/unsecured-websites-report.component.ts index a2d46e6ae2a6..18d8765dc723 100644 --- a/apps/web/src/app/organizations/tools/unsecured-websites-report.component.ts +++ b/apps/web/src/app/organizations/tools/unsecured-websites-report.component.ts @@ -6,7 +6,7 @@ import { CipherService } from "@bitwarden/common/abstractions/cipher.service"; import { MessagingService } from "@bitwarden/common/abstractions/messaging.service"; import { OrganizationService } from "@bitwarden/common/abstractions/organization/organization.service.abstraction"; import { PasswordRepromptService } from "@bitwarden/common/abstractions/passwordReprompt.service"; -import { CipherView } from "@bitwarden/common/models/view/cipher.view"; +import { CipherView } from "@bitwarden/common/models/view"; // eslint-disable-next-line no-restricted-imports import { UnsecuredWebsitesReportComponent as BaseUnsecuredWebsitesReportComponent } from "../../reports/pages/unsecured-websites-report.component"; diff --git a/apps/web/src/app/organizations/tools/weak-passwords-report.component.ts b/apps/web/src/app/organizations/tools/weak-passwords-report.component.ts index ccf6bfb5e00c..6fc7b464d279 100644 --- a/apps/web/src/app/organizations/tools/weak-passwords-report.component.ts +++ b/apps/web/src/app/organizations/tools/weak-passwords-report.component.ts @@ -8,7 +8,7 @@ import { OrganizationService } from "@bitwarden/common/abstractions/organization import { PasswordGenerationService } from "@bitwarden/common/abstractions/passwordGeneration.service"; import { PasswordRepromptService } from "@bitwarden/common/abstractions/passwordReprompt.service"; import { Cipher } from "@bitwarden/common/models/domain/cipher"; -import { CipherView } from "@bitwarden/common/models/view/cipher.view"; +import { CipherView } from "@bitwarden/common/models/view"; // eslint-disable-next-line no-restricted-imports import { WeakPasswordsReportComponent as BaseWeakPasswordsReportComponent } from "../../reports/pages/weak-passwords-report.component"; diff --git a/apps/web/src/app/organizations/vault/add-edit.component.ts b/apps/web/src/app/organizations/vault/add-edit.component.ts index 6a03696c2ef0..fb3c76451b71 100644 --- a/apps/web/src/app/organizations/vault/add-edit.component.ts +++ b/apps/web/src/app/organizations/vault/add-edit.component.ts @@ -4,6 +4,7 @@ import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { AuditService } from "@bitwarden/common/abstractions/audit.service"; import { CipherService } from "@bitwarden/common/abstractions/cipher.service"; import { CollectionService } from "@bitwarden/common/abstractions/collection.service"; +import { CryptoService } from "@bitwarden/common/abstractions/crypto.service"; import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service"; import { FolderService } from "@bitwarden/common/abstractions/folder/folder.service.abstraction"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; @@ -17,7 +18,7 @@ import { PolicyService } from "@bitwarden/common/abstractions/policy/policy.serv import { StateService } from "@bitwarden/common/abstractions/state.service"; import { TotpService } from "@bitwarden/common/abstractions/totp.service"; import { CipherData } from "@bitwarden/common/models/data/cipher.data"; -import { Cipher } from "@bitwarden/common/models/domain/cipher"; +import { Cipher } from "@bitwarden/common/models/domain"; import { CipherCreateRequest } from "@bitwarden/common/models/request/cipher-create.request"; import { CipherRequest } from "@bitwarden/common/models/request/cipher.request"; @@ -28,7 +29,6 @@ import { AddEditComponent as BaseAddEditComponent } from "../../vault/add-edit.c templateUrl: "../../vault/add-edit.component.html", }) export class AddEditComponent extends BaseAddEditComponent { - originalCipher: Cipher = null; protected override componentName = "app-org-vault-add-edit"; constructor( @@ -47,7 +47,8 @@ export class AddEditComponent extends BaseAddEditComponent { policyService: PolicyService, logService: LogService, passwordRepromptService: PasswordRepromptService, - organizationService: OrganizationService + organizationService: OrganizationService, + cryptoService: CryptoService ) { super( cipherService, @@ -64,7 +65,8 @@ export class AddEditComponent extends BaseAddEditComponent { policyService, organizationService, logService, - passwordRepromptService + passwordRepromptService, + cryptoService ); } @@ -98,7 +100,6 @@ export class AddEditComponent extends BaseAddEditComponent { data.edit = true; const cipher = new Cipher(data); - this.originalCipher = cipher; return cipher; } @@ -106,7 +107,7 @@ export class AddEditComponent extends BaseAddEditComponent { if (!this.organization.canEditAnyCollection) { return super.encryptCipher(); } - return this.cipherService.encrypt(this.cipher, null, this.originalCipher); + return this.cryptoService.encryptView(this.cipher); } protected async saveCipher(cipher: Cipher) { diff --git a/apps/web/src/app/organizations/vault/attachments.component.ts b/apps/web/src/app/organizations/vault/attachments.component.ts index 79ed8e67b842..29a4b4d282ae 100644 --- a/apps/web/src/app/organizations/vault/attachments.component.ts +++ b/apps/web/src/app/organizations/vault/attachments.component.ts @@ -11,7 +11,7 @@ import { StateService } from "@bitwarden/common/abstractions/state.service"; import { CipherData } from "@bitwarden/common/models/data/cipher.data"; import { Cipher } from "@bitwarden/common/models/domain/cipher"; import { Organization } from "@bitwarden/common/models/domain/organization"; -import { AttachmentView } from "@bitwarden/common/models/view/attachment.view"; +import { AttachmentView } from "@bitwarden/common/models/view"; import { AttachmentsComponent as BaseAttachmentsComponent } from "../../vault/attachments.component"; diff --git a/apps/web/src/app/organizations/vault/collections.component.ts b/apps/web/src/app/organizations/vault/collections.component.ts index 59fb4c8d15ff..da0b10d6cecc 100644 --- a/apps/web/src/app/organizations/vault/collections.component.ts +++ b/apps/web/src/app/organizations/vault/collections.component.ts @@ -3,6 +3,7 @@ import { Component } from "@angular/core"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { CipherService } from "@bitwarden/common/abstractions/cipher.service"; import { CollectionService } from "@bitwarden/common/abstractions/collection.service"; +import { CryptoService } from "@bitwarden/common/abstractions/crypto.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"; @@ -26,9 +27,17 @@ export class CollectionsComponent extends BaseCollectionsComponent { i18nService: I18nService, cipherService: CipherService, private apiService: ApiService, - logService: LogService + logService: LogService, + cryptoService: CryptoService ) { - super(collectionService, platformUtilsService, i18nService, cipherService, logService); + super( + collectionService, + platformUtilsService, + i18nService, + cipherService, + logService, + cryptoService + ); this.allowSelectNone = true; } diff --git a/apps/web/src/app/organizations/vault/vault-items.component.ts b/apps/web/src/app/organizations/vault/vault-items.component.ts index e7ee2cb28e60..df921258e83d 100644 --- a/apps/web/src/app/organizations/vault/vault-items.component.ts +++ b/apps/web/src/app/organizations/vault/vault-items.component.ts @@ -12,7 +12,7 @@ import { SearchService } from "@bitwarden/common/abstractions/search.service"; import { StateService } from "@bitwarden/common/abstractions/state.service"; import { TokenService } from "@bitwarden/common/abstractions/token.service"; import { TotpService } from "@bitwarden/common/abstractions/totp.service"; -import { CipherView } from "@bitwarden/common/models/view/cipher.view"; +import { CipherView } from "@bitwarden/common/models/view"; import { VaultItemsComponent as BaseVaultItemsComponent } from "../../vault/vault-items.component"; diff --git a/apps/web/src/app/organizations/vault/vault.component.ts b/apps/web/src/app/organizations/vault/vault.component.ts index c175e42d785d..a7661e161f09 100644 --- a/apps/web/src/app/organizations/vault/vault.component.ts +++ b/apps/web/src/app/organizations/vault/vault.component.ts @@ -22,7 +22,7 @@ import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUti import { SyncService } from "@bitwarden/common/abstractions/sync/sync.service.abstraction"; import { CipherType } from "@bitwarden/common/enums/cipherType"; import { Organization } from "@bitwarden/common/models/domain/organization"; -import { CipherView } from "@bitwarden/common/models/view/cipher.view"; +import { CipherView } from "@bitwarden/common/models/view"; import { VaultService } from "../../vault/shared/vault.service"; import { EntityEventsComponent } from "../manage/entity-events.component"; diff --git a/apps/web/src/app/reports/pages/cipher-report.component.ts b/apps/web/src/app/reports/pages/cipher-report.component.ts index baec67eee351..9ea3809b4da2 100644 --- a/apps/web/src/app/reports/pages/cipher-report.component.ts +++ b/apps/web/src/app/reports/pages/cipher-report.component.ts @@ -5,7 +5,7 @@ import { MessagingService } from "@bitwarden/common/abstractions/messaging.servi import { PasswordRepromptService } from "@bitwarden/common/abstractions/passwordReprompt.service"; import { CipherRepromptType } from "@bitwarden/common/enums/cipherRepromptType"; import { Organization } from "@bitwarden/common/models/domain/organization"; -import { CipherView } from "@bitwarden/common/models/view/cipher.view"; +import { CipherView } from "@bitwarden/common/models/view"; import { AddEditComponent as OrgAddEditComponent } from "../../organizations/vault/add-edit.component"; import { AddEditComponent } from "../../vault/add-edit.component"; diff --git a/apps/web/src/app/reports/pages/exposed-passwords-report.component.ts b/apps/web/src/app/reports/pages/exposed-passwords-report.component.ts index 5f51baa00248..9d5c796b23b9 100644 --- a/apps/web/src/app/reports/pages/exposed-passwords-report.component.ts +++ b/apps/web/src/app/reports/pages/exposed-passwords-report.component.ts @@ -6,7 +6,7 @@ import { CipherService } from "@bitwarden/common/abstractions/cipher.service"; import { MessagingService } from "@bitwarden/common/abstractions/messaging.service"; import { PasswordRepromptService } from "@bitwarden/common/abstractions/passwordReprompt.service"; import { CipherType } from "@bitwarden/common/enums/cipherType"; -import { CipherView } from "@bitwarden/common/models/view/cipher.view"; +import { CipherView } from "@bitwarden/common/models/view"; import { CipherReportComponent } from "./cipher-report.component"; diff --git a/apps/web/src/app/reports/pages/inactive-two-factor-report.component.ts b/apps/web/src/app/reports/pages/inactive-two-factor-report.component.ts index 0beaa53035da..18eda2d19af4 100644 --- a/apps/web/src/app/reports/pages/inactive-two-factor-report.component.ts +++ b/apps/web/src/app/reports/pages/inactive-two-factor-report.component.ts @@ -7,7 +7,7 @@ import { MessagingService } from "@bitwarden/common/abstractions/messaging.servi import { PasswordRepromptService } from "@bitwarden/common/abstractions/passwordReprompt.service"; import { CipherType } from "@bitwarden/common/enums/cipherType"; import { Utils } from "@bitwarden/common/misc/utils"; -import { CipherView } from "@bitwarden/common/models/view/cipher.view"; +import { CipherView } from "@bitwarden/common/models/view"; import { CipherReportComponent } from "./cipher-report.component"; diff --git a/apps/web/src/app/reports/pages/reused-passwords-report.component.ts b/apps/web/src/app/reports/pages/reused-passwords-report.component.ts index adcfa0ec5c20..791fc5aeef49 100644 --- a/apps/web/src/app/reports/pages/reused-passwords-report.component.ts +++ b/apps/web/src/app/reports/pages/reused-passwords-report.component.ts @@ -6,7 +6,7 @@ import { MessagingService } from "@bitwarden/common/abstractions/messaging.servi import { PasswordRepromptService } from "@bitwarden/common/abstractions/passwordReprompt.service"; import { StateService } from "@bitwarden/common/abstractions/state.service"; import { CipherType } from "@bitwarden/common/enums/cipherType"; -import { CipherView } from "@bitwarden/common/models/view/cipher.view"; +import { CipherView } from "@bitwarden/common/models/view"; import { CipherReportComponent } from "./cipher-report.component"; diff --git a/apps/web/src/app/reports/pages/unsecured-websites-report.component.ts b/apps/web/src/app/reports/pages/unsecured-websites-report.component.ts index 3918116c2214..7414402bc014 100644 --- a/apps/web/src/app/reports/pages/unsecured-websites-report.component.ts +++ b/apps/web/src/app/reports/pages/unsecured-websites-report.component.ts @@ -5,7 +5,7 @@ import { CipherService } from "@bitwarden/common/abstractions/cipher.service"; import { MessagingService } from "@bitwarden/common/abstractions/messaging.service"; import { PasswordRepromptService } from "@bitwarden/common/abstractions/passwordReprompt.service"; import { CipherType } from "@bitwarden/common/enums/cipherType"; -import { CipherView } from "@bitwarden/common/models/view/cipher.view"; +import { CipherView } from "@bitwarden/common/models/view"; import { CipherReportComponent } from "./cipher-report.component"; diff --git a/apps/web/src/app/reports/pages/weak-passwords-report.component.ts b/apps/web/src/app/reports/pages/weak-passwords-report.component.ts index 6d7817842668..19f752048e0f 100644 --- a/apps/web/src/app/reports/pages/weak-passwords-report.component.ts +++ b/apps/web/src/app/reports/pages/weak-passwords-report.component.ts @@ -6,7 +6,7 @@ import { MessagingService } from "@bitwarden/common/abstractions/messaging.servi import { PasswordGenerationService } from "@bitwarden/common/abstractions/passwordGeneration.service"; import { PasswordRepromptService } from "@bitwarden/common/abstractions/passwordReprompt.service"; import { CipherType } from "@bitwarden/common/enums/cipherType"; -import { CipherView } from "@bitwarden/common/models/view/cipher.view"; +import { CipherView } from "@bitwarden/common/models/view"; import { BadgeTypes } from "@bitwarden/components"; import { CipherReportComponent } from "./cipher-report.component"; diff --git a/apps/web/src/app/settings/change-password.component.ts b/apps/web/src/app/settings/change-password.component.ts index ae9fcd4c88bc..33fb8b9bcd19 100644 --- a/apps/web/src/app/settings/change-password.component.ts +++ b/apps/web/src/app/settings/change-password.component.ts @@ -218,7 +218,7 @@ export class ChangePasswordComponent extends BaseChangePasswordComponent { continue; } - const cipher = await this.cipherService.encrypt(ciphers[i], encKey[0]); + const cipher = await ciphers[i].encrypt(this.encryptService, encKey[0]); request.ciphers.push(new CipherWithIdRequest(cipher)); } diff --git a/apps/web/src/app/settings/emergency-access-attachments.component.ts b/apps/web/src/app/settings/emergency-access-attachments.component.ts index 383078e33680..fc186919b9ff 100644 --- a/apps/web/src/app/settings/emergency-access-attachments.component.ts +++ b/apps/web/src/app/settings/emergency-access-attachments.component.ts @@ -9,7 +9,7 @@ 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 { StateService } from "@bitwarden/common/abstractions/state.service"; -import { AttachmentView } from "@bitwarden/common/models/view/attachment.view"; +import { AttachmentView } from "@bitwarden/common/models/view"; @Component({ selector: "emergency-access-attachments", diff --git a/apps/web/src/app/settings/emergency-access-view.component.ts b/apps/web/src/app/settings/emergency-access-view.component.ts index 6c314aabc310..ee0b9337d285 100644 --- a/apps/web/src/app/settings/emergency-access-view.component.ts +++ b/apps/web/src/app/settings/emergency-access-view.component.ts @@ -5,11 +5,12 @@ import { ModalService } from "@bitwarden/angular/services/modal.service"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { CipherService } from "@bitwarden/common/abstractions/cipher.service"; import { CryptoService } from "@bitwarden/common/abstractions/crypto.service"; +import { EncryptService } from "@bitwarden/common/abstractions/encrypt.service"; import { CipherData } from "@bitwarden/common/models/data/cipher.data"; import { Cipher } from "@bitwarden/common/models/domain/cipher"; import { SymmetricCryptoKey } from "@bitwarden/common/models/domain/symmetric-crypto-key"; import { EmergencyAccessViewResponse } from "@bitwarden/common/models/response/emergency-access.response"; -import { CipherView } from "@bitwarden/common/models/view/cipher.view"; +import { CipherView } from "@bitwarden/common/models/view"; import { EmergencyAccessAttachmentsComponent } from "./emergency-access-attachments.component"; import { EmergencyAddEditComponent } from "./emergency-add-edit.component"; @@ -35,7 +36,8 @@ export class EmergencyAccessViewComponent implements OnInit { private modalService: ModalService, private router: Router, private route: ActivatedRoute, - private apiService: ApiService + private apiService: ApiService, + private encryptService: EncryptService ) {} ngOnInit() { @@ -93,7 +95,11 @@ export class EmergencyAccessViewComponent implements OnInit { ciphers.forEach((cipherResponse) => { const cipherData = new CipherData(cipherResponse); const cipher = new Cipher(cipherData); - promises.push(cipher.decrypt(oldEncKey).then((c) => decCiphers.push(c))); + promises.push( + this.encryptService + .decryptDomain(CipherView, cipher, oldEncKey) + .then((c) => decCiphers.push(c)) + ); }); await Promise.all(promises); diff --git a/apps/web/src/app/settings/emergency-add-edit.component.ts b/apps/web/src/app/settings/emergency-add-edit.component.ts index 3e97067d6f9c..3264221e2f93 100644 --- a/apps/web/src/app/settings/emergency-add-edit.component.ts +++ b/apps/web/src/app/settings/emergency-add-edit.component.ts @@ -3,6 +3,7 @@ import { Component } from "@angular/core"; import { AuditService } from "@bitwarden/common/abstractions/audit.service"; import { CipherService } from "@bitwarden/common/abstractions/cipher.service"; import { CollectionService } from "@bitwarden/common/abstractions/collection.service"; +import { CryptoService } from "@bitwarden/common/abstractions/crypto.service"; import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service"; import { FolderService } from "@bitwarden/common/abstractions/folder/folder.service.abstraction"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; @@ -43,7 +44,8 @@ export class EmergencyAddEditComponent extends BaseAddEditComponent { policyService: PolicyService, passwordRepromptService: PasswordRepromptService, organizationService: OrganizationService, - logService: LogService + logService: LogService, + cryptoService: CryptoService ) { super( cipherService, @@ -60,7 +62,8 @@ export class EmergencyAddEditComponent extends BaseAddEditComponent { policyService, organizationService, logService, - passwordRepromptService + passwordRepromptService, + cryptoService ); } diff --git a/apps/web/src/app/settings/update-key.component.ts b/apps/web/src/app/settings/update-key.component.ts index 6221a33909cd..b846df9c2e0c 100644 --- a/apps/web/src/app/settings/update-key.component.ts +++ b/apps/web/src/app/settings/update-key.component.ts @@ -98,7 +98,7 @@ export class UpdateKeyComponent { if (ciphers[i].organizationId != null) { continue; } - const cipher = await this.cipherService.encrypt(ciphers[i], encKey[0]); + const cipher = await ciphers[i].encrypt(this.encryptService, encKey[0]); request.ciphers.push(new CipherWithIdRequest(cipher)); } diff --git a/apps/web/src/app/vault/add-edit.component.ts b/apps/web/src/app/vault/add-edit.component.ts index c17009fab9e4..435808316f80 100644 --- a/apps/web/src/app/vault/add-edit.component.ts +++ b/apps/web/src/app/vault/add-edit.component.ts @@ -4,6 +4,7 @@ import { AddEditComponent as BaseAddEditComponent } from "@bitwarden/angular/com import { AuditService } from "@bitwarden/common/abstractions/audit.service"; import { CipherService } from "@bitwarden/common/abstractions/cipher.service"; import { CollectionService } from "@bitwarden/common/abstractions/collection.service"; +import { CryptoService } from "@bitwarden/common/abstractions/crypto.service"; import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service"; import { FolderService } from "@bitwarden/common/abstractions/folder/folder.service.abstraction"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; @@ -18,7 +19,7 @@ import { StateService } from "@bitwarden/common/abstractions/state.service"; import { TotpService } from "@bitwarden/common/abstractions/totp.service"; import { CipherType } from "@bitwarden/common/enums/cipherType"; import { EventType } from "@bitwarden/common/enums/eventType"; -import { LoginUriView } from "@bitwarden/common/models/view/login-uri.view"; +import { LoginUriView } from "@bitwarden/common/models/view"; @Component({ selector: "app-vault-add-edit", @@ -55,7 +56,8 @@ export class AddEditComponent extends BaseAddEditComponent implements OnInit, On protected policyService: PolicyService, organizationService: OrganizationService, logService: LogService, - passwordRepromptService: PasswordRepromptService + passwordRepromptService: PasswordRepromptService, + cryptoService: CryptoService ) { super( cipherService, @@ -70,7 +72,8 @@ export class AddEditComponent extends BaseAddEditComponent implements OnInit, On policyService, logService, passwordRepromptService, - organizationService + organizationService, + cryptoService ); } diff --git a/apps/web/src/app/vault/attachments.component.ts b/apps/web/src/app/vault/attachments.component.ts index 63e1f8bf39fb..748cdd16b118 100644 --- a/apps/web/src/app/vault/attachments.component.ts +++ b/apps/web/src/app/vault/attachments.component.ts @@ -9,7 +9,7 @@ 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 { StateService } from "@bitwarden/common/abstractions/state.service"; -import { AttachmentView } from "@bitwarden/common/models/view/attachment.view"; +import { AttachmentView } from "@bitwarden/common/models/view"; @Component({ selector: "app-vault-attachments", diff --git a/apps/web/src/app/vault/bulk-share.component.ts b/apps/web/src/app/vault/bulk-share.component.ts index 74fa1a304357..3dbc5133c8db 100644 --- a/apps/web/src/app/vault/bulk-share.component.ts +++ b/apps/web/src/app/vault/bulk-share.component.ts @@ -7,7 +7,7 @@ import { LogService } from "@bitwarden/common/abstractions/log.service"; import { OrganizationService } from "@bitwarden/common/abstractions/organization/organization.service.abstraction"; import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; import { Organization } from "@bitwarden/common/models/domain/organization"; -import { CipherView } from "@bitwarden/common/models/view/cipher.view"; +import { CipherView } from "@bitwarden/common/models/view"; import { CollectionView } from "@bitwarden/common/models/view/collection.view"; import { Checkable, isChecked } from "@bitwarden/common/types/checkable"; diff --git a/apps/web/src/app/vault/collections.component.ts b/apps/web/src/app/vault/collections.component.ts index d169bb7b3325..065031420894 100644 --- a/apps/web/src/app/vault/collections.component.ts +++ b/apps/web/src/app/vault/collections.component.ts @@ -3,6 +3,7 @@ import { Component, OnDestroy } from "@angular/core"; import { CollectionsComponent as BaseCollectionsComponent } from "@bitwarden/angular/components/collections.component"; import { CipherService } from "@bitwarden/common/abstractions/cipher.service"; import { CollectionService } from "@bitwarden/common/abstractions/collection.service"; +import { CryptoService } from "@bitwarden/common/abstractions/crypto.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"; @@ -18,9 +19,17 @@ export class CollectionsComponent extends BaseCollectionsComponent implements On platformUtilsService: PlatformUtilsService, i18nService: I18nService, cipherService: CipherService, - logService: LogService + logService: LogService, + cryptoService: CryptoService ) { - super(collectionService, platformUtilsService, i18nService, cipherService, logService); + super( + collectionService, + platformUtilsService, + i18nService, + cipherService, + logService, + cryptoService + ); } ngOnDestroy() { diff --git a/apps/web/src/app/vault/share.component.ts b/apps/web/src/app/vault/share.component.ts index 2fd64268a83e..036715c74210 100644 --- a/apps/web/src/app/vault/share.component.ts +++ b/apps/web/src/app/vault/share.component.ts @@ -3,6 +3,7 @@ import { Component, OnDestroy } from "@angular/core"; import { ShareComponent as BaseShareComponent } from "@bitwarden/angular/components/share.component"; import { CipherService } from "@bitwarden/common/abstractions/cipher.service"; import { CollectionService } from "@bitwarden/common/abstractions/collection.service"; +import { CryptoService } from "@bitwarden/common/abstractions/crypto.service"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/abstractions/log.service"; import { OrganizationService } from "@bitwarden/common/abstractions/organization/organization.service.abstraction"; @@ -20,7 +21,8 @@ export class ShareComponent extends BaseShareComponent implements OnDestroy { i18nService: I18nService, cipherService: CipherService, organizationService: OrganizationService, - logService: LogService + logService: LogService, + cryptoService: CryptoService ) { super( collectionService, @@ -28,7 +30,8 @@ export class ShareComponent extends BaseShareComponent implements OnDestroy { i18nService, cipherService, logService, - organizationService + organizationService, + cryptoService ); } diff --git a/apps/web/src/app/vault/vault-items.component.ts b/apps/web/src/app/vault/vault-items.component.ts index e82007523cc7..d89abbc8ae50 100644 --- a/apps/web/src/app/vault/vault-items.component.ts +++ b/apps/web/src/app/vault/vault-items.component.ts @@ -16,7 +16,7 @@ import { CipherRepromptType } from "@bitwarden/common/enums/cipherRepromptType"; import { CipherType } from "@bitwarden/common/enums/cipherType"; import { EventType } from "@bitwarden/common/enums/eventType"; import { Organization } from "@bitwarden/common/models/domain/organization"; -import { CipherView } from "@bitwarden/common/models/view/cipher.view"; +import { CipherView } from "@bitwarden/common/models/view"; import { Icons } from "@bitwarden/components"; const MaxCheckedCount = 500; diff --git a/apps/web/src/app/vault/vault.component.ts b/apps/web/src/app/vault/vault.component.ts index 4113b3ab2722..7ec2f309307e 100644 --- a/apps/web/src/app/vault/vault.component.ts +++ b/apps/web/src/app/vault/vault.component.ts @@ -23,7 +23,7 @@ import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUti import { StateService } from "@bitwarden/common/abstractions/state.service"; import { SyncService } from "@bitwarden/common/abstractions/sync/sync.service.abstraction"; import { TokenService } from "@bitwarden/common/abstractions/token.service"; -import { CipherView } from "@bitwarden/common/models/view/cipher.view"; +import { CipherView } from "@bitwarden/common/models/view"; import { UpdateKeyComponent } from "../settings/update-key.component"; diff --git a/libs/angular/src/components/add-edit-custom-fields.component.ts b/libs/angular/src/components/add-edit-custom-fields.component.ts index 2be5e7d5a568..348dbd7af9d2 100644 --- a/libs/angular/src/components/add-edit-custom-fields.component.ts +++ b/libs/angular/src/components/add-edit-custom-fields.component.ts @@ -7,8 +7,7 @@ import { CipherType } from "@bitwarden/common/enums/cipherType"; import { EventType } from "@bitwarden/common/enums/eventType"; import { FieldType } from "@bitwarden/common/enums/fieldType"; import { Utils } from "@bitwarden/common/misc/utils"; -import { CipherView } from "@bitwarden/common/models/view/cipher.view"; -import { FieldView } from "@bitwarden/common/models/view/field.view"; +import { CipherView, FieldView } from "@bitwarden/common/models/view"; @Directive() export class AddEditCustomFieldsComponent implements OnChanges { diff --git a/libs/angular/src/components/add-edit.component.ts b/libs/angular/src/components/add-edit.component.ts index c7b73bbcce00..33d5df467ca4 100644 --- a/libs/angular/src/components/add-edit.component.ts +++ b/libs/angular/src/components/add-edit.component.ts @@ -4,6 +4,7 @@ import { Observable, Subject, takeUntil, concatMap } from "rxjs"; import { AuditService } from "@bitwarden/common/abstractions/audit.service"; import { CipherService } from "@bitwarden/common/abstractions/cipher.service"; import { CollectionService } from "@bitwarden/common/abstractions/collection.service"; +import { CryptoService } from "@bitwarden/common/abstractions/crypto.service"; import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service"; import { FolderService } from "@bitwarden/common/abstractions/folder/folder.service.abstraction"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; @@ -24,14 +25,16 @@ import { UriMatchType } from "@bitwarden/common/enums/uriMatchType"; import { Utils } from "@bitwarden/common/misc/utils"; import { Cipher } from "@bitwarden/common/models/domain/cipher"; import { Organization } from "@bitwarden/common/models/domain/organization"; -import { CardView } from "@bitwarden/common/models/view/card.view"; -import { CipherView } from "@bitwarden/common/models/view/cipher.view"; +import { + CardView, + CipherView, + IdentityView, + LoginView, + SecureNoteView, + LoginUriView, +} from "@bitwarden/common/models/view"; import { CollectionView } from "@bitwarden/common/models/view/collection.view"; import { FolderView } from "@bitwarden/common/models/view/folder.view"; -import { IdentityView } from "@bitwarden/common/models/view/identity.view"; -import { LoginUriView } from "@bitwarden/common/models/view/login-uri.view"; -import { LoginView } from "@bitwarden/common/models/view/login.view"; -import { SecureNoteView } from "@bitwarden/common/models/view/secure-note.view"; @Directive() export class AddEditComponent implements OnInit, OnDestroy { @@ -96,7 +99,8 @@ export class AddEditComponent implements OnInit, OnDestroy { protected policyService: PolicyService, private logService: LogService, protected passwordRepromptService: PasswordRepromptService, - private organizationService: OrganizationService + private organizationService: OrganizationService, + protected cryptoService: CryptoService ) { this.typeOptions = [ { name: i18nService.t("typeLogin"), value: CipherType.Login }, @@ -224,7 +228,7 @@ export class AddEditComponent implements OnInit, OnDestroy { if (this.cipher == null) { if (this.editMode) { const cipher = await this.loadCipher(); - this.cipher = await cipher.decrypt(); + this.cipher = await this.cryptoService.decryptDomain(CipherView, cipher); // Adjust Cipher Name if Cloning if (this.cloneMode) { @@ -594,7 +598,7 @@ export class AddEditComponent implements OnInit, OnDestroy { } protected encryptCipher() { - return this.cipherService.encrypt(this.cipher); + return this.cryptoService.encryptView(this.cipher); } protected saveCipher(cipher: Cipher) { diff --git a/libs/angular/src/components/attachments.component.ts b/libs/angular/src/components/attachments.component.ts index 8a8db676185a..3b4207e18530 100644 --- a/libs/angular/src/components/attachments.component.ts +++ b/libs/angular/src/components/attachments.component.ts @@ -11,8 +11,7 @@ import { StateService } from "@bitwarden/common/abstractions/state.service"; import { Cipher } from "@bitwarden/common/models/domain/cipher"; import { EncArrayBuffer } from "@bitwarden/common/models/domain/enc-array-buffer"; import { ErrorResponse } from "@bitwarden/common/models/response/error.response"; -import { AttachmentView } from "@bitwarden/common/models/view/attachment.view"; -import { CipherView } from "@bitwarden/common/models/view/cipher.view"; +import { CipherView, AttachmentView } from "@bitwarden/common/models/view"; @Directive() export class AttachmentsComponent implements OnInit { @@ -81,7 +80,7 @@ export class AttachmentsComponent implements OnInit { try { this.formPromise = this.saveCipherAttachment(files[0]); this.cipherDomain = await this.formPromise; - this.cipher = await this.cipherDomain.decrypt(); + this.cipher = await this.cryptoService.decryptDomain(CipherView, this.cipherDomain); this.platformUtilsService.showToast("success", null, this.i18nService.t("attachmentSaved")); this.onUploadedAttachment.emit(); } catch (e) { @@ -190,7 +189,7 @@ export class AttachmentsComponent implements OnInit { protected async init() { this.cipherDomain = await this.loadCipher(); - this.cipher = await this.cipherDomain.decrypt(); + this.cipher = await this.cryptoService.decryptDomain(CipherView, this.cipherDomain); this.hasUpdatedKey = await this.cryptoService.hasEncKey(); const canAccessPremium = await this.stateService.getCanAccessPremium(); @@ -253,7 +252,7 @@ export class AttachmentsComponent implements OnInit { decBuf, admin ); - this.cipher = await this.cipherDomain.decrypt(); + this.cipher = await this.cryptoService.decryptDomain(CipherView, this.cipherDomain); // 3. Delete old this.deletePromises[attachment.id] = this.deleteCipherAttachment(attachment.id); diff --git a/libs/angular/src/components/collections.component.ts b/libs/angular/src/components/collections.component.ts index 2265454ead04..43b281ca7269 100644 --- a/libs/angular/src/components/collections.component.ts +++ b/libs/angular/src/components/collections.component.ts @@ -2,11 +2,12 @@ import { Directive, EventEmitter, Input, OnInit, Output } from "@angular/core"; import { CipherService } from "@bitwarden/common/abstractions/cipher.service"; import { CollectionService } from "@bitwarden/common/abstractions/collection.service"; +import { CryptoService } from "@bitwarden/common/abstractions/crypto.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 { Cipher } from "@bitwarden/common/models/domain/cipher"; -import { CipherView } from "@bitwarden/common/models/view/cipher.view"; +import { CipherView } from "@bitwarden/common/models/view"; import { CollectionView } from "@bitwarden/common/models/view/collection.view"; @Directive() @@ -27,7 +28,8 @@ export class CollectionsComponent implements OnInit { protected platformUtilsService: PlatformUtilsService, protected i18nService: I18nService, protected cipherService: CipherService, - private logService: LogService + private logService: LogService, + private cryptoService: CryptoService ) {} async ngOnInit() { @@ -37,7 +39,7 @@ export class CollectionsComponent implements OnInit { async load() { this.cipherDomain = await this.loadCipher(); this.collectionIds = this.loadCipherCollections(); - this.cipher = await this.cipherDomain.decrypt(); + this.cipher = await this.cryptoService.decryptDomain(CipherView, this.cipherDomain); this.collections = await this.loadCollections(); this.collections.forEach((c) => ((c as any).checked = false)); diff --git a/libs/angular/src/components/icon.component.ts b/libs/angular/src/components/icon.component.ts index 1c9b5a8b5512..0758f2d2a944 100644 --- a/libs/angular/src/components/icon.component.ts +++ b/libs/angular/src/components/icon.component.ts @@ -4,7 +4,7 @@ import { EnvironmentService } from "@bitwarden/common/abstractions/environment.s import { StateService } from "@bitwarden/common/abstractions/state.service"; import { CipherType } from "@bitwarden/common/enums/cipherType"; import { Utils } from "@bitwarden/common/misc/utils"; -import { CipherView } from "@bitwarden/common/models/view/cipher.view"; +import { CipherView } from "@bitwarden/common/models/view"; /** * Provides a mapping from supported card brands to diff --git a/libs/angular/src/components/password-history.component.ts b/libs/angular/src/components/password-history.component.ts index 438596694111..9accd14bfc9c 100644 --- a/libs/angular/src/components/password-history.component.ts +++ b/libs/angular/src/components/password-history.component.ts @@ -1,9 +1,10 @@ import { Directive, OnInit } from "@angular/core"; import { CipherService } from "@bitwarden/common/abstractions/cipher.service"; +import { CryptoService } from "@bitwarden/common/abstractions/crypto.service"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; -import { PasswordHistoryView } from "@bitwarden/common/models/view/password-history.view"; +import { CipherView, PasswordHistoryView } from "@bitwarden/common/models/view"; @Directive() export class PasswordHistoryComponent implements OnInit { @@ -14,6 +15,7 @@ export class PasswordHistoryComponent implements OnInit { protected cipherService: CipherService, protected platformUtilsService: PlatformUtilsService, protected i18nService: I18nService, + protected cryptoService: CryptoService, private win: Window ) {} @@ -33,7 +35,7 @@ export class PasswordHistoryComponent implements OnInit { protected async init() { const cipher = await this.cipherService.get(this.cipherId); - const decCipher = await cipher.decrypt(); + const decCipher = await this.cryptoService.decryptDomain(CipherView, cipher); this.history = decCipher.passwordHistory == null ? [] : decCipher.passwordHistory; } } diff --git a/libs/angular/src/components/share.component.ts b/libs/angular/src/components/share.component.ts index e12aeb021130..f95c14a61d41 100644 --- a/libs/angular/src/components/share.component.ts +++ b/libs/angular/src/components/share.component.ts @@ -3,6 +3,7 @@ import { firstValueFrom, map, Observable, Subject, takeUntil } from "rxjs"; import { CipherService } from "@bitwarden/common/abstractions/cipher.service"; import { CollectionService } from "@bitwarden/common/abstractions/collection.service"; +import { CryptoService } from "@bitwarden/common/abstractions/crypto.service"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/abstractions/log.service"; import { @@ -13,7 +14,7 @@ import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUti import { OrganizationUserStatusType } from "@bitwarden/common/enums/organizationUserStatusType"; import { Utils } from "@bitwarden/common/misc/utils"; import { Organization } from "@bitwarden/common/models/domain/organization"; -import { CipherView } from "@bitwarden/common/models/view/cipher.view"; +import { CipherView } from "@bitwarden/common/models/view"; import { CollectionView } from "@bitwarden/common/models/view/collection.view"; import { Checkable, isChecked } from "@bitwarden/common/types/checkable"; @@ -38,7 +39,8 @@ export class ShareComponent implements OnInit, OnDestroy { protected i18nService: I18nService, protected cipherService: CipherService, private logService: LogService, - protected organizationService: OrganizationService + protected organizationService: OrganizationService, + private cryptoService: CryptoService ) {} async ngOnInit() { @@ -72,7 +74,7 @@ export class ShareComponent implements OnInit, OnDestroy { }); const cipherDomain = await this.cipherService.get(this.cipherId); - this.cipher = await cipherDomain.decrypt(); + this.cipher = await this.cryptoService.decryptDomain(CipherView, cipherDomain); this.filterCollections(); } @@ -100,7 +102,7 @@ export class ShareComponent implements OnInit, OnDestroy { } const cipherDomain = await this.cipherService.get(this.cipherId); - const cipherView = await cipherDomain.decrypt(); + const cipherView = await this.cryptoService.decryptDomain(CipherView, cipherDomain); const orgs = await firstValueFrom(this.organizations$); const orgName = orgs.find((o) => o.id === this.organizationId)?.name ?? this.i18nService.t("organization"); diff --git a/libs/angular/src/components/vault-items.component.ts b/libs/angular/src/components/vault-items.component.ts index 28df06890ad8..72763dd1ac4e 100644 --- a/libs/angular/src/components/vault-items.component.ts +++ b/libs/angular/src/components/vault-items.component.ts @@ -2,7 +2,7 @@ import { Directive, EventEmitter, Input, Output } from "@angular/core"; import { SearchService } from "@bitwarden/common/abstractions/search.service"; import { Organization } from "@bitwarden/common/models/domain/organization"; -import { CipherView } from "@bitwarden/common/models/view/cipher.view"; +import { CipherView } from "@bitwarden/common/models/view"; @Directive() export class VaultItemsComponent { diff --git a/libs/angular/src/components/view-custom-fields.component.ts b/libs/angular/src/components/view-custom-fields.component.ts index 46289fbc5ebc..178e28ea1b08 100644 --- a/libs/angular/src/components/view-custom-fields.component.ts +++ b/libs/angular/src/components/view-custom-fields.component.ts @@ -3,7 +3,7 @@ import { Directive, Input } from "@angular/core"; import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service"; import { EventType } from "@bitwarden/common/enums/eventType"; import { FieldType } from "@bitwarden/common/enums/fieldType"; -import { CipherView } from "@bitwarden/common/models/view/cipher.view"; +import { CipherView } from "@bitwarden/common/models/view"; import { FieldView } from "@bitwarden/common/models/view/field.view"; @Directive() diff --git a/libs/angular/src/components/view.component.ts b/libs/angular/src/components/view.component.ts index 243ca85ff97d..90e4ad40fe04 100644 --- a/libs/angular/src/components/view.component.ts +++ b/libs/angular/src/components/view.component.ts @@ -31,8 +31,8 @@ import { EventType } from "@bitwarden/common/enums/eventType"; import { FieldType } from "@bitwarden/common/enums/fieldType"; import { EncArrayBuffer } from "@bitwarden/common/models/domain/enc-array-buffer"; import { ErrorResponse } from "@bitwarden/common/models/response/error.response"; +import { CipherView } from "@bitwarden/common/models/view"; import { AttachmentView } from "@bitwarden/common/models/view/attachment.view"; -import { CipherView } from "@bitwarden/common/models/view/cipher.view"; import { FolderView } from "@bitwarden/common/models/view/folder.view"; import { LoginUriView } from "@bitwarden/common/models/view/login-uri.view"; @@ -112,7 +112,7 @@ export class ViewComponent implements OnDestroy, OnInit { this.cleanUp(); const cipher = await this.cipherService.get(this.cipherId); - this.cipher = await cipher.decrypt(); + this.cipher = await this.cryptoService.decryptDomain(CipherView, cipher); this.canAccessPremium = await this.stateService.getCanAccessPremium(); this.showPremiumRequiredTotp = this.cipher.login.totp && !this.canAccessPremium && !this.cipher.organizationUseTotp; diff --git a/libs/angular/src/pipes/search-ciphers.pipe.ts b/libs/angular/src/pipes/search-ciphers.pipe.ts index 4e98aee9e229..54349a0f2666 100644 --- a/libs/angular/src/pipes/search-ciphers.pipe.ts +++ b/libs/angular/src/pipes/search-ciphers.pipe.ts @@ -1,6 +1,6 @@ import { Pipe, PipeTransform } from "@angular/core"; -import { CipherView } from "@bitwarden/common/models/view/cipher.view"; +import { CipherView } from "@bitwarden/common/models/view"; @Pipe({ name: "searchCiphers", diff --git a/libs/angular/src/vault/vault-filter/models/vault-filter.model.spec.ts b/libs/angular/src/vault/vault-filter/models/vault-filter.model.spec.ts index 12d458a12782..7228086d9ba9 100644 --- a/libs/angular/src/vault/vault-filter/models/vault-filter.model.spec.ts +++ b/libs/angular/src/vault/vault-filter/models/vault-filter.model.spec.ts @@ -1,5 +1,5 @@ import { CipherType } from "@bitwarden/common/enums/cipherType"; -import { CipherView } from "@bitwarden/common/models/view/cipher.view"; +import { CipherView } from "@bitwarden/common/models/view"; import { VaultFilter } from "./vault-filter.model"; diff --git a/libs/angular/src/vault/vault-filter/models/vault-filter.model.ts b/libs/angular/src/vault/vault-filter/models/vault-filter.model.ts index 0fd0fcc6d09d..29fb6687667e 100644 --- a/libs/angular/src/vault/vault-filter/models/vault-filter.model.ts +++ b/libs/angular/src/vault/vault-filter/models/vault-filter.model.ts @@ -1,5 +1,5 @@ import { CipherType } from "@bitwarden/common/enums/cipherType"; -import { CipherView } from "@bitwarden/common/models/view/cipher.view"; +import { CipherView } from "@bitwarden/common/models/view"; import { CipherStatus } from "./cipher-status.model"; diff --git a/libs/common/spec/importers/chrome-csv-importer.spec.ts b/libs/common/spec/importers/chrome-csv-importer.spec.ts index 8e57965d6d9f..d0e93424fc8f 100644 --- a/libs/common/spec/importers/chrome-csv-importer.spec.ts +++ b/libs/common/spec/importers/chrome-csv-importer.spec.ts @@ -1,7 +1,5 @@ import { ChromeCsvImporter as Importer } from "@bitwarden/common/importers/chrome-csv-importer"; -import { CipherView } from "@bitwarden/common/models/view/cipher.view"; -import { LoginUriView } from "@bitwarden/common/models/view/login-uri.view"; -import { LoginView } from "@bitwarden/common/models/view/login.view"; +import { CipherView, LoginUriView, LoginView } from "@bitwarden/common/models/view"; import { data as androidData } from "./test-data/chrome-csv/android-data.csv"; import { data as simplePasswordData } from "./test-data/chrome-csv/simple-password-data.csv"; diff --git a/libs/common/spec/importers/firefox-csv-importer.spec.ts b/libs/common/spec/importers/firefox-csv-importer.spec.ts index e25535c5a2b0..3a1619111658 100644 --- a/libs/common/spec/importers/firefox-csv-importer.spec.ts +++ b/libs/common/spec/importers/firefox-csv-importer.spec.ts @@ -1,7 +1,5 @@ import { FirefoxCsvImporter as Importer } from "@bitwarden/common/importers/firefox-csv-importer"; -import { CipherView } from "@bitwarden/common/models/view/cipher.view"; -import { LoginUriView } from "@bitwarden/common/models/view/login-uri.view"; -import { LoginView } from "@bitwarden/common/models/view/login.view"; +import { CipherView, LoginUriView, LoginView } from "@bitwarden/common/models/view"; import { data as firefoxAccountsData } from "./test-data/firefox-csv/firefox-accounts-data.csv"; import { data as simplePasswordData } from "./test-data/firefox-csv/simple-password-data.csv"; diff --git a/libs/common/spec/importers/lastpass-csv-importer.spec.ts b/libs/common/spec/importers/lastpass-csv-importer.spec.ts index 8e5f5d8a55dc..55f99b9d7f20 100644 --- a/libs/common/spec/importers/lastpass-csv-importer.spec.ts +++ b/libs/common/spec/importers/lastpass-csv-importer.spec.ts @@ -2,8 +2,7 @@ import { CipherType } from "@bitwarden/common/enums/cipherType"; import { FieldType } from "@bitwarden/common/enums/fieldType"; import { LastPassCsvImporter as Importer } from "@bitwarden/common/importers/lastpass-csv-importer"; import { ImportResult } from "@bitwarden/common/models/domain/import-result"; -import { CipherView } from "@bitwarden/common/models/view/cipher.view"; -import { FieldView } from "@bitwarden/common/models/view/field.view"; +import { CipherView, FieldView } from "@bitwarden/common/models/view"; function baseExcept(result: ImportResult) { expect(result).not.toBeNull(); diff --git a/libs/common/spec/importers/myki-csv-importer.spec.ts b/libs/common/spec/importers/myki-csv-importer.spec.ts index b28e495cf8b1..0f7f00cc92e2 100644 --- a/libs/common/spec/importers/myki-csv-importer.spec.ts +++ b/libs/common/spec/importers/myki-csv-importer.spec.ts @@ -1,6 +1,6 @@ import { CipherType } from "@bitwarden/common/enums/cipherType"; import { MykiCsvImporter as Importer } from "@bitwarden/common/importers/myki-csv-importer"; -import { CipherView } from "@bitwarden/common/models/view/cipher.view"; +import { CipherView } from "@bitwarden/common/models/view"; import { userAccountData } from "./test-data/myki-csv/user-account.csv"; import { userCreditCardData } from "./test-data/myki-csv/user-credit-card.csv"; diff --git a/libs/common/spec/importers/nordpass-csv-importer.spec.ts b/libs/common/spec/importers/nordpass-csv-importer.spec.ts index b9ef3c32a5df..213bb077c6be 100644 --- a/libs/common/spec/importers/nordpass-csv-importer.spec.ts +++ b/libs/common/spec/importers/nordpass-csv-importer.spec.ts @@ -1,8 +1,7 @@ import { CipherType } from "@bitwarden/common/enums/cipherType"; import { SecureNoteType } from "@bitwarden/common/enums/secureNoteType"; import { NordPassCsvImporter as Importer } from "@bitwarden/common/importers/nordpass-csv-importer"; -import { CipherView } from "@bitwarden/common/models/view/cipher.view"; -import { IdentityView } from "@bitwarden/common/models/view/identity.view"; +import { CipherView, IdentityView } from "@bitwarden/common/models/view"; import { data as creditCardData } from "./test-data/nordpass-csv/nordpass.card.csv"; import { data as identityData } from "./test-data/nordpass-csv/nordpass.identity.csv"; diff --git a/libs/common/spec/importers/onepassword-1pux-importer.spec.ts b/libs/common/spec/importers/onepassword-1pux-importer.spec.ts index 98b9d6f1ddce..e692585278ec 100644 --- a/libs/common/spec/importers/onepassword-1pux-importer.spec.ts +++ b/libs/common/spec/importers/onepassword-1pux-importer.spec.ts @@ -3,7 +3,7 @@ import { FieldType } from "@bitwarden/common/enums/fieldType"; import { SecureNoteType } from "@bitwarden/common/enums/secureNoteType"; import { OnePassword1PuxImporter as Importer } from "@bitwarden/common/importers/onepassword/onepassword-1pux-importer"; import { Utils } from "@bitwarden/common/misc/utils"; -import { FieldView } from "@bitwarden/common/models/view/field.view"; +import { FieldView } from "@bitwarden/common/models/view"; import { APICredentialsData } from "./test-data/onepassword-1pux/api-credentials"; import { BankAccountData } from "./test-data/onepassword-1pux/bank-account"; diff --git a/libs/common/spec/importers/onepassword-mac-csv-importer.spec.ts b/libs/common/spec/importers/onepassword-mac-csv-importer.spec.ts index fc61d9760c95..71f119f1b802 100644 --- a/libs/common/spec/importers/onepassword-mac-csv-importer.spec.ts +++ b/libs/common/spec/importers/onepassword-mac-csv-importer.spec.ts @@ -1,6 +1,6 @@ import { CipherType } from "@bitwarden/common/enums/cipherType"; import { OnePasswordMacCsvImporter as Importer } from "@bitwarden/common/importers/onepassword/onepassword-mac-csv-importer"; -import { CipherView } from "@bitwarden/common/models/view/cipher.view"; +import { CipherView } from "@bitwarden/common/models/view"; import { data as creditCardData } from "./test-data/onepassword-csv/credit-card.mac.csv"; import { data as identityData } from "./test-data/onepassword-csv/identity.mac.csv"; diff --git a/libs/common/spec/importers/onepassword-win-csv-importer.spec.ts b/libs/common/spec/importers/onepassword-win-csv-importer.spec.ts index 5398f823ff03..e0ccdc8f05d8 100644 --- a/libs/common/spec/importers/onepassword-win-csv-importer.spec.ts +++ b/libs/common/spec/importers/onepassword-win-csv-importer.spec.ts @@ -1,8 +1,7 @@ import { CipherType } from "@bitwarden/common/enums/cipherType"; import { FieldType } from "@bitwarden/common/enums/fieldType"; import { OnePasswordWinCsvImporter as Importer } from "@bitwarden/common/importers/onepassword/onepassword-win-csv-importer"; -import { CipherView } from "@bitwarden/common/models/view/cipher.view"; -import { FieldView } from "@bitwarden/common/models/view/field.view"; +import { CipherView, FieldView } from "@bitwarden/common/models/view"; import { data as creditCardData } from "./test-data/onepassword-csv/credit-card.windows.csv"; import { data as identityData } from "./test-data/onepassword-csv/identity.windows.csv"; diff --git a/libs/common/spec/importers/safari-csv-importer.spec.ts b/libs/common/spec/importers/safari-csv-importer.spec.ts index 3bb0f614cec5..835acebe4306 100644 --- a/libs/common/spec/importers/safari-csv-importer.spec.ts +++ b/libs/common/spec/importers/safari-csv-importer.spec.ts @@ -1,7 +1,5 @@ import { SafariCsvImporter as Importer } from "@bitwarden/common/importers/safari-csv-importer"; -import { CipherView } from "@bitwarden/common/models/view/cipher.view"; -import { LoginUriView } from "@bitwarden/common/models/view/login-uri.view"; -import { LoginView } from "@bitwarden/common/models/view/login.view"; +import { CipherView, LoginUriView, LoginView } from "@bitwarden/common/models/view"; import { data as oldSimplePasswordData } from "./test-data/safari-csv/old-simple-password-data.csv"; import { data as simplePasswordData } from "./test-data/safari-csv/simple-password-data.csv"; diff --git a/libs/common/spec/models/domain/attachment.spec.ts b/libs/common/spec/models/domain/attachment.spec.ts deleted file mode 100644 index 50e5ee7cae03..000000000000 --- a/libs/common/spec/models/domain/attachment.spec.ts +++ /dev/null @@ -1,155 +0,0 @@ -import { mock, MockProxy } from "jest-mock-extended"; - -import { CryptoService } from "@bitwarden/common/abstractions/crypto.service"; -import { EncryptService } from "@bitwarden/common/abstractions/encrypt.service"; -import { AttachmentData } from "@bitwarden/common/models/data/attachment.data"; -import { Attachment } from "@bitwarden/common/models/domain/attachment"; -import { EncString } from "@bitwarden/common/models/domain/enc-string"; -import { SymmetricCryptoKey } from "@bitwarden/common/models/domain/symmetric-crypto-key"; -import { ContainerService } from "@bitwarden/common/services/container.service"; - -import { makeStaticByteArray, mockEnc, mockFromJson } from "../../utils"; - -describe("Attachment", () => { - let data: AttachmentData; - - beforeEach(() => { - data = { - id: "id", - url: "url", - fileName: "fileName", - key: "key", - size: "1100", - sizeName: "1.1 KB", - }; - }); - - it("Convert from empty", () => { - const data = new AttachmentData(); - const attachment = new Attachment(data); - - expect(attachment).toEqual({ - id: null, - url: null, - size: undefined, - sizeName: null, - key: null, - fileName: null, - }); - }); - - it("Convert", () => { - const attachment = new Attachment(data); - - expect(attachment).toEqual({ - size: "1100", - id: "id", - url: "url", - sizeName: "1.1 KB", - fileName: { encryptedString: "fileName", encryptionType: 0 }, - key: { encryptedString: "key", encryptionType: 0 }, - }); - }); - - it("toAttachmentData", () => { - const attachment = new Attachment(data); - expect(attachment.toAttachmentData()).toEqual(data); - }); - - describe("decrypt", () => { - let cryptoService: MockProxy; - let encryptService: MockProxy; - - beforeEach(() => { - cryptoService = mock(); - encryptService = mock(); - - (window as any).bitwardenContainerService = new ContainerService( - cryptoService, - encryptService - ); - }); - - it("expected output", async () => { - const attachment = new Attachment(); - attachment.id = "id"; - attachment.url = "url"; - attachment.size = "1100"; - attachment.sizeName = "1.1 KB"; - attachment.key = mockEnc("key"); - attachment.fileName = mockEnc("fileName"); - - encryptService.decryptToBytes.mockResolvedValue(makeStaticByteArray(32)); - - const view = await attachment.decrypt(null); - - expect(view).toEqual({ - id: "id", - url: "url", - size: "1100", - sizeName: "1.1 KB", - fileName: "fileName", - key: expect.any(SymmetricCryptoKey), - }); - }); - - describe("decrypts attachment.key", () => { - let attachment: Attachment; - - beforeEach(() => { - attachment = new Attachment(); - attachment.key = mock(); - }); - - it("uses the provided key without depending on CryptoService", async () => { - const providedKey = mock(); - - await attachment.decrypt(null, providedKey); - - expect(cryptoService.getKeyForUserEncryption).not.toHaveBeenCalled(); - expect(encryptService.decryptToBytes).toHaveBeenCalledWith(attachment.key, providedKey); - }); - - it("gets an organization key if required", async () => { - const orgKey = mock(); - cryptoService.getOrgKey.calledWith("orgId").mockResolvedValue(orgKey); - - await attachment.decrypt("orgId", null); - - expect(cryptoService.getOrgKey).toHaveBeenCalledWith("orgId"); - expect(encryptService.decryptToBytes).toHaveBeenCalledWith(attachment.key, orgKey); - }); - - it("gets the user's decryption key if required", async () => { - const userKey = mock(); - cryptoService.getKeyForUserEncryption.mockResolvedValue(userKey); - - await attachment.decrypt(null, null); - - expect(cryptoService.getKeyForUserEncryption).toHaveBeenCalled(); - expect(encryptService.decryptToBytes).toHaveBeenCalledWith(attachment.key, userKey); - }); - }); - }); - - describe("fromJSON", () => { - it("initializes nested objects", () => { - jest.spyOn(EncString, "fromJSON").mockImplementation(mockFromJson); - - const actual = Attachment.fromJSON({ - key: "myKey", - fileName: "myFileName", - }); - - expect(actual).toEqual({ - key: "myKey_fromJSON", - fileName: "myFileName_fromJSON", - }); - expect(actual).toBeInstanceOf(Attachment); - }); - - it("returns null if object is null", () => { - expect(Attachment.fromJSON(null)).toBeNull(); - }); - }); -}); diff --git a/libs/common/spec/models/view/attachmentView.spec.ts b/libs/common/spec/models/view/attachmentView.spec.ts deleted file mode 100644 index de1b399d5d34..000000000000 --- a/libs/common/spec/models/view/attachmentView.spec.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { SymmetricCryptoKey } from "@bitwarden/common/models/domain/symmetric-crypto-key"; -import { AttachmentView } from "@bitwarden/common/models/view/attachment.view"; - -import { mockFromJson } from "../../utils"; - -jest.mock("@bitwarden/common/models/domain/symmetric-crypto-key"); - -describe("AttachmentView", () => { - it("fromJSON initializes nested objects", () => { - jest.spyOn(SymmetricCryptoKey, "fromJSON").mockImplementation(mockFromJson); - - const actual = AttachmentView.fromJSON({ - key: "encKeyB64" as any, - }); - - expect(actual.key).toEqual("encKeyB64_fromJSON"); - }); -}); diff --git a/libs/common/spec/models/view/cipherView.spec.ts b/libs/common/spec/models/view/cipherView.spec.ts deleted file mode 100644 index b58c82b15674..000000000000 --- a/libs/common/spec/models/view/cipherView.spec.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { CipherType } from "@bitwarden/common/enums/cipherType"; -import { AttachmentView } from "@bitwarden/common/models/view/attachment.view"; -import { CardView } from "@bitwarden/common/models/view/card.view"; -import { CipherView } from "@bitwarden/common/models/view/cipher.view"; -import { FieldView } from "@bitwarden/common/models/view/field.view"; -import { IdentityView } from "@bitwarden/common/models/view/identity.view"; -import { LoginView } from "@bitwarden/common/models/view/login.view"; -import { PasswordHistoryView } from "@bitwarden/common/models/view/password-history.view"; -import { SecureNoteView } from "@bitwarden/common/models/view/secure-note.view"; - -import { mockFromJson } from "../../utils"; - -jest.mock("@bitwarden/common/models/view/login.view"); -jest.mock("@bitwarden/common/models/view/attachment.view"); -jest.mock("@bitwarden/common/models/view/field.view"); -jest.mock("@bitwarden/common/models/view/password-history.view"); - -describe("CipherView", () => { - beforeEach(() => { - (LoginView as any).mockClear(); - (AttachmentView as any).mockClear(); - (FieldView as any).mockClear(); - (PasswordHistoryView as any).mockClear(); - }); - - describe("fromJSON", () => { - it("initializes nested objects", () => { - jest.spyOn(AttachmentView, "fromJSON").mockImplementation(mockFromJson); - jest.spyOn(FieldView, "fromJSON").mockImplementation(mockFromJson); - jest.spyOn(PasswordHistoryView, "fromJSON").mockImplementation(mockFromJson); - - const revisionDate = new Date("2022-08-04T01:06:40.441Z"); - const deletedDate = new Date("2022-09-04T01:06:40.441Z"); - const actual = CipherView.fromJSON({ - revisionDate: revisionDate.toISOString(), - deletedDate: deletedDate.toISOString(), - attachments: ["attachment1", "attachment2"] as any, - fields: ["field1", "field2"] as any, - passwordHistory: ["ph1", "ph2", "ph3"] as any, - }); - - const expected = { - revisionDate: revisionDate, - deletedDate: deletedDate, - attachments: ["attachment1_fromJSON", "attachment2_fromJSON"], - fields: ["field1_fromJSON", "field2_fromJSON"], - passwordHistory: ["ph1_fromJSON", "ph2_fromJSON", "ph3_fromJSON"], - }; - - expect(actual).toMatchObject(expected); - }); - - test.each([ - // Test description, CipherType, expected output - ["LoginView", CipherType.Login, { login: "myLogin_fromJSON" }], - ["CardView", CipherType.Card, { card: "myCard_fromJSON" }], - ["IdentityView", CipherType.Identity, { identity: "myIdentity_fromJSON" }], - ["Secure Note", CipherType.SecureNote, { secureNote: "mySecureNote_fromJSON" }], - ])("initializes %s", (description: string, cipherType: CipherType, expected: any) => { - jest.spyOn(LoginView, "fromJSON").mockImplementation(mockFromJson); - jest.spyOn(IdentityView, "fromJSON").mockImplementation(mockFromJson); - jest.spyOn(CardView, "fromJSON").mockImplementation(mockFromJson); - jest.spyOn(SecureNoteView, "fromJSON").mockImplementation(mockFromJson); - - const actual = CipherView.fromJSON({ - login: "myLogin", - card: "myCard", - identity: "myIdentity", - secureNote: "mySecureNote", - type: cipherType, - } as any); - - expect(actual).toMatchObject(expected); - }); - }); -}); diff --git a/libs/common/spec/models/view/passwordHistoryView.spec.ts b/libs/common/spec/models/view/passwordHistoryView.spec.ts deleted file mode 100644 index 514bc32b511a..000000000000 --- a/libs/common/spec/models/view/passwordHistoryView.spec.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { PasswordHistoryView } from "@bitwarden/common/models/view/password-history.view"; - -describe("PasswordHistoryView", () => { - it("fromJSON initializes nested objects", () => { - const lastUsedDate = new Date(); - - const actual = PasswordHistoryView.fromJSON({ - lastUsedDate: lastUsedDate.toISOString(), - }); - - expect(actual.lastUsedDate).toEqual(lastUsedDate); - }); -}); diff --git a/libs/common/spec/services/export.service.spec.ts b/libs/common/spec/services/export.service.spec.ts index 92dbd16883ed..ee606eee7dd4 100644 --- a/libs/common/spec/services/export.service.spec.ts +++ b/libs/common/spec/services/export.service.spec.ts @@ -9,14 +9,12 @@ import { FolderService } from "@bitwarden/common/abstractions/folder/folder.serv import { CipherType } from "@bitwarden/common/enums/cipherType"; import { KdfType } from "@bitwarden/common/enums/kdfType"; import { Utils } from "@bitwarden/common/misc/utils"; -import { Cipher } from "@bitwarden/common/models/domain/cipher"; +import { Login, Cipher } from "@bitwarden/common/models/domain"; import { EncString } from "@bitwarden/common/models/domain/enc-string"; import { Folder } from "@bitwarden/common/models/domain/folder"; -import { Login } from "@bitwarden/common/models/domain/login"; import { CipherWithIdExport as CipherExport } from "@bitwarden/common/models/export/cipher-with-ids.export"; -import { CipherView } from "@bitwarden/common/models/view/cipher.view"; +import { CipherView, LoginView } from "@bitwarden/common/models/view"; import { FolderView } from "@bitwarden/common/models/view/folder.view"; -import { LoginView } from "@bitwarden/common/models/view/login.view"; import { ExportService } from "@bitwarden/common/services/export.service"; import { BuildTestObject, GetUniqueString } from "../utils"; diff --git a/libs/common/spec/utils.ts b/libs/common/spec/utils.ts index 21b0f581e0cb..4a65a7c11ad4 100644 --- a/libs/common/spec/utils.ts +++ b/libs/common/spec/utils.ts @@ -25,6 +25,7 @@ export function BuildTestObject( export function mockEnc(s: string): EncString { const mock = Substitute.for(); mock.decrypt(Arg.any(), Arg.any()).resolves(s); + mock.decryptWithEncryptService(Arg.any(), Arg.any()).resolves(s); return mock; } diff --git a/libs/common/spec/view/login-uri-view.spec.ts b/libs/common/spec/view/login-uri-view.spec.ts index 7e29651b1ecc..a3e6ea8f595f 100644 --- a/libs/common/spec/view/login-uri-view.spec.ts +++ b/libs/common/spec/view/login-uri-view.spec.ts @@ -1,5 +1,5 @@ import { UriMatchType } from "@bitwarden/common/enums/uriMatchType"; -import { LoginUriView } from "@bitwarden/common/models/view/login-uri.view"; +import { LoginUriView } from "@bitwarden/common/models/view"; const testData = [ { diff --git a/libs/common/src/abstractions/cipher.service.ts b/libs/common/src/abstractions/cipher.service.ts index 457bbcd962b7..3809fe85206c 100644 --- a/libs/common/src/abstractions/cipher.service.ts +++ b/libs/common/src/abstractions/cipher.service.ts @@ -1,21 +1,11 @@ import { CipherType } from "../enums/cipherType"; import { UriMatchType } from "../enums/uriMatchType"; import { CipherData } from "../models/data/cipher.data"; -import { Cipher } from "../models/domain/cipher"; -import { Field } from "../models/domain/field"; -import { SymmetricCryptoKey } from "../models/domain/symmetric-crypto-key"; -import { CipherView } from "../models/view/cipher.view"; -import { FieldView } from "../models/view/field.view"; +import { Cipher } from "../models/domain"; +import { CipherView } from "../models/view"; export abstract class CipherService { clearCache: (userId?: string) => Promise; - encrypt: ( - model: CipherView, - key?: SymmetricCryptoKey, - originalCipher?: Cipher - ) => Promise; - encryptFields: (fieldsModel: FieldView[], key: SymmetricCryptoKey) => Promise; - encryptField: (fieldModel: FieldView, key: SymmetricCryptoKey) => Promise; get: (id: string) => Promise; getAll: () => Promise; getAllDecrypted: () => Promise; diff --git a/libs/common/src/abstractions/crypto.service.ts b/libs/common/src/abstractions/crypto.service.ts index 132a8462e6cd..33aef5b72d6d 100644 --- a/libs/common/src/abstractions/crypto.service.ts +++ b/libs/common/src/abstractions/crypto.service.ts @@ -93,6 +93,6 @@ export abstract class CryptoService { decryptDomain: (view: Decryptable, model: D) => Promise; encryptView: >>( - folder: V + view: V ) => Promise>; } diff --git a/libs/common/src/abstractions/encrypt.service.ts b/libs/common/src/abstractions/encrypt.service.ts index 8251bb39134a..4dbbb91be33b 100644 --- a/libs/common/src/abstractions/encrypt.service.ts +++ b/libs/common/src/abstractions/encrypt.service.ts @@ -5,7 +5,6 @@ import { Encryptable, EncryptableDomain, } from "../interfaces/crypto.interface"; -import { OldDecryptable } from "../interfaces/decryptable.interface"; import { InitializerMetadata } from "../interfaces/initializer-metadata.interface"; import { EncArrayBuffer } from "../models/domain/enc-array-buffer"; import { EncString } from "../models/domain/enc-string"; @@ -20,10 +19,11 @@ export abstract class EncryptService { abstract decryptToUtf8: (encString: EncString, key: SymmetricCryptoKey) => Promise; abstract decryptToBytes: (encThing: IEncrypted, key: SymmetricCryptoKey) => Promise; abstract resolveLegacyKey: (key: SymmetricCryptoKey, encThing: IEncrypted) => SymmetricCryptoKey; - abstract decryptItems: ( - items: OldDecryptable[], + abstract decryptItems: ( + view: Decryptable & InitializerMetadata, + items: D[], key: SymmetricCryptoKey - ) => Promise; + ) => Promise; abstract encryptView: >>( view: V, diff --git a/libs/common/src/abstractions/search.service.ts b/libs/common/src/abstractions/search.service.ts index 02eba41c138a..27069f590995 100644 --- a/libs/common/src/abstractions/search.service.ts +++ b/libs/common/src/abstractions/search.service.ts @@ -1,4 +1,4 @@ -import { CipherView } from "../models/view/cipher.view"; +import { CipherView } from "../models/view"; import { SendView } from "../models/view/send.view"; export abstract class SearchService { diff --git a/libs/common/src/abstractions/state.service.ts b/libs/common/src/abstractions/state.service.ts index e7974e6852cd..e9b450e68af6 100644 --- a/libs/common/src/abstractions/state.service.ts +++ b/libs/common/src/abstractions/state.service.ts @@ -22,7 +22,7 @@ import { Policy } from "../models/domain/policy"; import { StorageOptions } from "../models/domain/storage-options"; import { SymmetricCryptoKey } from "../models/domain/symmetric-crypto-key"; import { WindowState } from "../models/domain/window-state"; -import { CipherView } from "../models/view/cipher.view"; +import { CipherView } from "../models/view"; import { CollectionView } from "../models/view/collection.view"; import { SendView } from "../models/view/send.view"; diff --git a/libs/common/src/importers/base-importer.ts b/libs/common/src/importers/base-importer.ts index dec6e2e715b7..b92e8b1bb951 100644 --- a/libs/common/src/importers/base-importer.ts +++ b/libs/common/src/importers/base-importer.ts @@ -6,13 +6,9 @@ import { FieldType } from "../enums/fieldType"; import { SecureNoteType } from "../enums/secureNoteType"; import { Utils } from "../misc/utils"; import { ImportResult } from "../models/domain/import-result"; -import { CipherView } from "../models/view/cipher.view"; +import { CipherView, FieldView, LoginUriView, LoginView, SecureNoteView } from "../models/view"; import { CollectionView } from "../models/view/collection.view"; -import { FieldView } from "../models/view/field.view"; import { FolderView } from "../models/view/folder.view"; -import { LoginUriView } from "../models/view/login-uri.view"; -import { LoginView } from "../models/view/login.view"; -import { SecureNoteView } from "../models/view/secure-note.view"; import { ConsoleLogService } from "../services/consoleLog.service"; export abstract class BaseImporter { diff --git a/libs/common/src/importers/bitwarden-csv-importer.ts b/libs/common/src/importers/bitwarden-csv-importer.ts index f5f2554789df..6f4dafe7f75b 100644 --- a/libs/common/src/importers/bitwarden-csv-importer.ts +++ b/libs/common/src/importers/bitwarden-csv-importer.ts @@ -3,11 +3,8 @@ import { CipherType } from "../enums/cipherType"; import { FieldType } from "../enums/fieldType"; import { SecureNoteType } from "../enums/secureNoteType"; import { ImportResult } from "../models/domain/import-result"; -import { CipherView } from "../models/view/cipher.view"; +import { CipherView, FieldView, LoginView, SecureNoteView } from "../models/view"; import { CollectionView } from "../models/view/collection.view"; -import { FieldView } from "../models/view/field.view"; -import { LoginView } from "../models/view/login.view"; -import { SecureNoteView } from "../models/view/secure-note.view"; import { BaseImporter } from "./base-importer"; import { Importer } from "./importer"; diff --git a/libs/common/src/importers/bitwarden-json-importer.ts b/libs/common/src/importers/bitwarden-json-importer.ts index 26ad0dd0e0d1..2cc28878b4e3 100644 --- a/libs/common/src/importers/bitwarden-json-importer.ts +++ b/libs/common/src/importers/bitwarden-json-importer.ts @@ -5,6 +5,7 @@ import { ImportResult } from "../models/domain/import-result"; import { CipherWithIdExport } from "../models/export/cipher-with-ids.export"; import { CollectionWithIdExport } from "../models/export/collection-with-id.export"; import { FolderWithIdExport } from "../models/export/folder-with-id.export"; +import { CipherView } from "../models/view"; import { FolderView } from "../models/view/folder.view"; import { BaseImporter } from "./base-importer"; @@ -111,7 +112,7 @@ export class BitwardenJsonImporter extends BaseImporter implements Importer { }); } - const view = await cipher.decrypt(); + const view = await this.cryptoService.decryptDomain(CipherView, cipher); this.cleanupCipher(view); this.result.ciphers.push(view); } diff --git a/libs/common/src/importers/dashlane/dashlane-csv-importer.ts b/libs/common/src/importers/dashlane/dashlane-csv-importer.ts index 46860fd4a8dc..e5f0627c4d47 100644 --- a/libs/common/src/importers/dashlane/dashlane-csv-importer.ts +++ b/libs/common/src/importers/dashlane/dashlane-csv-importer.ts @@ -1,10 +1,7 @@ import { CipherType } from "../../enums/cipherType"; import { SecureNoteType } from "../../enums/secureNoteType"; import { ImportResult } from "../../models/domain/import-result"; -import { CardView } from "../../models/view/card.view"; -import { CipherView } from "../../models/view/cipher.view"; -import { IdentityView } from "../../models/view/identity.view"; -import { LoginView } from "../../models/view/login.view"; +import { CardView, CipherView, IdentityView, LoginView } from "../../models/view"; import { BaseImporter } from "../base-importer"; import { Importer } from "../importer"; diff --git a/libs/common/src/importers/dashlane/dashlane-json-importer.ts b/libs/common/src/importers/dashlane/dashlane-json-importer.ts index d6812fe283d9..24f2c087a5cc 100644 --- a/libs/common/src/importers/dashlane/dashlane-json-importer.ts +++ b/libs/common/src/importers/dashlane/dashlane-json-importer.ts @@ -1,10 +1,7 @@ import { CipherType } from "../../enums/cipherType"; import { SecureNoteType } from "../../enums/secureNoteType"; import { ImportResult } from "../../models/domain/import-result"; -import { CardView } from "../../models/view/card.view"; -import { CipherView } from "../../models/view/cipher.view"; -import { IdentityView } from "../../models/view/identity.view"; -import { SecureNoteView } from "../../models/view/secure-note.view"; +import { CardView, CipherView, IdentityView, SecureNoteView } from "../../models/view"; import { BaseImporter } from "../base-importer"; import { Importer } from "../importer"; diff --git a/libs/common/src/importers/encryptr-csv-importer.ts b/libs/common/src/importers/encryptr-csv-importer.ts index 68449d6c979e..fc46dc2681d1 100644 --- a/libs/common/src/importers/encryptr-csv-importer.ts +++ b/libs/common/src/importers/encryptr-csv-importer.ts @@ -1,6 +1,6 @@ import { CipherType } from "../enums/cipherType"; import { ImportResult } from "../models/domain/import-result"; -import { CardView } from "../models/view/card.view"; +import { CardView } from "../models/view"; import { BaseImporter } from "./base-importer"; import { Importer } from "./importer"; diff --git a/libs/common/src/importers/enpass-csv-importer.ts b/libs/common/src/importers/enpass-csv-importer.ts index d913c439eeea..ab41bd82b643 100644 --- a/libs/common/src/importers/enpass-csv-importer.ts +++ b/libs/common/src/importers/enpass-csv-importer.ts @@ -1,8 +1,7 @@ import { CipherType } from "../enums/cipherType"; import { SecureNoteType } from "../enums/secureNoteType"; import { ImportResult } from "../models/domain/import-result"; -import { CardView } from "../models/view/card.view"; -import { SecureNoteView } from "../models/view/secure-note.view"; +import { CardView, SecureNoteView } from "../models/view"; import { BaseImporter } from "./base-importer"; import { Importer } from "./importer"; diff --git a/libs/common/src/importers/enpass-json-importer.ts b/libs/common/src/importers/enpass-json-importer.ts index 88778c8adef7..95c41c42c182 100644 --- a/libs/common/src/importers/enpass-json-importer.ts +++ b/libs/common/src/importers/enpass-json-importer.ts @@ -1,8 +1,7 @@ import { CipherType } from "../enums/cipherType"; import { FieldType } from "../enums/fieldType"; import { ImportResult } from "../models/domain/import-result"; -import { CardView } from "../models/view/card.view"; -import { CipherView } from "../models/view/cipher.view"; +import { CardView, CipherView } from "../models/view"; import { FolderView } from "../models/view/folder.view"; import { BaseImporter } from "./base-importer"; diff --git a/libs/common/src/importers/fsecure/fsecure-fsk-importer.ts b/libs/common/src/importers/fsecure/fsecure-fsk-importer.ts index c86c43640a12..84fbb0a9e6ba 100644 --- a/libs/common/src/importers/fsecure/fsecure-fsk-importer.ts +++ b/libs/common/src/importers/fsecure/fsecure-fsk-importer.ts @@ -1,7 +1,6 @@ import { CipherType } from "../../enums/cipherType"; import { ImportResult } from "../../models/domain/import-result"; -import { CardView } from "../../models/view/card.view"; -import { CipherView } from "../../models/view/cipher.view"; +import { CardView, CipherView } from "../../models/view"; import { BaseImporter } from "../base-importer"; import { Importer } from "../importer"; diff --git a/libs/common/src/importers/lastpass-csv-importer.ts b/libs/common/src/importers/lastpass-csv-importer.ts index e75be31f5466..9aabd55c06f9 100644 --- a/libs/common/src/importers/lastpass-csv-importer.ts +++ b/libs/common/src/importers/lastpass-csv-importer.ts @@ -1,12 +1,8 @@ import { CipherType } from "../enums/cipherType"; import { SecureNoteType } from "../enums/secureNoteType"; import { ImportResult } from "../models/domain/import-result"; -import { CardView } from "../models/view/card.view"; -import { CipherView } from "../models/view/cipher.view"; +import { CardView, CipherView, IdentityView, LoginView, SecureNoteView } from "../models/view"; import { FolderView } from "../models/view/folder.view"; -import { IdentityView } from "../models/view/identity.view"; -import { LoginView } from "../models/view/login.view"; -import { SecureNoteView } from "../models/view/secure-note.view"; import { BaseImporter } from "./base-importer"; import { Importer } from "./importer"; diff --git a/libs/common/src/importers/msecure-csv-importer.ts b/libs/common/src/importers/msecure-csv-importer.ts index cb17da5c17d9..3123b4d7ee59 100644 --- a/libs/common/src/importers/msecure-csv-importer.ts +++ b/libs/common/src/importers/msecure-csv-importer.ts @@ -1,7 +1,7 @@ import { CipherType } from "../enums/cipherType"; import { SecureNoteType } from "../enums/secureNoteType"; import { ImportResult } from "../models/domain/import-result"; -import { SecureNoteView } from "../models/view/secure-note.view"; +import { SecureNoteView } from "../models/view"; import { BaseImporter } from "./base-importer"; import { Importer } from "./importer"; diff --git a/libs/common/src/importers/myki-csv-importer.ts b/libs/common/src/importers/myki-csv-importer.ts index a56b0de4d3b7..9c041ad9d2fb 100644 --- a/libs/common/src/importers/myki-csv-importer.ts +++ b/libs/common/src/importers/myki-csv-importer.ts @@ -1,10 +1,7 @@ import { CipherType } from "../enums/cipherType"; import { SecureNoteType } from "../enums/secureNoteType"; import { ImportResult } from "../models/domain/import-result"; -import { CardView } from "../models/view/card.view"; -import { CipherView } from "../models/view/cipher.view"; -import { IdentityView } from "../models/view/identity.view"; -import { SecureNoteView } from "../models/view/secure-note.view"; +import { CardView, CipherView, IdentityView, SecureNoteView } from "../models/view"; import { BaseImporter } from "./base-importer"; import { Importer } from "./importer"; diff --git a/libs/common/src/importers/nordpass-csv-importer.ts b/libs/common/src/importers/nordpass-csv-importer.ts index cf6b73e13f33..9c365a56745f 100644 --- a/libs/common/src/importers/nordpass-csv-importer.ts +++ b/libs/common/src/importers/nordpass-csv-importer.ts @@ -1,8 +1,7 @@ import { CipherType } from "../enums/cipherType"; import { SecureNoteType } from "../enums/secureNoteType"; import { ImportResult } from "../models/domain/import-result"; -import { CipherView } from "../models/view/cipher.view"; -import { LoginView } from "../models/view/login.view"; +import { CipherView, LoginView } from "../models/view"; import { BaseImporter } from "./base-importer"; import { Importer } from "./importer"; diff --git a/libs/common/src/importers/onepassword/cipher-import-context.ts b/libs/common/src/importers/onepassword/cipher-import-context.ts index 4a8810205f1e..0da7834274a6 100644 --- a/libs/common/src/importers/onepassword/cipher-import-context.ts +++ b/libs/common/src/importers/onepassword/cipher-import-context.ts @@ -1,4 +1,4 @@ -import { CipherView } from "../../models/view/cipher.view"; +import { CipherView } from "../../models/view"; export class CipherImportContext { lowerProperty: string; diff --git a/libs/common/src/importers/onepassword/onepassword-1pif-importer.ts b/libs/common/src/importers/onepassword/onepassword-1pif-importer.ts index a0b6bb84bf87..a066bf6f58fc 100644 --- a/libs/common/src/importers/onepassword/onepassword-1pif-importer.ts +++ b/libs/common/src/importers/onepassword/onepassword-1pif-importer.ts @@ -2,11 +2,13 @@ import { CipherType } from "../../enums/cipherType"; import { FieldType } from "../../enums/fieldType"; import { SecureNoteType } from "../../enums/secureNoteType"; import { ImportResult } from "../../models/domain/import-result"; -import { CardView } from "../../models/view/card.view"; -import { CipherView } from "../../models/view/cipher.view"; -import { IdentityView } from "../../models/view/identity.view"; -import { PasswordHistoryView } from "../../models/view/password-history.view"; -import { SecureNoteView } from "../../models/view/secure-note.view"; +import { + CardView, + CipherView, + IdentityView, + PasswordHistoryView, + SecureNoteView, +} from "../../models/view"; import { BaseImporter } from "../base-importer"; import { Importer } from "../importer"; diff --git a/libs/common/src/importers/onepassword/onepassword-1pux-importer.ts b/libs/common/src/importers/onepassword/onepassword-1pux-importer.ts index 35027a1e90c7..b7143f56b2f7 100644 --- a/libs/common/src/importers/onepassword/onepassword-1pux-importer.ts +++ b/libs/common/src/importers/onepassword/onepassword-1pux-importer.ts @@ -3,12 +3,14 @@ import { CipherType } from "../../enums/cipherType"; import { FieldType } from "../../enums/fieldType"; import { SecureNoteType } from "../../enums/secureNoteType"; import { ImportResult } from "../../models/domain/import-result"; -import { CardView } from "../../models/view/card.view"; -import { CipherView } from "../../models/view/cipher.view"; -import { IdentityView } from "../../models/view/identity.view"; -import { LoginView } from "../../models/view/login.view"; -import { PasswordHistoryView } from "../../models/view/password-history.view"; -import { SecureNoteView } from "../../models/view/secure-note.view"; +import { + CardView, + CipherView, + IdentityView, + LoginView, + PasswordHistoryView, + SecureNoteView, +} from "../../models/view"; import { BaseImporter } from "../base-importer"; import { Importer } from "../importer"; diff --git a/libs/common/src/importers/onepassword/onepassword-csv-importer.ts b/libs/common/src/importers/onepassword/onepassword-csv-importer.ts index 12433c135f4d..2edbbf5ed3ae 100644 --- a/libs/common/src/importers/onepassword/onepassword-csv-importer.ts +++ b/libs/common/src/importers/onepassword/onepassword-csv-importer.ts @@ -1,7 +1,7 @@ import { CipherType } from "../../enums/cipherType"; import { FieldType } from "../../enums/fieldType"; import { ImportResult } from "../../models/domain/import-result"; -import { CipherView } from "../../models/view/cipher.view"; +import { CipherView } from "../../models/view"; import { BaseImporter } from "../base-importer"; import { Importer } from "../importer"; diff --git a/libs/common/src/importers/onepassword/onepassword-mac-csv-importer.ts b/libs/common/src/importers/onepassword/onepassword-mac-csv-importer.ts index 522e6b0ef45f..5822e8f9838e 100644 --- a/libs/common/src/importers/onepassword/onepassword-mac-csv-importer.ts +++ b/libs/common/src/importers/onepassword/onepassword-mac-csv-importer.ts @@ -1,7 +1,5 @@ import { CipherType } from "../../enums/cipherType"; -import { CardView } from "../../models/view/card.view"; -import { CipherView } from "../../models/view/cipher.view"; -import { IdentityView } from "../../models/view/identity.view"; +import { CardView, CipherView, IdentityView } from "../../models/view"; import { Importer } from "../importer"; import { IgnoredProperties, OnePasswordCsvImporter } from "./onepassword-csv-importer"; diff --git a/libs/common/src/importers/onepassword/onepassword-win-csv-importer.ts b/libs/common/src/importers/onepassword/onepassword-win-csv-importer.ts index 5f0bca1c8a24..a0be4825b6a0 100644 --- a/libs/common/src/importers/onepassword/onepassword-win-csv-importer.ts +++ b/libs/common/src/importers/onepassword/onepassword-win-csv-importer.ts @@ -1,8 +1,5 @@ import { CipherType } from "../../enums/cipherType"; -import { CardView } from "../../models/view/card.view"; -import { CipherView } from "../../models/view/cipher.view"; -import { IdentityView } from "../../models/view/identity.view"; -import { LoginView } from "../../models/view/login.view"; +import { CardView, CipherView, IdentityView, LoginView } from "../../models/view"; import { Importer } from "../importer"; import { CipherImportContext } from "./cipher-import-context"; diff --git a/libs/common/src/importers/passwordboss-json-importer.ts b/libs/common/src/importers/passwordboss-json-importer.ts index dc29edf117bb..5455fdcd4586 100644 --- a/libs/common/src/importers/passwordboss-json-importer.ts +++ b/libs/common/src/importers/passwordboss-json-importer.ts @@ -1,6 +1,6 @@ import { CipherType } from "../enums/cipherType"; import { ImportResult } from "../models/domain/import-result"; -import { CardView } from "../models/view/card.view"; +import { CardView } from "../models/view"; import { FolderView } from "../models/view/folder.view"; import { BaseImporter } from "./base-importer"; diff --git a/libs/common/src/importers/remembear-csv-importer.ts b/libs/common/src/importers/remembear-csv-importer.ts index 3ddb32714078..54807be90a51 100644 --- a/libs/common/src/importers/remembear-csv-importer.ts +++ b/libs/common/src/importers/remembear-csv-importer.ts @@ -1,6 +1,6 @@ import { CipherType } from "../enums/cipherType"; import { ImportResult } from "../models/domain/import-result"; -import { CardView } from "../models/view/card.view"; +import { CardView } from "../models/view"; import { BaseImporter } from "./base-importer"; import { Importer } from "./importer"; diff --git a/libs/common/src/importers/safeincloud-xml-importer.ts b/libs/common/src/importers/safeincloud-xml-importer.ts index 5d81a001aaa6..65cbb0ee6d76 100644 --- a/libs/common/src/importers/safeincloud-xml-importer.ts +++ b/libs/common/src/importers/safeincloud-xml-importer.ts @@ -2,10 +2,8 @@ import { CipherType } from "../enums/cipherType"; import { FieldType } from "../enums/fieldType"; import { SecureNoteType } from "../enums/secureNoteType"; import { ImportResult } from "../models/domain/import-result"; -import { CipherView } from "../models/view/cipher.view"; -import { FieldView } from "../models/view/field.view"; +import { CipherView, FieldView, SecureNoteView } from "../models/view"; import { FolderView } from "../models/view/folder.view"; -import { SecureNoteView } from "../models/view/secure-note.view"; import { BaseImporter } from "./base-importer"; import { Importer } from "./importer"; diff --git a/libs/common/src/importers/splashid-csv-importer.ts b/libs/common/src/importers/splashid-csv-importer.ts index 0270d91d1395..e40b07664ab7 100644 --- a/libs/common/src/importers/splashid-csv-importer.ts +++ b/libs/common/src/importers/splashid-csv-importer.ts @@ -1,5 +1,5 @@ import { ImportResult } from "../models/domain/import-result"; -import { CipherView } from "../models/view/cipher.view"; +import { CipherView } from "../models/view"; import { BaseImporter } from "./base-importer"; import { Importer } from "./importer"; diff --git a/libs/common/src/importers/truekey-csv-importer.ts b/libs/common/src/importers/truekey-csv-importer.ts index 8b65dbd5d9f6..8fb5a25729a1 100644 --- a/libs/common/src/importers/truekey-csv-importer.ts +++ b/libs/common/src/importers/truekey-csv-importer.ts @@ -1,8 +1,7 @@ import { CipherType } from "../enums/cipherType"; import { SecureNoteType } from "../enums/secureNoteType"; import { ImportResult } from "../models/domain/import-result"; -import { CardView } from "../models/view/card.view"; -import { SecureNoteView } from "../models/view/secure-note.view"; +import { CardView, SecureNoteView } from "../models/view"; import { BaseImporter } from "./base-importer"; import { Importer } from "./importer"; diff --git a/libs/common/src/importers/zohovault-csv-importer.ts b/libs/common/src/importers/zohovault-csv-importer.ts index 2d4def098ac0..80353a640490 100644 --- a/libs/common/src/importers/zohovault-csv-importer.ts +++ b/libs/common/src/importers/zohovault-csv-importer.ts @@ -1,5 +1,5 @@ import { ImportResult } from "../models/domain/import-result"; -import { CipherView } from "../models/view/cipher.view"; +import { CipherView } from "../models/view"; import { BaseImporter } from "./base-importer"; import { Importer } from "./importer"; diff --git a/libs/common/src/interfaces/crypto.interface.ts b/libs/common/src/interfaces/crypto.interface.ts index fab310dd968e..8c7de2fbc0e1 100644 --- a/libs/common/src/interfaces/crypto.interface.ts +++ b/libs/common/src/interfaces/crypto.interface.ts @@ -45,6 +45,7 @@ export interface Encryptable { */ export type Decryptable = { decrypt(encryptService: EncryptService, key: SymmetricCryptoKey, model: TDomain): Promise; + fromJSON(obj: any): TView; }; /** diff --git a/libs/common/src/interfaces/decryptable.interface.ts b/libs/common/src/interfaces/decryptable.interface.ts deleted file mode 100644 index 93994bc5067e..000000000000 --- a/libs/common/src/interfaces/decryptable.interface.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { SymmetricCryptoKey } from "../models/domain/symmetric-crypto-key"; - -import { InitializerMetadata } from "./initializer-metadata.interface"; - -/** - * An object that contains EncStrings and knows how to decrypt them. This is usually a domain object with the - * corresponding view object as the type argument. - * @example Cipher implements Decryptable - */ -export interface OldDecryptable - extends InitializerMetadata { - decrypt: (key?: SymmetricCryptoKey) => Promise; -} diff --git a/libs/common/src/models/domain/account.ts b/libs/common/src/models/domain/account.ts index 40de21b3b68e..f3c0e671aad3 100644 --- a/libs/common/src/models/domain/account.ts +++ b/libs/common/src/models/domain/account.ts @@ -15,7 +15,7 @@ import { PolicyData } from "../data/policy.data"; import { ProviderData } from "../data/provider.data"; import { SendData } from "../data/send.data"; import { ServerConfigData } from "../data/server-config.data"; -import { CipherView } from "../view/cipher.view"; +import { CipherView } from "../view"; import { CollectionView } from "../view/collection.view"; import { SendView } from "../view/send.view"; diff --git a/libs/common/src/models/domain/attachment.ts b/libs/common/src/models/domain/attachment.ts deleted file mode 100644 index a3fc69f55db6..000000000000 --- a/libs/common/src/models/domain/attachment.ts +++ /dev/null @@ -1,109 +0,0 @@ -import { Jsonify } from "type-fest"; - -import { Utils } from "../../misc/utils"; -import { AttachmentData } from "../data/attachment.data"; -import { AttachmentView } from "../view/attachment.view"; - -import Domain from "./domain-base"; -import { EncString } from "./enc-string"; -import { SymmetricCryptoKey } from "./symmetric-crypto-key"; - -export class Attachment extends Domain { - id: string; - url: string; - size: string; - sizeName: string; // Readable size, ex: "4.2 KB" or "1.43 GB" - key: EncString; - fileName: EncString; - - constructor(obj?: AttachmentData) { - super(); - if (obj == null) { - return; - } - - this.size = obj.size; - this.buildDomainModel( - this, - obj, - { - id: null, - url: null, - sizeName: null, - fileName: null, - key: null, - }, - ["id", "url", "sizeName"] - ); - } - - async decrypt(orgId: string, encKey?: SymmetricCryptoKey): Promise { - const view = await this.decryptObj( - new AttachmentView(this), - { - fileName: null, - }, - orgId, - encKey - ); - - if (this.key != null) { - view.key = await this.decryptAttachmentKey(orgId, encKey); - } - - return view; - } - - private async decryptAttachmentKey(orgId: string, encKey?: SymmetricCryptoKey) { - try { - if (encKey == null) { - encKey = await this.getKeyForDecryption(orgId); - } - - const encryptService = Utils.getContainerService().getEncryptService(); - const decValue = await encryptService.decryptToBytes(this.key, encKey); - return new SymmetricCryptoKey(decValue); - } catch (e) { - // TODO: error? - } - } - - private async getKeyForDecryption(orgId: string) { - const cryptoService = Utils.getContainerService().getCryptoService(); - return orgId != null - ? await cryptoService.getOrgKey(orgId) - : await cryptoService.getKeyForUserEncryption(); - } - - toAttachmentData(): AttachmentData { - const a = new AttachmentData(); - a.size = this.size; - this.buildDataModel( - this, - a, - { - id: null, - url: null, - sizeName: null, - fileName: null, - key: null, - }, - ["id", "url", "sizeName"] - ); - return a; - } - - static fromJSON(obj: Partial>): Attachment { - if (obj == null) { - return null; - } - - const key = EncString.fromJSON(obj.key); - const fileName = EncString.fromJSON(obj.fileName); - - return Object.assign(new Attachment(), obj, { - key, - fileName, - }); - } -} diff --git a/libs/common/src/models/domain/card.ts b/libs/common/src/models/domain/card.ts deleted file mode 100644 index 4b8ca113095b..000000000000 --- a/libs/common/src/models/domain/card.ts +++ /dev/null @@ -1,88 +0,0 @@ -import { Jsonify } from "type-fest"; - -import { CardData } from "../data/card.data"; -import { CardView } from "../view/card.view"; - -import Domain from "./domain-base"; -import { EncString } from "./enc-string"; -import { SymmetricCryptoKey } from "./symmetric-crypto-key"; - -export class Card extends Domain { - cardholderName: EncString; - brand: EncString; - number: EncString; - expMonth: EncString; - expYear: EncString; - code: EncString; - - constructor(obj?: CardData) { - super(); - if (obj == null) { - return; - } - - this.buildDomainModel( - this, - obj, - { - cardholderName: null, - brand: null, - number: null, - expMonth: null, - expYear: null, - code: null, - }, - [] - ); - } - - decrypt(orgId: string, encKey?: SymmetricCryptoKey): Promise { - return this.decryptObj( - new CardView(), - { - cardholderName: null, - brand: null, - number: null, - expMonth: null, - expYear: null, - code: null, - }, - orgId, - encKey - ); - } - - toCardData(): CardData { - const c = new CardData(); - this.buildDataModel(this, c, { - cardholderName: null, - brand: null, - number: null, - expMonth: null, - expYear: null, - code: null, - }); - return c; - } - - static fromJSON(obj: Partial>): Card { - if (obj == null) { - return null; - } - - const cardholderName = EncString.fromJSON(obj.cardholderName); - const brand = EncString.fromJSON(obj.brand); - const number = EncString.fromJSON(obj.number); - const expMonth = EncString.fromJSON(obj.expMonth); - const expYear = EncString.fromJSON(obj.expYear); - const code = EncString.fromJSON(obj.code); - return Object.assign(new Card(), obj, { - cardholderName, - brand, - number, - expMonth, - expYear, - code, - }); - } -} diff --git a/libs/common/src/models/domain/cipher/attachment.spec.ts b/libs/common/src/models/domain/cipher/attachment.spec.ts new file mode 100644 index 000000000000..020a97a0960d --- /dev/null +++ b/libs/common/src/models/domain/cipher/attachment.spec.ts @@ -0,0 +1,69 @@ +import { AttachmentData } from "../../data/attachment.data"; + +import { Attachment } from "./attachment"; + +describe("Attachment", () => { + let data: AttachmentData; + + beforeEach(() => { + data = { + id: "id", + url: "url", + fileName: "fileName", + key: "key", + size: "1100", + sizeName: "1.1 KB", + }; + }); + + it("Convert from empty", () => { + const data = new AttachmentData(); + const attachment = new Attachment(data); + + expect(attachment).toEqual({ + id: undefined, + url: undefined, + size: undefined, + sizeName: undefined, + key: null, + fileName: null, + }); + }); + + it("Convert", () => { + const attachment = new Attachment(data); + + expect(attachment).toEqual({ + size: "1100", + id: "id", + url: "url", + sizeName: "1.1 KB", + fileName: { encryptedString: "fileName", encryptionType: 0 }, + key: { encryptedString: "key", encryptionType: 0 }, + }); + }); + + it("toAttachmentData", () => { + const attachment = new Attachment(data); + expect(attachment.toAttachmentData()).toEqual(data); + }); + + describe("fromJSON", () => { + it("initializes nested objects", () => { + const actual = Attachment.fromJSON({ + key: "myKey", + fileName: "myFileName", + }); + + expect(actual).toEqual({ + key: { encryptedString: "myKey", encryptionType: 0 }, + fileName: { encryptedString: "myFileName", encryptionType: 0 }, + }); + expect(actual).toBeInstanceOf(Attachment); + }); + + it("returns null if object is null", () => { + expect(Attachment.fromJSON(null)).toBeNull(); + }); + }); +}); diff --git a/libs/common/src/models/domain/cipher/attachment.ts b/libs/common/src/models/domain/cipher/attachment.ts new file mode 100644 index 000000000000..2e36659333a6 --- /dev/null +++ b/libs/common/src/models/domain/cipher/attachment.ts @@ -0,0 +1,51 @@ +import { Jsonify } from "type-fest"; + +import { nullableFactory } from "../../../interfaces/crypto.interface"; +import { AttachmentData } from "../../data/attachment.data"; +import { EncString } from "../enc-string"; + +export class Attachment { + id: string; + url: string; + size: string; + sizeName: string; // Readable size, ex: "4.2 KB" or "1.43 GB" + key: EncString; + fileName: EncString; + + constructor(obj?: AttachmentData) { + if (obj == null) { + return; + } + + this.id = obj.id; + this.url = obj.url; + this.size = obj.size; + this.sizeName = obj.sizeName; + this.key = nullableFactory(EncString, obj.key); + this.fileName = nullableFactory(EncString, obj.fileName); + } + + toAttachmentData(): AttachmentData { + const data = new AttachmentData(); + + data.id = this.id; + data.url = this.url; + data.size = this.size; + data.sizeName = this.sizeName; + data.key = this.key?.encryptedString; + data.fileName = this.fileName?.encryptedString; + + return data; + } + + static fromJSON(obj: Partial>): Attachment { + if (obj == null) { + return null; + } + + return Object.assign(new Attachment(), obj, { + key: nullableFactory(EncString, obj.key), + fileName: nullableFactory(EncString, obj.fileName), + }); + } +} diff --git a/libs/common/spec/models/domain/card.spec.ts b/libs/common/src/models/domain/cipher/card.spec.ts similarity index 62% rename from libs/common/spec/models/domain/card.spec.ts rename to libs/common/src/models/domain/cipher/card.spec.ts index 8a734e36d917..bbce49430ae6 100644 --- a/libs/common/spec/models/domain/card.spec.ts +++ b/libs/common/src/models/domain/cipher/card.spec.ts @@ -1,8 +1,8 @@ -import { CardData } from "@bitwarden/common/models/data/card.data"; -import { Card } from "@bitwarden/common/models/domain/card"; -import { EncString } from "@bitwarden/common/models/domain/enc-string"; +import { mockFromJson } from "../../../../spec/utils"; +import { CardData } from "../../data/card.data"; +import { EncString } from "../enc-string"; -import { mockEnc, mockFromJson } from "../../utils"; +import { Card } from "./card"; describe("Card", () => { let data: CardData; @@ -50,28 +50,6 @@ describe("Card", () => { expect(card.toCardData()).toEqual(data); }); - it("Decrypt", async () => { - const card = new Card(); - card.cardholderName = mockEnc("cardHolder"); - card.brand = mockEnc("brand"); - card.number = mockEnc("number"); - card.expMonth = mockEnc("expMonth"); - card.expYear = mockEnc("expYear"); - card.code = mockEnc("code"); - - const view = await card.decrypt(null); - - expect(view).toEqual({ - _brand: "brand", - _number: "number", - _subTitle: null, - cardholderName: "cardHolder", - code: "code", - expMonth: "expMonth", - expYear: "expYear", - }); - }); - describe("fromJSON", () => { it("initializes nested objects", () => { jest.spyOn(EncString, "fromJSON").mockImplementation(mockFromJson); @@ -86,12 +64,12 @@ describe("Card", () => { }); expect(actual).toEqual({ - cardholderName: "mockCardHolder_fromJSON", - brand: "mockBrand_fromJSON", - number: "mockNumber_fromJSON", - expMonth: "mockExpMonth_fromJSON", - expYear: "mockExpYear_fromJSON", - code: "mockCode_fromJSON", + cardholderName: { encryptedString: "mockCardHolder", encryptionType: 0 }, + brand: { encryptedString: "mockBrand", encryptionType: 0 }, + number: { encryptedString: "mockNumber", encryptionType: 0 }, + expMonth: { encryptedString: "mockExpMonth", encryptionType: 0 }, + expYear: { encryptedString: "mockExpYear", encryptionType: 0 }, + code: { encryptedString: "mockCode", encryptionType: 0 }, }); expect(actual).toBeInstanceOf(Card); }); diff --git a/libs/common/src/models/domain/cipher/card.ts b/libs/common/src/models/domain/cipher/card.ts new file mode 100644 index 000000000000..530b0acd7384 --- /dev/null +++ b/libs/common/src/models/domain/cipher/card.ts @@ -0,0 +1,62 @@ +import { Jsonify } from "type-fest"; + +import { nullableFactory } from "../../../interfaces/crypto.interface"; +import { CardData } from "../../data/card.data"; +import { EncString } from "../enc-string"; + +export class Card { + cardholderName: EncString; + brand: EncString; + number: EncString; + expMonth: EncString; + expYear: EncString; + code: EncString; + + constructor(obj?: CardData) { + if (obj == null) { + return; + } + + this.cardholderName = nullableFactory(EncString, obj.cardholderName); + this.brand = nullableFactory(EncString, obj.brand); + this.number = nullableFactory(EncString, obj.number); + this.expMonth = nullableFactory(EncString, obj.expMonth); + this.expYear = nullableFactory(EncString, obj.expYear); + this.code = nullableFactory(EncString, obj.code); + } + + toCardData(): CardData { + const data = new CardData(); + + data.cardholderName = this.cardholderName?.encryptedString; + data.brand = this.brand?.encryptedString; + data.number = this.number?.encryptedString; + data.expMonth = this.expMonth?.encryptedString; + data.expYear = this.expYear?.encryptedString; + data.code = this.code?.encryptedString; + + return data; + } + + static fromJSON(obj: Partial>): Card { + if (obj == null) { + return null; + } + + const cardholderName = nullableFactory(EncString, obj.cardholderName); + const brand = nullableFactory(EncString, obj.brand); + const number = nullableFactory(EncString, obj.number); + const expMonth = nullableFactory(EncString, obj.expMonth); + const expYear = nullableFactory(EncString, obj.expYear); + const code = nullableFactory(EncString, obj.code); + + return Object.assign(new Card(), obj, { + cardholderName, + brand, + number, + expMonth, + expYear, + code, + }); + } +} diff --git a/libs/common/spec/models/domain/cipher.spec.ts b/libs/common/src/models/domain/cipher/cipher.spec.ts similarity index 65% rename from libs/common/spec/models/domain/cipher.spec.ts rename to libs/common/src/models/domain/cipher/cipher.spec.ts index cd49ea5484ba..7fd0ad200a4b 100644 --- a/libs/common/spec/models/domain/cipher.spec.ts +++ b/libs/common/src/models/domain/cipher/cipher.spec.ts @@ -1,28 +1,23 @@ -// eslint-disable-next-line no-restricted-imports -import { Substitute, Arg } from "@fluffy-spoon/substitute"; import { Jsonify } from "type-fest"; -import { CipherRepromptType } from "@bitwarden/common/enums/cipherRepromptType"; -import { CipherType } from "@bitwarden/common/enums/cipherType"; -import { FieldType } from "@bitwarden/common/enums/fieldType"; -import { SecureNoteType } from "@bitwarden/common/enums/secureNoteType"; -import { UriMatchType } from "@bitwarden/common/enums/uriMatchType"; -import { CipherData } from "@bitwarden/common/models/data/cipher.data"; -import { Attachment } from "@bitwarden/common/models/domain/attachment"; -import { Card } from "@bitwarden/common/models/domain/card"; -import { Cipher } from "@bitwarden/common/models/domain/cipher"; -import { EncString } from "@bitwarden/common/models/domain/enc-string"; -import { Field } from "@bitwarden/common/models/domain/field"; -import { Identity } from "@bitwarden/common/models/domain/identity"; -import { Login } from "@bitwarden/common/models/domain/login"; -import { Password } from "@bitwarden/common/models/domain/password"; -import { SecureNote } from "@bitwarden/common/models/domain/secure-note"; -import { CardView } from "@bitwarden/common/models/view/card.view"; -import { IdentityView } from "@bitwarden/common/models/view/identity.view"; -import { LoginView } from "@bitwarden/common/models/view/login.view"; -import { InitializerKey } from "@bitwarden/common/services/cryptography/initializer-key"; - -import { mockEnc, mockFromJson } from "../../utils"; +import { mockFromJson } from "../../../../spec/utils"; +import { CipherRepromptType } from "../../../enums/cipherRepromptType"; +import { CipherType } from "../../../enums/cipherType"; +import { FieldType } from "../../../enums/fieldType"; +import { SecureNoteType } from "../../../enums/secureNoteType"; +import { UriMatchType } from "../../../enums/uriMatchType"; +import { InitializerKey } from "../../../services/cryptography/initializer-key"; +import { CipherData } from "../../data/cipher.data"; +import { EncString } from "../enc-string"; + +import { Attachment } from "./attachment"; +import { Card } from "./card"; +import { Cipher } from "./cipher"; +import { Field } from "./field"; +import { Identity } from "./identity"; +import { Login } from "./login"; +import { Password } from "./password"; +import { SecureNote } from "./secure-note"; describe("Cipher DTO", () => { it("Convert from empty CipherData", () => { @@ -31,9 +26,9 @@ describe("Cipher DTO", () => { expect(cipher).toEqual({ initializerKey: InitializerKey.Cipher, - id: null, - organizationId: null, - folderId: null, + id: undefined, + organizationId: undefined, + folderId: undefined, name: null, notes: null, type: undefined, @@ -192,57 +187,6 @@ describe("Cipher DTO", () => { const cipher = new Cipher(cipherData); expect(cipher.toCipherData()).toEqual(cipherData); }); - - it("Decrypt", async () => { - const cipher = new Cipher(); - cipher.id = "id"; - cipher.organizationId = "orgId"; - cipher.folderId = "folderId"; - cipher.edit = true; - cipher.viewPassword = true; - cipher.organizationUseTotp = true; - cipher.favorite = false; - cipher.revisionDate = new Date("2022-01-31T12:00:00.000Z"); - cipher.type = CipherType.Login; - cipher.name = mockEnc("EncryptedString"); - cipher.notes = mockEnc("EncryptedString"); - cipher.creationDate = new Date("2022-01-01T12:00:00.000Z"); - cipher.deletedDate = null; - cipher.reprompt = CipherRepromptType.None; - - const loginView = new LoginView(); - loginView.username = "username"; - loginView.password = "password"; - - const login = Substitute.for(); - login.decrypt(Arg.any(), Arg.any()).resolves(loginView); - cipher.login = login; - - const cipherView = await cipher.decrypt(); - - expect(cipherView).toMatchObject({ - id: "id", - organizationId: "orgId", - folderId: "folderId", - name: "EncryptedString", - notes: "EncryptedString", - type: 1, - favorite: false, - organizationUseTotp: true, - edit: true, - viewPassword: true, - login: loginView, - attachments: null, - fields: null, - passwordHistory: null, - collectionIds: undefined, - revisionDate: new Date("2022-01-31T12:00:00.000Z"), - creationDate: new Date("2022-01-01T12:00:00.000Z"), - deletedDate: null, - reprompt: 0, - localData: undefined, - }); - }); }); describe("SecureNoteCipher", () => { @@ -302,51 +246,6 @@ describe("Cipher DTO", () => { const cipher = new Cipher(cipherData); expect(cipher.toCipherData()).toEqual(cipherData); }); - - it("Decrypt", async () => { - const cipher = new Cipher(); - cipher.id = "id"; - cipher.organizationId = "orgId"; - cipher.folderId = "folderId"; - cipher.edit = true; - cipher.viewPassword = true; - cipher.organizationUseTotp = true; - cipher.favorite = false; - cipher.revisionDate = new Date("2022-01-31T12:00:00.000Z"); - cipher.type = CipherType.SecureNote; - cipher.name = mockEnc("EncryptedString"); - cipher.notes = mockEnc("EncryptedString"); - cipher.creationDate = new Date("2022-01-01T12:00:00.000Z"); - cipher.deletedDate = null; - cipher.reprompt = CipherRepromptType.None; - cipher.secureNote = new SecureNote(); - cipher.secureNote.type = SecureNoteType.Generic; - - const cipherView = await cipher.decrypt(); - - expect(cipherView).toMatchObject({ - id: "id", - organizationId: "orgId", - folderId: "folderId", - name: "EncryptedString", - notes: "EncryptedString", - type: 2, - favorite: false, - organizationUseTotp: true, - edit: true, - viewPassword: true, - secureNote: { type: 0 }, - attachments: null, - fields: null, - passwordHistory: null, - collectionIds: undefined, - revisionDate: new Date("2022-01-31T12:00:00.000Z"), - creationDate: new Date("2022-01-01T12:00:00.000Z"), - deletedDate: null, - reprompt: 0, - localData: undefined, - }); - }); }); describe("CardCipher", () => { @@ -418,57 +317,6 @@ describe("Cipher DTO", () => { const cipher = new Cipher(cipherData); expect(cipher.toCipherData()).toEqual(cipherData); }); - - it("Decrypt", async () => { - const cipher = new Cipher(); - cipher.id = "id"; - cipher.organizationId = "orgId"; - cipher.folderId = "folderId"; - cipher.edit = true; - cipher.viewPassword = true; - cipher.organizationUseTotp = true; - cipher.favorite = false; - cipher.revisionDate = new Date("2022-01-31T12:00:00.000Z"); - cipher.type = CipherType.Card; - cipher.name = mockEnc("EncryptedString"); - cipher.notes = mockEnc("EncryptedString"); - cipher.creationDate = new Date("2022-01-01T12:00:00.000Z"); - cipher.deletedDate = null; - cipher.reprompt = CipherRepromptType.None; - - const cardView = new CardView(); - cardView.cardholderName = "cardholderName"; - cardView.number = "4111111111111111"; - - const card = Substitute.for(); - card.decrypt(Arg.any(), Arg.any()).resolves(cardView); - cipher.card = card; - - const cipherView = await cipher.decrypt(); - - expect(cipherView).toMatchObject({ - id: "id", - organizationId: "orgId", - folderId: "folderId", - name: "EncryptedString", - notes: "EncryptedString", - type: 3, - favorite: false, - organizationUseTotp: true, - edit: true, - viewPassword: true, - card: cardView, - attachments: null, - fields: null, - passwordHistory: null, - collectionIds: undefined, - revisionDate: new Date("2022-01-31T12:00:00.000Z"), - creationDate: new Date("2022-01-01T12:00:00.000Z"), - deletedDate: null, - reprompt: 0, - localData: undefined, - }); - }); }); describe("IdentityCipher", () => { @@ -564,57 +412,6 @@ describe("Cipher DTO", () => { const cipher = new Cipher(cipherData); expect(cipher.toCipherData()).toEqual(cipherData); }); - - it("Decrypt", async () => { - const cipher = new Cipher(); - cipher.id = "id"; - cipher.organizationId = "orgId"; - cipher.folderId = "folderId"; - cipher.edit = true; - cipher.viewPassword = true; - cipher.organizationUseTotp = true; - cipher.favorite = false; - cipher.revisionDate = new Date("2022-01-31T12:00:00.000Z"); - cipher.type = CipherType.Identity; - cipher.name = mockEnc("EncryptedString"); - cipher.notes = mockEnc("EncryptedString"); - cipher.creationDate = new Date("2022-01-01T12:00:00.000Z"); - cipher.deletedDate = null; - cipher.reprompt = CipherRepromptType.None; - - const identityView = new IdentityView(); - identityView.firstName = "firstName"; - identityView.lastName = "lastName"; - - const identity = Substitute.for(); - identity.decrypt(Arg.any(), Arg.any()).resolves(identityView); - cipher.identity = identity; - - const cipherView = await cipher.decrypt(); - - expect(cipherView).toMatchObject({ - id: "id", - organizationId: "orgId", - folderId: "folderId", - name: "EncryptedString", - notes: "EncryptedString", - type: 4, - favorite: false, - organizationUseTotp: true, - edit: true, - viewPassword: true, - identity: identityView, - attachments: null, - fields: null, - passwordHistory: null, - collectionIds: undefined, - revisionDate: new Date("2022-01-31T12:00:00.000Z"), - creationDate: new Date("2022-01-01T12:00:00.000Z"), - deletedDate: null, - reprompt: 0, - localData: undefined, - }); - }); }); describe("fromJSON", () => { @@ -637,8 +434,14 @@ describe("Cipher DTO", () => { } as Jsonify); expect(actual).toMatchObject({ - name: "myName_fromJSON", - notes: "myNotes_fromJSON", + name: { + encryptedString: "myName", + encryptionType: 0, + }, + notes: { + encryptedString: "myNotes", + encryptionType: 0, + }, revisionDate: revisionDate, attachments: ["attachment1_fromJSON", "attachment2_fromJSON"], fields: ["field1_fromJSON", "field2_fromJSON"], diff --git a/libs/common/src/models/domain/cipher.ts b/libs/common/src/models/domain/cipher/cipher.ts similarity index 54% rename from libs/common/src/models/domain/cipher.ts rename to libs/common/src/models/domain/cipher/cipher.ts index 53e208ae1393..5d9913ddf74f 100644 --- a/libs/common/src/models/domain/cipher.ts +++ b/libs/common/src/models/domain/cipher/cipher.ts @@ -1,25 +1,23 @@ import { Jsonify } from "type-fest"; -import { CipherRepromptType } from "../../enums/cipherRepromptType"; -import { CipherType } from "../../enums/cipherType"; -import { OldDecryptable } from "../../interfaces/decryptable.interface"; -import { InitializerKey } from "../../services/cryptography/initializer-key"; -import { CipherData } from "../data/cipher.data"; -import { LocalData } from "../data/local.data"; -import { CipherView } from "../view/cipher.view"; +import { CipherRepromptType } from "../../../enums/cipherRepromptType"; +import { CipherType } from "../../../enums/cipherType"; +import { DecryptableDomain, nullableFactory } from "../../../interfaces/crypto.interface"; +import { InitializerMetadata } from "../../../interfaces/initializer-metadata.interface"; +import { InitializerKey } from "../../../services/cryptography/initializer-key"; +import { CipherData } from "../../data/cipher.data"; +import { LocalData } from "../../data/local.data"; +import { EncString } from "../enc-string"; import { Attachment } from "./attachment"; import { Card } from "./card"; -import Domain from "./domain-base"; -import { EncString } from "./enc-string"; import { Field } from "./field"; import { Identity } from "./identity"; import { Login } from "./login"; import { Password } from "./password"; import { SecureNote } from "./secure-note"; -import { SymmetricCryptoKey } from "./symmetric-crypto-key"; -export class Cipher extends Domain implements OldDecryptable { +export class Cipher implements DecryptableDomain, InitializerMetadata { readonly initializerKey = InitializerKey.Cipher; id: string; @@ -47,38 +45,25 @@ export class Cipher extends Domain implements OldDecryptable { reprompt: CipherRepromptType; constructor(obj?: CipherData, localData: LocalData = null) { - super(); if (obj == null) { return; } - this.buildDomainModel( - this, - obj, - { - id: null, - organizationId: null, - folderId: null, - name: null, - notes: null, - }, - ["id", "organizationId", "folderId"] - ); - + this.id = obj.id; + this.organizationId = obj.organizationId; + this.folderId = obj.folderId; + this.name = nullableFactory(EncString, obj.name); + this.notes = nullableFactory(EncString, obj.notes); this.type = obj.type; this.favorite = obj.favorite; this.organizationUseTotp = obj.organizationUseTotp; this.edit = obj.edit; - if (obj.viewPassword != null) { - this.viewPassword = obj.viewPassword; - } else { - this.viewPassword = true; // Default for already synced Ciphers without viewPassword - } - this.revisionDate = obj.revisionDate != null ? new Date(obj.revisionDate) : null; + this.viewPassword = obj.viewPassword ?? true; + this.revisionDate = nullableFactory(Date, obj.revisionDate); this.collectionIds = obj.collectionIds; this.localData = localData; - this.creationDate = obj.creationDate != null ? new Date(obj.creationDate) : null; - this.deletedDate = obj.deletedDate != null ? new Date(obj.deletedDate) : null; + this.creationDate = nullableFactory(Date, obj.creationDate); + this.deletedDate = nullableFactory(Date, obj.deletedDate); this.reprompt = obj.reprompt; switch (this.type) { @@ -117,83 +102,11 @@ export class Cipher extends Domain implements OldDecryptable { } } - async decrypt(encKey?: SymmetricCryptoKey): Promise { - const model = new CipherView(this); - - await this.decryptObj( - model, - { - name: null, - notes: null, - }, - this.organizationId, - encKey - ); - - switch (this.type) { - case CipherType.Login: - model.login = await this.login.decrypt(this.organizationId, encKey); - break; - case CipherType.SecureNote: - model.secureNote = await this.secureNote.decrypt(this.organizationId, encKey); - break; - case CipherType.Card: - model.card = await this.card.decrypt(this.organizationId, encKey); - break; - case CipherType.Identity: - model.identity = await this.identity.decrypt(this.organizationId, encKey); - break; - default: - break; - } - - const orgId = this.organizationId; - - if (this.attachments != null && this.attachments.length > 0) { - const attachments: any[] = []; - await this.attachments.reduce((promise, attachment) => { - return promise - .then(() => { - return attachment.decrypt(orgId, encKey); - }) - .then((decAttachment) => { - attachments.push(decAttachment); - }); - }, Promise.resolve()); - model.attachments = attachments; - } - - if (this.fields != null && this.fields.length > 0) { - const fields: any[] = []; - await this.fields.reduce((promise, field) => { - return promise - .then(() => { - return field.decrypt(orgId, encKey); - }) - .then((decField) => { - fields.push(decField); - }); - }, Promise.resolve()); - model.fields = fields; - } - - if (this.passwordHistory != null && this.passwordHistory.length > 0) { - const passwordHistory: any[] = []; - await this.passwordHistory.reduce((promise, ph) => { - return promise - .then(() => { - return ph.decrypt(orgId, encKey); - }) - .then((decPh) => { - passwordHistory.push(decPh); - }); - }, Promise.resolve()); - model.passwordHistory = passwordHistory; - } - - return model; + keyIdentifier(): string { + return this.organizationId || null; } + // TODO: This should be moved into the CipherData toCipherData(): CipherData { const c = new CipherData(); c.id = this.id; @@ -210,10 +123,8 @@ export class Cipher extends Domain implements OldDecryptable { c.deletedDate = this.deletedDate != null ? this.deletedDate.toISOString() : null; c.reprompt = this.reprompt; - this.buildDataModel(this, c, { - name: null, - notes: null, - }); + c.name = this.name?.encryptedString; + c.notes = this.notes?.encryptedString; switch (c.type) { case CipherType.Login: @@ -250,10 +161,10 @@ export class Cipher extends Domain implements OldDecryptable { } const domain = new Cipher(); - const name = EncString.fromJSON(obj.name); - const notes = EncString.fromJSON(obj.notes); - const revisionDate = obj.revisionDate == null ? null : new Date(obj.revisionDate); - const deletedDate = obj.deletedDate == null ? null : new Date(obj.deletedDate); + const name = nullableFactory(EncString, obj.name); + const notes = nullableFactory(EncString, obj.notes); + const revisionDate = nullableFactory(Date, obj.revisionDate); + const deletedDate = nullableFactory(Date, obj.deletedDate); const attachments = obj.attachments?.map((a: any) => Attachment.fromJSON(a)); const fields = obj.fields?.map((f: any) => Field.fromJSON(f)); const passwordHistory = obj.passwordHistory?.map((ph: any) => Password.fromJSON(ph)); diff --git a/libs/common/spec/models/domain/field.spec.ts b/libs/common/src/models/domain/cipher/field.spec.ts similarity index 62% rename from libs/common/spec/models/domain/field.spec.ts rename to libs/common/src/models/domain/cipher/field.spec.ts index 42f0addaf483..b38ce6e45980 100644 --- a/libs/common/spec/models/domain/field.spec.ts +++ b/libs/common/src/models/domain/cipher/field.spec.ts @@ -1,9 +1,9 @@ -import { FieldType } from "@bitwarden/common/enums/fieldType"; -import { FieldData } from "@bitwarden/common/models/data/field.data"; -import { EncString } from "@bitwarden/common/models/domain/enc-string"; -import { Field } from "@bitwarden/common/models/domain/field"; +import { mockFromJson } from "../../../../spec/utils"; +import { FieldType } from "../../../enums/fieldType"; +import { FieldData } from "../../data/field.data"; +import { EncString } from "../enc-string"; -import { mockEnc, mockFromJson } from "../../utils"; +import { Field } from "./field"; describe("Field", () => { let data: FieldData; @@ -45,24 +45,6 @@ describe("Field", () => { expect(field.toFieldData()).toEqual(data); }); - it("Decrypt", async () => { - const field = new Field(); - field.type = FieldType.Text; - field.name = mockEnc("encName"); - field.value = mockEnc("encValue"); - - const view = await field.decrypt(null); - - expect(view).toEqual({ - type: 0, - name: "encName", - value: "encValue", - newField: false, - showCount: false, - showValue: false, - }); - }); - describe("fromJSON", () => { it("initializes nested objects", () => { jest.spyOn(EncString, "fromJSON").mockImplementation(mockFromJson); @@ -73,8 +55,8 @@ describe("Field", () => { }); expect(actual).toEqual({ - name: "myName_fromJSON", - value: "myValue_fromJSON", + name: { encryptedString: "myName", encryptionType: 0 }, + value: { encryptedString: "myValue", encryptionType: 0 }, }); expect(actual).toBeInstanceOf(Field); }); diff --git a/libs/common/src/models/domain/cipher/field.ts b/libs/common/src/models/domain/cipher/field.ts new file mode 100644 index 000000000000..fce2a54da4e7 --- /dev/null +++ b/libs/common/src/models/domain/cipher/field.ts @@ -0,0 +1,47 @@ +import { Jsonify } from "type-fest"; + +import { FieldType } from "../../../enums/fieldType"; +import { LinkedIdType } from "../../../enums/linkedIdType"; +import { nullableFactory } from "../../../interfaces/crypto.interface"; +import { FieldData } from "../../data/field.data"; +import { EncString } from "../enc-string"; + +export class Field { + name: EncString; + value: EncString; + type: FieldType; + linkedId: LinkedIdType; + + constructor(obj?: FieldData) { + if (obj == null) { + return; + } + + this.type = obj.type; + this.linkedId = obj.linkedId; + this.name = nullableFactory(EncString, obj.name); + this.value = nullableFactory(EncString, obj.value); + } + + toFieldData(): FieldData { + const data = new FieldData(); + + data.type = this.type; + data.linkedId = this.linkedId; + data.name = this.name?.encryptedString; + data.value = this.value?.encryptedString; + + return data; + } + + static fromJSON(obj: Partial>): Field { + if (obj == null) { + return null; + } + + return Object.assign(new Field(), obj, { + name: nullableFactory(EncString, obj.name), + value: nullableFactory(EncString, obj.value), + }); + } +} diff --git a/libs/common/spec/models/domain/identity.spec.ts b/libs/common/src/models/domain/cipher/identity.spec.ts similarity index 57% rename from libs/common/spec/models/domain/identity.spec.ts rename to libs/common/src/models/domain/cipher/identity.spec.ts index 649da6aa885b..468ed99ab7c5 100644 --- a/libs/common/spec/models/domain/identity.spec.ts +++ b/libs/common/src/models/domain/cipher/identity.spec.ts @@ -1,8 +1,6 @@ -import { IdentityData } from "@bitwarden/common/models/data/identity.data"; -import { EncString } from "@bitwarden/common/models/domain/enc-string"; -import { Identity } from "@bitwarden/common/models/domain/identity"; +import { IdentityData } from "../../data/identity.data"; -import { mockEnc, mockFromJson } from "../../utils"; +import { Identity } from "./identity"; describe("Identity", () => { let data: IdentityData; @@ -86,57 +84,8 @@ describe("Identity", () => { expect(identity.toIdentityData()).toEqual(data); }); - it("Decrypt", async () => { - const identity = new Identity(); - - identity.title = mockEnc("mockTitle"); - identity.firstName = mockEnc("mockFirstName"); - identity.middleName = mockEnc("mockMiddleName"); - identity.lastName = mockEnc("mockLastName"); - identity.address1 = mockEnc("mockAddress1"); - identity.address2 = mockEnc("mockAddress2"); - identity.address3 = mockEnc("mockAddress3"); - identity.city = mockEnc("mockCity"); - identity.state = mockEnc("mockState"); - identity.postalCode = mockEnc("mockPostalCode"); - identity.country = mockEnc("mockCountry"); - identity.company = mockEnc("mockCompany"); - identity.email = mockEnc("mockEmail"); - identity.phone = mockEnc("mockPhone"); - identity.ssn = mockEnc("mockSsn"); - identity.username = mockEnc("mockUsername"); - identity.passportNumber = mockEnc("mockPassportNumber"); - identity.licenseNumber = mockEnc("mockLicenseNumber"); - - const view = await identity.decrypt(null); - - expect(view).toEqual({ - _firstName: "mockFirstName", - _lastName: "mockLastName", - _subTitle: null, - address1: "mockAddress1", - address2: "mockAddress2", - address3: "mockAddress3", - city: "mockCity", - company: "mockCompany", - country: "mockCountry", - email: "mockEmail", - licenseNumber: "mockLicenseNumber", - middleName: "mockMiddleName", - passportNumber: "mockPassportNumber", - phone: "mockPhone", - postalCode: "mockPostalCode", - ssn: "mockSsn", - state: "mockState", - title: "mockTitle", - username: "mockUsername", - }); - }); - describe("fromJSON", () => { it("initializes nested objects", () => { - jest.spyOn(EncString, "fromJSON").mockImplementation(mockFromJson); - const actual = Identity.fromJSON({ firstName: "mockFirstName", lastName: "mockLastName", @@ -159,24 +108,24 @@ describe("Identity", () => { }); expect(actual).toEqual({ - firstName: "mockFirstName_fromJSON", - lastName: "mockLastName_fromJSON", - address1: "mockAddress1_fromJSON", - address2: "mockAddress2_fromJSON", - address3: "mockAddress3_fromJSON", - city: "mockCity_fromJSON", - company: "mockCompany_fromJSON", - country: "mockCountry_fromJSON", - email: "mockEmail_fromJSON", - licenseNumber: "mockLicenseNumber_fromJSON", - middleName: "mockMiddleName_fromJSON", - passportNumber: "mockPassportNumber_fromJSON", - phone: "mockPhone_fromJSON", - postalCode: "mockPostalCode_fromJSON", - ssn: "mockSsn_fromJSON", - state: "mockState_fromJSON", - title: "mockTitle_fromJSON", - username: "mockUsername_fromJSON", + firstName: { encryptedString: "mockFirstName", encryptionType: 0 }, + lastName: { encryptedString: "mockLastName", encryptionType: 0 }, + address1: { encryptedString: "mockAddress1", encryptionType: 0 }, + address2: { encryptedString: "mockAddress2", encryptionType: 0 }, + address3: { encryptedString: "mockAddress3", encryptionType: 0 }, + city: { encryptedString: "mockCity", encryptionType: 0 }, + company: { encryptedString: "mockCompany", encryptionType: 0 }, + country: { encryptedString: "mockCountry", encryptionType: 0 }, + email: { encryptedString: "mockEmail", encryptionType: 0 }, + licenseNumber: { encryptedString: "mockLicenseNumber", encryptionType: 0 }, + middleName: { encryptedString: "mockMiddleName", encryptionType: 0 }, + passportNumber: { encryptedString: "mockPassportNumber", encryptionType: 0 }, + phone: { encryptedString: "mockPhone", encryptionType: 0 }, + postalCode: { encryptedString: "mockPostalCode", encryptionType: 0 }, + ssn: { encryptedString: "mockSsn", encryptionType: 0 }, + state: { encryptedString: "mockState", encryptionType: 0 }, + title: { encryptedString: "mockTitle", encryptionType: 0 }, + username: { encryptedString: "mockUsername", encryptionType: 0 }, }); expect(actual).toBeInstanceOf(Identity); }); diff --git a/libs/common/src/models/domain/cipher/identity.ts b/libs/common/src/models/domain/cipher/identity.ts new file mode 100644 index 000000000000..d955d06d2285 --- /dev/null +++ b/libs/common/src/models/domain/cipher/identity.ts @@ -0,0 +1,103 @@ +import { Jsonify } from "type-fest"; + +import { nullableFactory } from "../../../interfaces/crypto.interface"; +import { IdentityData } from "../../data/identity.data"; +import { EncString } from "../enc-string"; + +export class Identity { + title: EncString; + firstName: EncString; + middleName: EncString; + lastName: EncString; + address1: EncString; + address2: EncString; + address3: EncString; + city: EncString; + state: EncString; + postalCode: EncString; + country: EncString; + company: EncString; + email: EncString; + phone: EncString; + ssn: EncString; + username: EncString; + passportNumber: EncString; + licenseNumber: EncString; + + constructor(obj?: IdentityData) { + if (obj == null) { + return; + } + + this.title = nullableFactory(EncString, obj.title); + this.firstName = nullableFactory(EncString, obj.firstName); + this.middleName = nullableFactory(EncString, obj.middleName); + this.lastName = nullableFactory(EncString, obj.lastName); + this.address1 = nullableFactory(EncString, obj.address1); + this.address2 = nullableFactory(EncString, obj.address2); + this.address3 = nullableFactory(EncString, obj.address3); + this.city = nullableFactory(EncString, obj.city); + this.state = nullableFactory(EncString, obj.state); + this.postalCode = nullableFactory(EncString, obj.postalCode); + this.country = nullableFactory(EncString, obj.country); + this.company = nullableFactory(EncString, obj.company); + this.email = nullableFactory(EncString, obj.email); + this.phone = nullableFactory(EncString, obj.phone); + this.ssn = nullableFactory(EncString, obj.ssn); + this.username = nullableFactory(EncString, obj.username); + this.passportNumber = nullableFactory(EncString, obj.passportNumber); + this.licenseNumber = nullableFactory(EncString, obj.licenseNumber); + } + + toIdentityData(): IdentityData { + const data = new IdentityData(); + + data.title = this.title?.encryptedString; + data.firstName = this.firstName?.encryptedString; + data.middleName = this.middleName?.encryptedString; + data.lastName = this.lastName?.encryptedString; + data.address1 = this.address1?.encryptedString; + data.address2 = this.address2?.encryptedString; + data.address3 = this.address3?.encryptedString; + data.city = this.city?.encryptedString; + data.state = this.state?.encryptedString; + data.postalCode = this.postalCode?.encryptedString; + data.country = this.country?.encryptedString; + data.company = this.company?.encryptedString; + data.email = this.email?.encryptedString; + data.phone = this.phone?.encryptedString; + data.ssn = this.ssn?.encryptedString; + data.username = this.username?.encryptedString; + data.passportNumber = this.passportNumber?.encryptedString; + data.licenseNumber = this.licenseNumber?.encryptedString; + + return data; + } + + static fromJSON(obj: Jsonify): Identity { + if (obj == null) { + return null; + } + + return Object.assign(new Identity(), obj, { + title: nullableFactory(EncString, obj.title), + firstName: nullableFactory(EncString, obj.firstName), + middleName: nullableFactory(EncString, obj.middleName), + lastName: nullableFactory(EncString, obj.lastName), + address1: nullableFactory(EncString, obj.address1), + address2: nullableFactory(EncString, obj.address2), + address3: nullableFactory(EncString, obj.address3), + city: nullableFactory(EncString, obj.city), + state: nullableFactory(EncString, obj.state), + postalCode: nullableFactory(EncString, obj.postalCode), + country: nullableFactory(EncString, obj.country), + company: nullableFactory(EncString, obj.company), + email: nullableFactory(EncString, obj.email), + phone: nullableFactory(EncString, obj.phone), + ssn: nullableFactory(EncString, obj.ssn), + username: nullableFactory(EncString, obj.username), + passportNumber: nullableFactory(EncString, obj.passportNumber), + licenseNumber: nullableFactory(EncString, obj.licenseNumber), + }); + } +} diff --git a/libs/common/src/models/domain/cipher/index.ts b/libs/common/src/models/domain/cipher/index.ts new file mode 100644 index 000000000000..23b00c1c8642 --- /dev/null +++ b/libs/common/src/models/domain/cipher/index.ts @@ -0,0 +1,9 @@ +export * from "./attachment"; +export * from "./card"; +export * from "./cipher"; +export * from "./field"; +export * from "./identity"; +export * from "./login-uri"; +export * from "./login"; +export * from "./password"; +export * from "./secure-note"; diff --git a/libs/common/spec/models/domain/loginUri.spec.ts b/libs/common/src/models/domain/cipher/login-uri.spec.ts similarity index 72% rename from libs/common/spec/models/domain/loginUri.spec.ts rename to libs/common/src/models/domain/cipher/login-uri.spec.ts index 1a9f13c893a3..4f24dba78a96 100644 --- a/libs/common/spec/models/domain/loginUri.spec.ts +++ b/libs/common/src/models/domain/cipher/login-uri.spec.ts @@ -1,11 +1,11 @@ import { Jsonify } from "type-fest"; -import { UriMatchType } from "@bitwarden/common/enums/uriMatchType"; -import { LoginUriData } from "@bitwarden/common/models/data/login-uri.data"; -import { EncString } from "@bitwarden/common/models/domain/enc-string"; -import { LoginUri } from "@bitwarden/common/models/domain/login-uri"; +import { mockEnc } from "../../../../spec/utils"; +import { UriMatchType } from "../../../enums/uriMatchType"; +import { LoginUriData } from "../../data/login-uri.data"; +import { LoginUriView } from "../../view"; -import { mockEnc, mockFromJson } from "../../utils"; +import { LoginUri } from "./login-uri"; describe("LoginUri", () => { let data: LoginUriData; @@ -41,33 +41,17 @@ describe("LoginUri", () => { expect(loginUri.toLoginUriData()).toEqual(data); }); - it("Decrypt", async () => { - const loginUri = new LoginUri(); - loginUri.match = UriMatchType.Exact; - loginUri.uri = mockEnc("uri"); - - const view = await loginUri.decrypt(null); - - expect(view).toEqual({ - _canLaunch: null, - _domain: null, - _host: null, - _hostname: null, - _uri: "uri", - match: 3, - }); - }); - describe("fromJSON", () => { it("initializes nested objects", () => { - jest.spyOn(EncString, "fromJSON").mockImplementation(mockFromJson); - const actual = LoginUri.fromJSON({ uri: "myUri", } as Jsonify); expect(actual).toEqual({ - uri: "myUri_fromJSON", + uri: { + encryptedString: "myUri", + encryptionType: 0, + }, }); expect(actual).toBeInstanceOf(LoginUri); }); @@ -76,4 +60,21 @@ describe("LoginUri", () => { expect(LoginUri.fromJSON(null)).toBeNull(); }); }); + + it("decrypt", async () => { + const loginUri = new LoginUri(); + loginUri.match = UriMatchType.Exact; + loginUri.uri = mockEnc("uri"); + + const view = await LoginUriView.decrypt(null, null, loginUri); + + expect(view).toEqual({ + _canLaunch: null, + _domain: null, + _host: null, + _hostname: null, + _uri: "uri", + match: 3, + }); + }); }); diff --git a/libs/common/src/models/domain/cipher/login-uri.ts b/libs/common/src/models/domain/cipher/login-uri.ts new file mode 100644 index 000000000000..33b925d1ca1b --- /dev/null +++ b/libs/common/src/models/domain/cipher/login-uri.ts @@ -0,0 +1,40 @@ +import { Jsonify } from "type-fest"; + +import { UriMatchType } from "../../../enums/uriMatchType"; +import { nullableFactory } from "../../../interfaces/crypto.interface"; +import { LoginUriData } from "../../data/login-uri.data"; +import { EncString } from "../enc-string"; + +export class LoginUri { + uri: EncString; + match: UriMatchType; + + constructor(obj?: LoginUriData) { + if (obj == null) { + return; + } + + this.match = obj.match; + this.uri = nullableFactory(EncString, obj.uri); + } + + // TODO: This should be moved into the LoginUriData + toLoginUriData(): LoginUriData { + const u = new LoginUriData(); + + u.uri = this.uri?.encryptedString; + u.match = this.match; + + return u; + } + + static fromJSON(obj: Jsonify): LoginUri { + if (obj == null) { + return null; + } + + return Object.assign(new LoginUri(), obj, { + uri: nullableFactory(EncString, obj.uri), + }); + } +} diff --git a/libs/common/spec/models/domain/login.spec.ts b/libs/common/src/models/domain/cipher/login.spec.ts similarity index 57% rename from libs/common/spec/models/domain/login.spec.ts rename to libs/common/src/models/domain/cipher/login.spec.ts index 1e5950a9478c..9a8dc7a1a2a4 100644 --- a/libs/common/spec/models/domain/login.spec.ts +++ b/libs/common/src/models/domain/cipher/login.spec.ts @@ -1,14 +1,9 @@ -// eslint-disable-next-line no-restricted-imports -import { Substitute, Arg } from "@fluffy-spoon/substitute"; +import { mockFromJson } from "../../../../spec/utils"; +import { UriMatchType } from "../../../enums/uriMatchType"; +import { LoginData } from "../../data/login.data"; -import { UriMatchType } from "@bitwarden/common/enums/uriMatchType"; -import { LoginData } from "@bitwarden/common/models/data/login.data"; -import { EncString } from "@bitwarden/common/models/domain/enc-string"; -import { Login } from "@bitwarden/common/models/domain/login"; -import { LoginUri } from "@bitwarden/common/models/domain/login-uri"; -import { LoginUriView } from "@bitwarden/common/models/view/login-uri.view"; - -import { mockEnc, mockFromJson } from "../../utils"; +import { Login } from "./login"; +import { LoginUri } from "./login-uri"; describe("Login DTO", () => { it("Convert from empty LoginData", () => { @@ -51,40 +46,6 @@ describe("Login DTO", () => { expect(login).toEqual({}); }); - it("Decrypts correctly", async () => { - const loginUri = Substitute.for(); - const loginUriView = new LoginUriView(); - loginUriView.uri = "decrypted uri"; - loginUri.decrypt(Arg.any()).resolves(loginUriView); - - const login = new Login(); - login.uris = [loginUri]; - login.username = mockEnc("encrypted username"); - login.password = mockEnc("encrypted password"); - login.passwordRevisionDate = new Date("2022-01-31T12:00:00.000Z"); - login.totp = mockEnc("encrypted totp"); - login.autofillOnPageLoad = true; - - const loginView = await login.decrypt(null); - expect(loginView).toEqual({ - username: "encrypted username", - password: "encrypted password", - passwordRevisionDate: new Date("2022-01-31T12:00:00.000Z"), - totp: "encrypted totp", - uris: [ - { - match: null, - _uri: "decrypted uri", - _domain: null, - _hostname: null, - _host: null, - _canLaunch: null, - }, - ], - autofillOnPageLoad: true, - }); - }); - it("Converts from LoginData and back", () => { const data: LoginData = { uris: [{ uri: "uri", match: UriMatchType.Domain }], @@ -103,7 +64,6 @@ describe("Login DTO", () => { describe("fromJSON", () => { it("initializes nested objects", () => { - jest.spyOn(EncString, "fromJSON").mockImplementation(mockFromJson); jest.spyOn(LoginUri, "fromJSON").mockImplementation(mockFromJson); const passwordRevisionDate = new Date("2022-01-31T12:00:00.000Z"); @@ -117,10 +77,10 @@ describe("Login DTO", () => { expect(actual).toEqual({ uris: ["loginUri1_fromJSON", "loginUri2_fromJSON"] as any, - username: "myUsername_fromJSON", - password: "myPassword_fromJSON", + username: { encryptedString: "myUsername", encryptionType: 0 }, + password: { encryptedString: "myPassword", encryptionType: 0 }, passwordRevisionDate: passwordRevisionDate, - totp: "myTotp_fromJSON", + totp: { encryptedString: "myTotp", encryptionType: 0 }, }); expect(actual).toBeInstanceOf(Login); }); diff --git a/libs/common/src/models/domain/cipher/login.ts b/libs/common/src/models/domain/cipher/login.ts new file mode 100644 index 000000000000..0cbb4979c5c2 --- /dev/null +++ b/libs/common/src/models/domain/cipher/login.ts @@ -0,0 +1,76 @@ +import { Jsonify } from "type-fest"; + +import { nullableFactory } from "../../../interfaces/crypto.interface"; +import { LoginData } from "../../data/login.data"; +import { EncString } from "../enc-string"; + +import { LoginUri } from "./login-uri"; + +export class Login { + uris: LoginUri[]; + username: EncString; + password: EncString; + passwordRevisionDate?: Date; + totp: EncString; + autofillOnPageLoad: boolean; + + constructor(obj?: LoginData) { + if (obj == null) { + return; + } + + this.passwordRevisionDate = nullableFactory(Date, obj.passwordRevisionDate); + this.autofillOnPageLoad = obj.autofillOnPageLoad; + + this.username = nullableFactory(EncString, obj.username); + this.password = nullableFactory(EncString, obj.password); + this.totp = nullableFactory(EncString, obj.totp); + + if (obj.uris) { + this.uris = []; + obj.uris.forEach((u) => { + this.uris.push(new LoginUri(u)); + }); + } + } + + toLoginData(): LoginData { + const data = new LoginData(); + + data.passwordRevisionDate = this.passwordRevisionDate?.toISOString(); + data.autofillOnPageLoad = this.autofillOnPageLoad; + data.username = this.username?.encryptedString; + data.password = this.password?.encryptedString; + data.totp = this.totp?.encryptedString; + + if (this.uris != null && this.uris.length > 0) { + data.uris = []; + this.uris.forEach((u) => { + data.uris.push(u.toLoginUriData()); + }); + } + + return data; + } + + static fromJSON(obj: Partial>): Login { + if (obj == null) { + return null; + } + + const username = nullableFactory(EncString, obj.username); + const password = nullableFactory(EncString, obj.password); + const totp = nullableFactory(EncString, obj.totp); + const passwordRevisionDate = + obj.passwordRevisionDate == null ? null : new Date(obj.passwordRevisionDate); + const uris = obj.uris?.map((uri: any) => LoginUri.fromJSON(uri)); + + return Object.assign(new Login(), obj, { + username, + password, + totp, + passwordRevisionDate: passwordRevisionDate, + uris: uris, + }); + } +} diff --git a/libs/common/spec/models/domain/password.spec.ts b/libs/common/src/models/domain/cipher/password.spec.ts similarity index 66% rename from libs/common/spec/models/domain/password.spec.ts rename to libs/common/src/models/domain/cipher/password.spec.ts index 065bda4ad885..d5c36255b854 100644 --- a/libs/common/spec/models/domain/password.spec.ts +++ b/libs/common/src/models/domain/cipher/password.spec.ts @@ -1,8 +1,8 @@ -import { PasswordHistoryData } from "@bitwarden/common/models/data/password-history.data"; -import { EncString } from "@bitwarden/common/models/domain/enc-string"; -import { Password } from "@bitwarden/common/models/domain/password"; +import { mockFromJson } from "../../../../spec/utils"; +import { PasswordHistoryData } from "../../data/password-history.data"; +import { EncString } from "../enc-string"; -import { mockEnc, mockFromJson } from "../../utils"; +import { Password } from "./password"; describe("Password", () => { let data: PasswordHistoryData; @@ -37,19 +37,6 @@ describe("Password", () => { expect(password.toPasswordHistoryData()).toEqual(data); }); - it("Decrypt", async () => { - const password = new Password(); - password.password = mockEnc("password"); - password.lastUsedDate = new Date("2022-01-31T12:00:00.000Z"); - - const view = await password.decrypt(null); - - expect(view).toEqual({ - password: "password", - lastUsedDate: new Date("2022-01-31T12:00:00.000Z"), - }); - }); - describe("fromJSON", () => { it("initializes nested objects", () => { jest.spyOn(EncString, "fromJSON").mockImplementation(mockFromJson); @@ -61,7 +48,7 @@ describe("Password", () => { }); expect(actual).toEqual({ - password: "myPassword_fromJSON", + password: { encryptedString: "myPassword", encryptionType: 0 }, lastUsedDate: lastUsedDate, }); expect(actual).toBeInstanceOf(Password); diff --git a/libs/common/src/models/domain/cipher/password.ts b/libs/common/src/models/domain/cipher/password.ts new file mode 100644 index 000000000000..20532d5864b8 --- /dev/null +++ b/libs/common/src/models/domain/cipher/password.ts @@ -0,0 +1,39 @@ +import { Jsonify } from "type-fest"; + +import { nullableFactory } from "../../../interfaces/crypto.interface"; +import { PasswordHistoryData } from "../../data/password-history.data"; +import { EncString } from "../enc-string"; + +export class Password { + password: EncString; + lastUsedDate: Date; + + constructor(obj?: PasswordHistoryData) { + if (obj == null) { + return; + } + + this.password = nullableFactory(EncString, obj.password); + this.lastUsedDate = new Date(obj.lastUsedDate); + } + + toPasswordHistoryData(): PasswordHistoryData { + const data = new PasswordHistoryData(); + + data.lastUsedDate = this.lastUsedDate.toISOString(); + data.password = this.password?.encryptedString; + + return data; + } + + static fromJSON(obj: Partial>): Password { + if (obj == null) { + return null; + } + + return Object.assign(new Password(), obj, { + password: nullableFactory(EncString, obj.password), + lastUsedDate: nullableFactory(Date, obj.lastUsedDate), + }); + } +} diff --git a/libs/common/spec/models/domain/secureNote.spec.ts b/libs/common/src/models/domain/cipher/secure-note.spec.ts similarity index 62% rename from libs/common/spec/models/domain/secureNote.spec.ts rename to libs/common/src/models/domain/cipher/secure-note.spec.ts index 52f1e5ddcd9f..40ebd85e96e6 100644 --- a/libs/common/spec/models/domain/secureNote.spec.ts +++ b/libs/common/src/models/domain/cipher/secure-note.spec.ts @@ -1,6 +1,7 @@ -import { SecureNoteType } from "@bitwarden/common/enums/secureNoteType"; -import { SecureNoteData } from "@bitwarden/common/models/data/secure-note.data"; -import { SecureNote } from "@bitwarden/common/models/domain/secure-note"; +import { SecureNoteType } from "../../../enums/secureNoteType"; +import { SecureNoteData } from "../../data/secure-note.data"; + +import { SecureNote } from "./secure-note"; describe("SecureNote", () => { let data: SecureNoteData; @@ -33,17 +34,6 @@ describe("SecureNote", () => { expect(secureNote.toSecureNoteData()).toEqual(data); }); - it("Decrypt", async () => { - const secureNote = new SecureNote(); - secureNote.type = SecureNoteType.Generic; - - const view = await secureNote.decrypt(null); - - expect(view).toEqual({ - type: 0, - }); - }); - describe("fromJSON", () => { it("returns null if object is null", () => { expect(SecureNote.fromJSON(null)).toBeNull(); diff --git a/libs/common/src/models/domain/cipher/secure-note.ts b/libs/common/src/models/domain/cipher/secure-note.ts new file mode 100644 index 000000000000..9735153e4603 --- /dev/null +++ b/libs/common/src/models/domain/cipher/secure-note.ts @@ -0,0 +1,30 @@ +import { Jsonify } from "type-fest"; + +import { SecureNoteType } from "../../../enums/secureNoteType"; +import { SecureNoteData } from "../../data/secure-note.data"; + +export class SecureNote { + type: SecureNoteType; + + constructor(obj?: SecureNoteData) { + if (obj == null) { + return; + } + + this.type = obj.type; + } + + toSecureNoteData(): SecureNoteData { + const n = new SecureNoteData(); + n.type = this.type; + return n; + } + + static fromJSON(obj: Jsonify): SecureNote { + if (obj == null) { + return null; + } + + return Object.assign(new SecureNote(), obj); + } +} diff --git a/libs/common/src/models/domain/field.ts b/libs/common/src/models/domain/field.ts deleted file mode 100644 index ed098f53ea80..000000000000 --- a/libs/common/src/models/domain/field.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { Jsonify } from "type-fest"; - -import { FieldType } from "../../enums/fieldType"; -import { LinkedIdType } from "../../enums/linkedIdType"; -import { FieldData } from "../data/field.data"; -import { FieldView } from "../view/field.view"; - -import Domain from "./domain-base"; -import { EncString } from "./enc-string"; -import { SymmetricCryptoKey } from "./symmetric-crypto-key"; - -export class Field extends Domain { - name: EncString; - value: EncString; - type: FieldType; - linkedId: LinkedIdType; - - constructor(obj?: FieldData) { - super(); - if (obj == null) { - return; - } - - this.type = obj.type; - this.linkedId = obj.linkedId; - this.buildDomainModel( - this, - obj, - { - name: null, - value: null, - }, - [] - ); - } - - decrypt(orgId: string, encKey?: SymmetricCryptoKey): Promise { - return this.decryptObj( - new FieldView(this), - { - name: null, - value: null, - }, - orgId, - encKey - ); - } - - toFieldData(): FieldData { - const f = new FieldData(); - this.buildDataModel( - this, - f, - { - name: null, - value: null, - type: null, - linkedId: null, - }, - ["type", "linkedId"] - ); - return f; - } - - static fromJSON(obj: Partial>): Field { - if (obj == null) { - return null; - } - - const name = EncString.fromJSON(obj.name); - const value = EncString.fromJSON(obj.value); - - return Object.assign(new Field(), obj, { - name, - value, - }); - } -} diff --git a/libs/common/src/models/domain/identity.ts b/libs/common/src/models/domain/identity.ts deleted file mode 100644 index 5888e59c4fa4..000000000000 --- a/libs/common/src/models/domain/identity.ts +++ /dev/null @@ -1,161 +0,0 @@ -import { Jsonify } from "type-fest"; - -import { IdentityData } from "../data/identity.data"; -import { IdentityView } from "../view/identity.view"; - -import Domain from "./domain-base"; -import { EncString } from "./enc-string"; -import { SymmetricCryptoKey } from "./symmetric-crypto-key"; - -export class Identity extends Domain { - title: EncString; - firstName: EncString; - middleName: EncString; - lastName: EncString; - address1: EncString; - address2: EncString; - address3: EncString; - city: EncString; - state: EncString; - postalCode: EncString; - country: EncString; - company: EncString; - email: EncString; - phone: EncString; - ssn: EncString; - username: EncString; - passportNumber: EncString; - licenseNumber: EncString; - - constructor(obj?: IdentityData) { - super(); - if (obj == null) { - return; - } - - this.buildDomainModel( - this, - obj, - { - title: null, - firstName: null, - middleName: null, - lastName: null, - address1: null, - address2: null, - address3: null, - city: null, - state: null, - postalCode: null, - country: null, - company: null, - email: null, - phone: null, - ssn: null, - username: null, - passportNumber: null, - licenseNumber: null, - }, - [] - ); - } - - decrypt(orgId: string, encKey?: SymmetricCryptoKey): Promise { - return this.decryptObj( - new IdentityView(), - { - title: null, - firstName: null, - middleName: null, - lastName: null, - address1: null, - address2: null, - address3: null, - city: null, - state: null, - postalCode: null, - country: null, - company: null, - email: null, - phone: null, - ssn: null, - username: null, - passportNumber: null, - licenseNumber: null, - }, - orgId, - encKey - ); - } - - toIdentityData(): IdentityData { - const i = new IdentityData(); - this.buildDataModel(this, i, { - title: null, - firstName: null, - middleName: null, - lastName: null, - address1: null, - address2: null, - address3: null, - city: null, - state: null, - postalCode: null, - country: null, - company: null, - email: null, - phone: null, - ssn: null, - username: null, - passportNumber: null, - licenseNumber: null, - }); - return i; - } - - static fromJSON(obj: Jsonify): Identity { - if (obj == null) { - return null; - } - - const title = EncString.fromJSON(obj.title); - const firstName = EncString.fromJSON(obj.firstName); - const middleName = EncString.fromJSON(obj.middleName); - const lastName = EncString.fromJSON(obj.lastName); - const address1 = EncString.fromJSON(obj.address1); - const address2 = EncString.fromJSON(obj.address2); - const address3 = EncString.fromJSON(obj.address3); - const city = EncString.fromJSON(obj.city); - const state = EncString.fromJSON(obj.state); - const postalCode = EncString.fromJSON(obj.postalCode); - const country = EncString.fromJSON(obj.country); - const company = EncString.fromJSON(obj.company); - const email = EncString.fromJSON(obj.email); - const phone = EncString.fromJSON(obj.phone); - const ssn = EncString.fromJSON(obj.ssn); - const username = EncString.fromJSON(obj.username); - const passportNumber = EncString.fromJSON(obj.passportNumber); - const licenseNumber = EncString.fromJSON(obj.licenseNumber); - - return Object.assign(new Identity(), obj, { - title, - firstName, - middleName, - lastName, - address1, - address2, - address3, - city, - state, - postalCode, - country, - company, - email, - phone, - ssn, - username, - passportNumber, - licenseNumber, - }); - } -} diff --git a/libs/common/src/models/domain/import-result.ts b/libs/common/src/models/domain/import-result.ts index 6c67826306ba..302bbfbfb0c5 100644 --- a/libs/common/src/models/domain/import-result.ts +++ b/libs/common/src/models/domain/import-result.ts @@ -1,4 +1,4 @@ -import { CipherView } from "../view/cipher.view"; +import { CipherView } from "../view"; import { CollectionView } from "../view/collection.view"; import { FolderView } from "../view/folder.view"; diff --git a/libs/common/src/models/domain/index.ts b/libs/common/src/models/domain/index.ts new file mode 100644 index 000000000000..785eef13539b --- /dev/null +++ b/libs/common/src/models/domain/index.ts @@ -0,0 +1,2 @@ +export * from "./cipher"; +export * from "./symmetric-crypto-key"; diff --git a/libs/common/src/models/domain/login-uri.ts b/libs/common/src/models/domain/login-uri.ts deleted file mode 100644 index ac5317687df7..000000000000 --- a/libs/common/src/models/domain/login-uri.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { Jsonify } from "type-fest"; - -import { UriMatchType } from "../../enums/uriMatchType"; -import { LoginUriData } from "../data/login-uri.data"; -import { LoginUriView } from "../view/login-uri.view"; - -import Domain from "./domain-base"; -import { EncString } from "./enc-string"; -import { SymmetricCryptoKey } from "./symmetric-crypto-key"; - -export class LoginUri extends Domain { - uri: EncString; - match: UriMatchType; - - constructor(obj?: LoginUriData) { - super(); - if (obj == null) { - return; - } - - this.match = obj.match; - this.buildDomainModel( - this, - obj, - { - uri: null, - }, - [] - ); - } - - decrypt(orgId: string, encKey?: SymmetricCryptoKey): Promise { - return this.decryptObj( - new LoginUriView(this), - { - uri: null, - }, - orgId, - encKey - ); - } - - toLoginUriData(): LoginUriData { - const u = new LoginUriData(); - this.buildDataModel( - this, - u, - { - uri: null, - match: null, - }, - ["match"] - ); - return u; - } - - static fromJSON(obj: Jsonify): LoginUri { - if (obj == null) { - return null; - } - - const uri = EncString.fromJSON(obj.uri); - return Object.assign(new LoginUri(), obj, { - uri, - }); - } -} diff --git a/libs/common/src/models/domain/login.ts b/libs/common/src/models/domain/login.ts deleted file mode 100644 index 2ce11c850bc7..000000000000 --- a/libs/common/src/models/domain/login.ts +++ /dev/null @@ -1,111 +0,0 @@ -import { Jsonify } from "type-fest"; - -import { LoginData } from "../data/login.data"; -import { LoginView } from "../view/login.view"; - -import Domain from "./domain-base"; -import { EncString } from "./enc-string"; -import { LoginUri } from "./login-uri"; -import { SymmetricCryptoKey } from "./symmetric-crypto-key"; - -export class Login extends Domain { - uris: LoginUri[]; - username: EncString; - password: EncString; - passwordRevisionDate?: Date; - totp: EncString; - autofillOnPageLoad: boolean; - - constructor(obj?: LoginData) { - super(); - if (obj == null) { - return; - } - - this.passwordRevisionDate = - obj.passwordRevisionDate != null ? new Date(obj.passwordRevisionDate) : null; - this.autofillOnPageLoad = obj.autofillOnPageLoad; - this.buildDomainModel( - this, - obj, - { - username: null, - password: null, - totp: null, - }, - [] - ); - - if (obj.uris) { - this.uris = []; - obj.uris.forEach((u) => { - this.uris.push(new LoginUri(u)); - }); - } - } - - async decrypt(orgId: string, encKey?: SymmetricCryptoKey): Promise { - const view = await this.decryptObj( - new LoginView(this), - { - username: null, - password: null, - totp: null, - }, - orgId, - encKey - ); - - if (this.uris != null) { - view.uris = []; - for (let i = 0; i < this.uris.length; i++) { - const uri = await this.uris[i].decrypt(orgId, encKey); - view.uris.push(uri); - } - } - - return view; - } - - toLoginData(): LoginData { - const l = new LoginData(); - l.passwordRevisionDate = - this.passwordRevisionDate != null ? this.passwordRevisionDate.toISOString() : null; - l.autofillOnPageLoad = this.autofillOnPageLoad; - this.buildDataModel(this, l, { - username: null, - password: null, - totp: null, - }); - - if (this.uris != null && this.uris.length > 0) { - l.uris = []; - this.uris.forEach((u) => { - l.uris.push(u.toLoginUriData()); - }); - } - - return l; - } - - static fromJSON(obj: Partial>): Login { - if (obj == null) { - return null; - } - - const username = EncString.fromJSON(obj.username); - const password = EncString.fromJSON(obj.password); - const totp = EncString.fromJSON(obj.totp); - const passwordRevisionDate = - obj.passwordRevisionDate == null ? null : new Date(obj.passwordRevisionDate); - const uris = obj.uris?.map((uri: any) => LoginUri.fromJSON(uri)); - - return Object.assign(new Login(), obj, { - username, - password, - totp, - passwordRevisionDate: passwordRevisionDate, - uris: uris, - }); - } -} diff --git a/libs/common/src/models/domain/password.ts b/libs/common/src/models/domain/password.ts deleted file mode 100644 index 4a1ffbd151ee..000000000000 --- a/libs/common/src/models/domain/password.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { Jsonify } from "type-fest"; - -import { PasswordHistoryData } from "../data/password-history.data"; -import { PasswordHistoryView } from "../view/password-history.view"; - -import Domain from "./domain-base"; -import { EncString } from "./enc-string"; -import { SymmetricCryptoKey } from "./symmetric-crypto-key"; - -export class Password extends Domain { - password: EncString; - lastUsedDate: Date; - - constructor(obj?: PasswordHistoryData) { - super(); - if (obj == null) { - return; - } - - this.buildDomainModel(this, obj, { - password: null, - }); - this.lastUsedDate = new Date(obj.lastUsedDate); - } - - decrypt(orgId: string, encKey?: SymmetricCryptoKey): Promise { - return this.decryptObj( - new PasswordHistoryView(this), - { - password: null, - }, - orgId, - encKey - ); - } - - toPasswordHistoryData(): PasswordHistoryData { - const ph = new PasswordHistoryData(); - ph.lastUsedDate = this.lastUsedDate.toISOString(); - this.buildDataModel(this, ph, { - password: null, - }); - return ph; - } - - static fromJSON(obj: Partial>): Password { - if (obj == null) { - return null; - } - - const password = EncString.fromJSON(obj.password); - const lastUsedDate = obj.lastUsedDate == null ? null : new Date(obj.lastUsedDate); - - return Object.assign(new Password(), obj, { - password, - lastUsedDate, - }); - } -} diff --git a/libs/common/src/models/domain/secure-note.ts b/libs/common/src/models/domain/secure-note.ts deleted file mode 100644 index b880677ce801..000000000000 --- a/libs/common/src/models/domain/secure-note.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { Jsonify } from "type-fest"; - -import { SecureNoteType } from "../../enums/secureNoteType"; -import { SecureNoteData } from "../data/secure-note.data"; -import { SecureNoteView } from "../view/secure-note.view"; - -import Domain from "./domain-base"; -import { SymmetricCryptoKey } from "./symmetric-crypto-key"; - -export class SecureNote extends Domain { - type: SecureNoteType; - - constructor(obj?: SecureNoteData) { - super(); - if (obj == null) { - return; - } - - this.type = obj.type; - } - - decrypt(orgId: string, encKey?: SymmetricCryptoKey): Promise { - return Promise.resolve(new SecureNoteView(this)); - } - - toSecureNoteData(): SecureNoteData { - const n = new SecureNoteData(); - n.type = this.type; - return n; - } - - static fromJSON(obj: Jsonify): SecureNote { - if (obj == null) { - return null; - } - - return Object.assign(new SecureNote(), obj); - } -} diff --git a/libs/common/src/models/domain/sorted-ciphers-cache.ts b/libs/common/src/models/domain/sorted-ciphers-cache.ts index 2835cb8d0684..a619a28181cb 100644 --- a/libs/common/src/models/domain/sorted-ciphers-cache.ts +++ b/libs/common/src/models/domain/sorted-ciphers-cache.ts @@ -1,4 +1,4 @@ -import { CipherView } from "../view/cipher.view"; +import { CipherView } from "../view"; const CacheTTL = 3000; diff --git a/libs/common/src/models/export/card.export.ts b/libs/common/src/models/export/card.export.ts index edd730b77385..49dd0a9ff94a 100644 --- a/libs/common/src/models/export/card.export.ts +++ b/libs/common/src/models/export/card.export.ts @@ -1,6 +1,6 @@ -import { Card as CardDomain } from "../domain/card"; +import { Card as CardDomain } from "../domain"; import { EncString } from "../domain/enc-string"; -import { CardView } from "../view/card.view"; +import { CardView } from "../view"; export class CardExport { static template(): CardExport { diff --git a/libs/common/src/models/export/cipher-with-ids.export.ts b/libs/common/src/models/export/cipher-with-ids.export.ts index 2ad601e9a6ea..71bd42cd5782 100644 --- a/libs/common/src/models/export/cipher-with-ids.export.ts +++ b/libs/common/src/models/export/cipher-with-ids.export.ts @@ -1,5 +1,5 @@ import { Cipher as CipherDomain } from "../domain/cipher"; -import { CipherView } from "../view/cipher.view"; +import { CipherView } from "../view"; import { CipherExport } from "./cipher.export"; diff --git a/libs/common/src/models/export/cipher.export.ts b/libs/common/src/models/export/cipher.export.ts index b4585cb4060f..c1534b9c41b4 100644 --- a/libs/common/src/models/export/cipher.export.ts +++ b/libs/common/src/models/export/cipher.export.ts @@ -2,7 +2,7 @@ import { CipherRepromptType } from "../../enums/cipherRepromptType"; import { CipherType } from "../../enums/cipherType"; import { Cipher as CipherDomain } from "../domain/cipher"; import { EncString } from "../domain/enc-string"; -import { CipherView } from "../view/cipher.view"; +import { CipherView } from "../view"; import { CardExport } from "./card.export"; import { FieldExport } from "./field.export"; diff --git a/libs/common/src/models/export/field.export.ts b/libs/common/src/models/export/field.export.ts index 66c856d7bfce..83af0c50a477 100644 --- a/libs/common/src/models/export/field.export.ts +++ b/libs/common/src/models/export/field.export.ts @@ -1,8 +1,8 @@ import { FieldType } from "../../enums/fieldType"; import { LinkedIdType } from "../../enums/linkedIdType"; +import { Field as FieldDomain } from "../domain"; import { EncString } from "../domain/enc-string"; -import { Field as FieldDomain } from "../domain/field"; -import { FieldView } from "../view/field.view"; +import { FieldView } from "../view"; export class FieldExport { static template(): FieldExport { diff --git a/libs/common/src/models/export/identity.export.ts b/libs/common/src/models/export/identity.export.ts index d4180d44a91c..6c3220c05e9a 100644 --- a/libs/common/src/models/export/identity.export.ts +++ b/libs/common/src/models/export/identity.export.ts @@ -1,6 +1,6 @@ +import { Identity as IdentityDomain } from "../domain"; import { EncString } from "../domain/enc-string"; -import { Identity as IdentityDomain } from "../domain/identity"; -import { IdentityView } from "../view/identity.view"; +import { IdentityView } from "../view"; export class IdentityExport { static template(): IdentityExport { diff --git a/libs/common/src/models/export/login-uri.export.ts b/libs/common/src/models/export/login-uri.export.ts index ee0d883c9840..fceb0a6b5d59 100644 --- a/libs/common/src/models/export/login-uri.export.ts +++ b/libs/common/src/models/export/login-uri.export.ts @@ -1,7 +1,7 @@ import { UriMatchType } from "../../enums/uriMatchType"; +import { LoginUri as LoginUriDomain } from "../domain"; import { EncString } from "../domain/enc-string"; -import { LoginUri as LoginUriDomain } from "../domain/login-uri"; -import { LoginUriView } from "../view/login-uri.view"; +import { LoginUriView } from "../view"; export class LoginUriExport { static template(): LoginUriExport { diff --git a/libs/common/src/models/export/login.export.ts b/libs/common/src/models/export/login.export.ts index 6a143fb99af2..06cf13ac75d7 100644 --- a/libs/common/src/models/export/login.export.ts +++ b/libs/common/src/models/export/login.export.ts @@ -1,6 +1,6 @@ +import { Login as LoginDomain } from "../domain"; import { EncString } from "../domain/enc-string"; -import { Login as LoginDomain } from "../domain/login"; -import { LoginView } from "../view/login.view"; +import { LoginView } from "../view"; import { LoginUriExport } from "./login-uri.export"; diff --git a/libs/common/src/models/export/secure-note.export.ts b/libs/common/src/models/export/secure-note.export.ts index 7b7e987698db..a79d0914acc0 100644 --- a/libs/common/src/models/export/secure-note.export.ts +++ b/libs/common/src/models/export/secure-note.export.ts @@ -1,6 +1,6 @@ import { SecureNoteType } from "../../enums/secureNoteType"; -import { SecureNote as SecureNoteDomain } from "../domain/secure-note"; -import { SecureNoteView } from "../view/secure-note.view"; +import { SecureNote as SecureNoteDomain } from "../domain"; +import { SecureNoteView } from "../view"; export class SecureNoteExport { static template(): SecureNoteExport { diff --git a/libs/common/src/models/view/attachment.view.ts b/libs/common/src/models/view/attachment.view.ts deleted file mode 100644 index 6a40ee52e56b..000000000000 --- a/libs/common/src/models/view/attachment.view.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { Jsonify } from "type-fest"; - -import { Attachment } from "../domain/attachment"; -import { SymmetricCryptoKey } from "../domain/symmetric-crypto-key"; - -import { View } from "./view"; - -export class AttachmentView implements View { - id: string = null; - url: string = null; - size: string = null; - sizeName: string = null; - fileName: string = null; - key: SymmetricCryptoKey = null; - - constructor(a?: Attachment) { - if (!a) { - return; - } - - this.id = a.id; - this.url = a.url; - this.size = a.size; - this.sizeName = a.sizeName; - } - - get fileSize(): number { - try { - if (this.size != null) { - return parseInt(this.size, null); - } - } catch { - // Invalid file size. - } - return 0; - } - - static fromJSON(obj: Partial>): AttachmentView { - const key = obj.key == null ? null : SymmetricCryptoKey.fromJSON(obj.key); - return Object.assign(new AttachmentView(), obj, { key: key }); - } -} diff --git a/libs/common/src/models/view/cipher.view.ts b/libs/common/src/models/view/cipher.view.ts deleted file mode 100644 index c3c69b3b9e71..000000000000 --- a/libs/common/src/models/view/cipher.view.ts +++ /dev/null @@ -1,179 +0,0 @@ -import { Jsonify } from "type-fest"; - -import { CipherRepromptType } from "../../enums/cipherRepromptType"; -import { CipherType } from "../../enums/cipherType"; -import { LinkedIdType } from "../../enums/linkedIdType"; -import { InitializerMetadata } from "../../interfaces/initializer-metadata.interface"; -import { InitializerKey } from "../../services/cryptography/initializer-key"; -import { LocalData } from "../data/local.data"; -import { Cipher } from "../domain/cipher"; - -import { AttachmentView } from "./attachment.view"; -import { CardView } from "./card.view"; -import { FieldView } from "./field.view"; -import { IdentityView } from "./identity.view"; -import { LoginView } from "./login.view"; -import { PasswordHistoryView } from "./password-history.view"; -import { SecureNoteView } from "./secure-note.view"; -import { View } from "./view"; - -export class CipherView implements View, InitializerMetadata { - readonly initializerKey = InitializerKey.CipherView; - - id: string = null; - organizationId: string = null; - folderId: string = null; - name: string = null; - notes: string = null; - type: CipherType = null; - favorite = false; - organizationUseTotp = false; - edit = false; - viewPassword = true; - localData: LocalData; - login = new LoginView(); - identity = new IdentityView(); - card = new CardView(); - secureNote = new SecureNoteView(); - attachments: AttachmentView[] = null; - fields: FieldView[] = null; - passwordHistory: PasswordHistoryView[] = null; - collectionIds: string[] = null; - revisionDate: Date = null; - creationDate: Date = null; - deletedDate: Date = null; - reprompt: CipherRepromptType = CipherRepromptType.None; - - constructor(c?: Cipher) { - if (!c) { - return; - } - - this.id = c.id; - this.organizationId = c.organizationId; - this.folderId = c.folderId; - this.favorite = c.favorite; - this.organizationUseTotp = c.organizationUseTotp; - this.edit = c.edit; - this.viewPassword = c.viewPassword; - this.type = c.type; - this.localData = c.localData; - this.collectionIds = c.collectionIds; - this.revisionDate = c.revisionDate; - this.creationDate = c.creationDate; - this.deletedDate = c.deletedDate; - // Old locally stored ciphers might have reprompt == null. If so set it to None. - this.reprompt = c.reprompt ?? CipherRepromptType.None; - } - - private get item() { - switch (this.type) { - case CipherType.Login: - return this.login; - case CipherType.SecureNote: - return this.secureNote; - case CipherType.Card: - return this.card; - case CipherType.Identity: - return this.identity; - default: - break; - } - - return null; - } - - get subTitle(): string { - return this.item.subTitle; - } - - get hasPasswordHistory(): boolean { - return this.passwordHistory && this.passwordHistory.length > 0; - } - - get hasAttachments(): boolean { - return this.attachments && this.attachments.length > 0; - } - - get hasOldAttachments(): boolean { - if (this.hasAttachments) { - for (let i = 0; i < this.attachments.length; i++) { - if (this.attachments[i].key == null) { - return true; - } - } - } - return false; - } - - get hasFields(): boolean { - return this.fields && this.fields.length > 0; - } - - get passwordRevisionDisplayDate(): Date { - if (this.type !== CipherType.Login || this.login == null) { - return null; - } else if (this.login.password == null || this.login.password === "") { - return null; - } - return this.login.passwordRevisionDate; - } - - get isDeleted(): boolean { - return this.deletedDate != null; - } - - get linkedFieldOptions() { - return this.item.linkedFieldOptions; - } - - linkedFieldValue(id: LinkedIdType) { - const linkedFieldOption = this.linkedFieldOptions?.get(id); - if (linkedFieldOption == null) { - return null; - } - - const item = this.item; - return this.item[linkedFieldOption.propertyKey as keyof typeof item]; - } - - linkedFieldI18nKey(id: LinkedIdType): string { - return this.linkedFieldOptions.get(id)?.i18nKey; - } - - static fromJSON(obj: Partial>): CipherView { - const view = new CipherView(); - const revisionDate = obj.revisionDate == null ? null : new Date(obj.revisionDate); - const deletedDate = obj.deletedDate == null ? null : new Date(obj.deletedDate); - const attachments = obj.attachments?.map((a: any) => AttachmentView.fromJSON(a)); - const fields = obj.fields?.map((f: any) => FieldView.fromJSON(f)); - const passwordHistory = obj.passwordHistory?.map((ph: any) => PasswordHistoryView.fromJSON(ph)); - - Object.assign(view, obj, { - revisionDate: revisionDate, - deletedDate: deletedDate, - attachments: attachments, - fields: fields, - passwordHistory: passwordHistory, - }); - - switch (obj.type) { - case CipherType.Card: - view.card = CardView.fromJSON(obj.card); - break; - case CipherType.Identity: - view.identity = IdentityView.fromJSON(obj.identity); - break; - case CipherType.Login: - view.login = LoginView.fromJSON(obj.login); - break; - case CipherType.SecureNote: - view.secureNote = SecureNoteView.fromJSON(obj.secureNote); - break; - default: - break; - } - - return view; - } -} diff --git a/libs/common/src/models/view/cipher/attachment.view.spec.ts b/libs/common/src/models/view/cipher/attachment.view.spec.ts new file mode 100644 index 000000000000..aa3f88cb9189 --- /dev/null +++ b/libs/common/src/models/view/cipher/attachment.view.spec.ts @@ -0,0 +1,62 @@ +import { mock, MockProxy } from "jest-mock-extended"; + +import { makeStaticByteArray, mockEnc, mockFromJson } from "../../../../spec/utils"; +import { CryptoService } from "../../../abstractions/crypto.service"; +import { EncryptService } from "../../../abstractions/encrypt.service"; +import { ContainerService } from "../../../services/container.service"; +import { Attachment } from "../../domain"; +import { SymmetricCryptoKey } from "../../domain/symmetric-crypto-key"; + +import { AttachmentView } from "./attachment.view"; + +jest.mock("../../domain/symmetric-crypto-key"); + +describe("AttachmentView", () => { + it("fromJSON initializes nested objects", () => { + jest.spyOn(SymmetricCryptoKey, "fromJSON").mockImplementation(mockFromJson); + + const actual = AttachmentView.fromJSON({ + key: "encKeyB64" as any, + }); + + expect(actual.key).toEqual("encKeyB64_fromJSON"); + }); + + describe("decrypt", () => { + let cryptoService: MockProxy; + let encryptService: MockProxy; + + beforeEach(() => { + cryptoService = mock(); + encryptService = mock(); + + (window as any).bitwardenContainerService = new ContainerService( + cryptoService, + encryptService + ); + }); + + it("expected output", async () => { + const attachment = new Attachment(); + attachment.id = "id"; + attachment.url = "url"; + attachment.size = "1100"; + attachment.sizeName = "1.1 KB"; + attachment.key = mockEnc("key"); + attachment.fileName = mockEnc("fileName"); + + encryptService.decryptToBytes.mockResolvedValue(makeStaticByteArray(32)); + + const view = await AttachmentView.decrypt(encryptService, null, attachment); + + expect(view).toEqual({ + id: "id", + url: "url", + size: "1100", + sizeName: "1.1 KB", + fileName: "fileName", + key: expect.any(SymmetricCryptoKey), + }); + }); + }); +}); diff --git a/libs/common/src/models/view/cipher/attachment.view.ts b/libs/common/src/models/view/cipher/attachment.view.ts new file mode 100644 index 000000000000..036084e27549 --- /dev/null +++ b/libs/common/src/models/view/cipher/attachment.view.ts @@ -0,0 +1,61 @@ +import { Jsonify } from "type-fest"; + +import { EncryptService } from "../../../abstractions/encrypt.service"; +import { Attachment } from "../../domain"; +import { SymmetricCryptoKey } from "../../domain/symmetric-crypto-key"; +import { View } from "../view"; + +export class AttachmentView implements View { + id: string = null; + url: string = null; + size: string = null; + sizeName: string = null; + fileName: string = null; + key: SymmetricCryptoKey = null; + + get fileSize(): number { + try { + if (this.size != null) { + return parseInt(this.size, null); + } + } catch { + // Invalid file size. + } + return 0; + } + + async encrypt(encryptService: EncryptService, key: SymmetricCryptoKey): Promise { + const attachment = new Attachment(); + + attachment.id = this.id; + attachment.url = this.url; + attachment.size = this.size; + attachment.sizeName = this.sizeName; + + attachment.fileName = + this.fileName != null ? await encryptService.encrypt(this.fileName, key) : null; + attachment.key = this.key != null ? await encryptService.encrypt(this.key.key, key) : null; + + return attachment; + } + + static fromJSON(obj: Partial>): AttachmentView { + const key = obj.key == null ? null : SymmetricCryptoKey.fromJSON(obj.key); + return Object.assign(new AttachmentView(), obj, { key: key }); + } + + static async decrypt(encryptService: EncryptService, key: SymmetricCryptoKey, model: Attachment) { + const view = new AttachmentView(); + + view.id = model.id; + view.url = model.url; + view.size = model.size; + view.sizeName = model.sizeName; + view.fileName = await model.fileName?.decryptWithEncryptService(encryptService, key); + + const attachmentKey = await (model.key ? encryptService.decryptToBytes(model.key, key) : null); + view.key = new SymmetricCryptoKey(attachmentKey); + + return view; + } +} diff --git a/libs/common/src/models/view/cipher/card.view.spec.ts b/libs/common/src/models/view/cipher/card.view.spec.ts new file mode 100644 index 000000000000..d2f408430b9c --- /dev/null +++ b/libs/common/src/models/view/cipher/card.view.spec.ts @@ -0,0 +1,28 @@ +import { mockEnc } from "../../../../spec/utils"; +import { Card } from "../../domain"; + +import { CardView } from "./card.view"; + +describe("CardView", () => { + it("Decrypt", async () => { + const card = new Card(); + card.cardholderName = mockEnc("cardHolder"); + card.brand = mockEnc("brand"); + card.number = mockEnc("number"); + card.expMonth = mockEnc("expMonth"); + card.expYear = mockEnc("expYear"); + card.code = mockEnc("code"); + + const view = await CardView.decrypt(null, null, card); + + expect(view).toEqual({ + _brand: "brand", + _number: "number", + _subTitle: null, + cardholderName: "cardHolder", + code: "code", + expMonth: "expMonth", + expYear: "expYear", + }); + }); +}); diff --git a/libs/common/src/models/view/card.view.ts b/libs/common/src/models/view/cipher/card.view.ts similarity index 56% rename from libs/common/src/models/view/card.view.ts rename to libs/common/src/models/view/cipher/card.view.ts index 08beed7a77f4..eb33d2d101bd 100644 --- a/libs/common/src/models/view/card.view.ts +++ b/libs/common/src/models/view/cipher/card.view.ts @@ -1,9 +1,11 @@ import { Jsonify } from "type-fest"; -import { CardLinkedId as LinkedId } from "../../enums/linkedIdType"; -import { linkedFieldOption } from "../../misc/linkedFieldOption.decorator"; +import { EncryptService } from "../../../abstractions/encrypt.service"; +import { CardLinkedId as LinkedId } from "../../../enums/linkedIdType"; +import { Card, SymmetricCryptoKey } from "../../domain"; import { ItemView } from "./item.view"; +import { linkedFieldOption } from "./linked-field-option.decorator"; export class CardView extends ItemView { @linkedFieldOption(LinkedId.CardholderName) @@ -78,7 +80,43 @@ export class CardView extends ItemView { return year.length === 2 ? "20" + year : year; } + async encrypt(encryptService: EncryptService, key: SymmetricCryptoKey): Promise { + const card = new Card(); + + [card.cardholderName, card.brand, card.number, card.expMonth, card.expYear, card.code] = + await Promise.all([ + this.cardholderName ? encryptService.encrypt(this.cardholderName, key) : null, + this.brand ? encryptService.encrypt(this.brand, key) : null, + this.number ? encryptService.encrypt(this.number, key) : null, + this.expMonth ? encryptService.encrypt(this.expMonth, key) : null, + this.expYear ? encryptService.encrypt(this.expYear, key) : null, + this.code ? encryptService.encrypt(this.code, key) : null, + ]); + + return card; + } + static fromJSON(obj: Partial>): CardView { return Object.assign(new CardView(), obj); } + + static async decrypt(encryptService: EncryptService, key: SymmetricCryptoKey, model: Card) { + if (model == null) { + return null; + } + + const view = new CardView(); + + [view.cardholderName, view.brand, view.number, view.expMonth, view.expYear, view.code] = + await Promise.all([ + model.cardholderName?.decryptWithEncryptService(encryptService, key), + model.brand?.decryptWithEncryptService(encryptService, key), + model.number?.decryptWithEncryptService(encryptService, key), + model.expMonth?.decryptWithEncryptService(encryptService, key), + model.expYear?.decryptWithEncryptService(encryptService, key), + model.code?.decryptWithEncryptService(encryptService, key), + ]); + + return view; + } } diff --git a/libs/common/src/models/view/cipher/cipher.view.spec.ts b/libs/common/src/models/view/cipher/cipher.view.spec.ts new file mode 100644 index 000000000000..d3b5a819c0e0 --- /dev/null +++ b/libs/common/src/models/view/cipher/cipher.view.spec.ts @@ -0,0 +1,240 @@ +import { mockEnc, mockFromJson } from "../../../../spec/utils"; +import { CipherRepromptType } from "../../../enums/cipherRepromptType"; +import { CipherType } from "../../../enums/cipherType"; +import { SecureNoteType } from "../../../enums/secureNoteType"; +import { Cipher, Identity, SecureNote } from "../../domain"; + +import { AttachmentView } from "./attachment.view"; +import { CardView } from "./card.view"; +import { CipherView } from "./cipher.view"; +import { FieldView } from "./field.view"; +import { IdentityView } from "./identity.view"; +import { LoginView } from "./login.view"; +import { PasswordHistoryView } from "./password-history.view"; +import { SecureNoteView } from "./secure-note.view"; + +jest.mock("./attachment.view"); +jest.mock("./card.view"); +jest.mock("./field.view"); +jest.mock("./login.view"); +jest.mock("./password-history.view"); + +describe("CipherView", () => { + beforeEach(() => { + (LoginView as any).mockClear(); + (AttachmentView as any).mockClear(); + (FieldView as any).mockClear(); + (PasswordHistoryView as any).mockClear(); + }); + + describe("fromJSON", () => { + it("initializes nested objects", () => { + jest.spyOn(AttachmentView, "fromJSON").mockImplementation(mockFromJson); + jest.spyOn(FieldView, "fromJSON").mockImplementation(mockFromJson); + jest.spyOn(PasswordHistoryView, "fromJSON").mockImplementation(mockFromJson); + + const revisionDate = new Date("2022-08-04T01:06:40.441Z"); + const deletedDate = new Date("2022-09-04T01:06:40.441Z"); + const actual = CipherView.fromJSON({ + revisionDate: revisionDate.toISOString(), + deletedDate: deletedDate.toISOString(), + attachments: ["attachment1", "attachment2"] as any, + fields: ["field1", "field2"] as any, + passwordHistory: ["ph1", "ph2", "ph3"] as any, + }); + + const expected = { + revisionDate: revisionDate, + deletedDate: deletedDate, + attachments: ["attachment1_fromJSON", "attachment2_fromJSON"], + fields: ["field1_fromJSON", "field2_fromJSON"], + passwordHistory: ["ph1_fromJSON", "ph2_fromJSON", "ph3_fromJSON"], + }; + + expect(actual).toMatchObject(expected); + }); + + test.each([ + // Test description, CipherType, expected output + ["LoginView", CipherType.Login, { login: "myLogin_fromJSON" }], + ["CardView", CipherType.Card, { card: "myCard_fromJSON" }], + ["IdentityView", CipherType.Identity, { identity: "myIdentity_fromJSON" }], + ["Secure Note", CipherType.SecureNote, { secureNote: "mySecureNote_fromJSON" }], + ])("initializes %s", (description: string, cipherType: CipherType, expected: any) => { + jest.spyOn(LoginView, "fromJSON").mockImplementation(mockFromJson); + jest.spyOn(IdentityView, "fromJSON").mockImplementation(mockFromJson); + jest.spyOn(CardView, "fromJSON").mockImplementation(mockFromJson); + jest.spyOn(SecureNoteView, "fromJSON").mockImplementation(mockFromJson); + + const actual = CipherView.fromJSON({ + login: "myLogin", + card: "myCard", + identity: "myIdentity", + secureNote: "mySecureNote", + type: cipherType, + } as any); + + expect(actual).toMatchObject(expected); + }); + }); + + describe("Decrypt", () => { + let cipher: Cipher; + + beforeEach(() => { + cipher = new Cipher(); + cipher.id = "id"; + cipher.organizationId = "orgId"; + cipher.folderId = "folderId"; + cipher.edit = true; + cipher.viewPassword = true; + cipher.organizationUseTotp = true; + cipher.favorite = false; + cipher.revisionDate = new Date("2022-01-31T12:00:00.000Z"); + cipher.name = mockEnc("EncryptedString"); + cipher.notes = mockEnc("EncryptedString"); + cipher.creationDate = new Date("2022-01-01T12:00:00.000Z"); + cipher.deletedDate = null; + cipher.reprompt = CipherRepromptType.None; + }); + + it("Login", async () => { + cipher.type = CipherType.Login; + + const loginView = new LoginView(); + loginView.username = "username"; + loginView.password = "password"; + + jest.spyOn(LoginView, "decrypt").mockImplementation(() => Promise.resolve(loginView)); + + const cipherView = await CipherView.decrypt(null, null, cipher); + + expect(cipherView).toMatchObject({ + id: "id", + organizationId: "orgId", + folderId: "folderId", + name: "EncryptedString", + notes: "EncryptedString", + type: 1, + favorite: false, + organizationUseTotp: true, + edit: true, + viewPassword: true, + login: loginView, + attachments: null, + fields: null, + passwordHistory: null, + collectionIds: undefined, + revisionDate: new Date("2022-01-31T12:00:00.000Z"), + creationDate: new Date("2022-01-01T12:00:00.000Z"), + deletedDate: null, + reprompt: 0, + localData: undefined, + }); + }); + + it("SecureNote", async () => { + cipher.type = CipherType.SecureNote; + + cipher.secureNote = new SecureNote(); + cipher.secureNote.type = SecureNoteType.Generic; + + const cipherView = await CipherView.decrypt(null, null, cipher); + + expect(cipherView).toMatchObject({ + id: "id", + organizationId: "orgId", + folderId: "folderId", + name: "EncryptedString", + notes: "EncryptedString", + type: 2, + favorite: false, + organizationUseTotp: true, + edit: true, + viewPassword: true, + secureNote: { type: 0 }, + attachments: null, + fields: null, + passwordHistory: null, + collectionIds: undefined, + revisionDate: new Date("2022-01-31T12:00:00.000Z"), + creationDate: new Date("2022-01-01T12:00:00.000Z"), + deletedDate: null, + reprompt: 0, + localData: undefined, + }); + }); + + it("Card", async () => { + cipher.type = CipherType.Card; + + const cardView = new CardView(); + cardView.cardholderName = "cardholderName"; + cardView.number = "4111111111111111"; + + jest.spyOn(CardView, "decrypt").mockImplementation(() => Promise.resolve(cardView)); + + const cipherView = await CipherView.decrypt(null, null, cipher); + + expect(cipherView).toMatchObject({ + id: "id", + organizationId: "orgId", + folderId: "folderId", + name: "EncryptedString", + notes: "EncryptedString", + type: 3, + favorite: false, + organizationUseTotp: true, + edit: true, + viewPassword: true, + card: cardView, + attachments: null, + fields: null, + passwordHistory: null, + collectionIds: undefined, + revisionDate: new Date("2022-01-31T12:00:00.000Z"), + creationDate: new Date("2022-01-01T12:00:00.000Z"), + deletedDate: null, + reprompt: 0, + localData: undefined, + }); + }); + + it("Identity", async () => { + cipher.type = CipherType.Identity; + + const identityView = new IdentityView(); + identityView.firstName = "firstName"; + identityView.lastName = "lastName"; + + jest.spyOn(IdentityView, "decrypt").mockImplementation(() => Promise.resolve(identityView)); + + const identity = new Identity(); + cipher.identity = identity; + const cipherView = await CipherView.decrypt(null, null, cipher); + + expect(cipherView).toMatchObject({ + id: "id", + organizationId: "orgId", + folderId: "folderId", + name: "EncryptedString", + notes: "EncryptedString", + type: 4, + favorite: false, + organizationUseTotp: true, + edit: true, + viewPassword: true, + identity: identityView, + attachments: null, + fields: null, + passwordHistory: null, + collectionIds: undefined, + revisionDate: new Date("2022-01-31T12:00:00.000Z"), + creationDate: new Date("2022-01-01T12:00:00.000Z"), + deletedDate: null, + reprompt: 0, + localData: undefined, + }); + }); + }); +}); diff --git a/libs/common/src/models/view/cipher/cipher.view.ts b/libs/common/src/models/view/cipher/cipher.view.ts new file mode 100644 index 000000000000..4714a7cacb6a --- /dev/null +++ b/libs/common/src/models/view/cipher/cipher.view.ts @@ -0,0 +1,281 @@ +import { Jsonify } from "type-fest"; + +import { EncryptService } from "../../../abstractions/encrypt.service"; +import { CipherRepromptType } from "../../../enums/cipherRepromptType"; +import { CipherType } from "../../../enums/cipherType"; +import { LinkedIdType } from "../../../enums/linkedIdType"; +import { Encryptable, nullableFactory } from "../../../interfaces/crypto.interface"; +import { InitializerKey } from "../../../services/cryptography/initializer-key"; +import { LocalData } from "../../data/local.data"; +import { SymmetricCryptoKey } from "../../domain"; +import { Cipher } from "../../domain/cipher"; +import { View } from "../view"; + +import { AttachmentView } from "./attachment.view"; +import { CardView } from "./card.view"; +import { FieldView } from "./field.view"; +import { IdentityView } from "./identity.view"; +import { LoginView } from "./login.view"; +import { PasswordHistoryView } from "./password-history.view"; +import { SecureNoteView } from "./secure-note.view"; + +export class CipherView implements View, Encryptable { + static readonly initializerKey = InitializerKey.CipherView; + + id: string = null; + organizationId: string = null; + folderId: string = null; + name: string = null; + notes: string = null; + type: CipherType = null; + favorite = false; + organizationUseTotp = false; + edit = false; + viewPassword = true; + localData: LocalData; + login = new LoginView(); + identity = new IdentityView(); + card = new CardView(); + secureNote = new SecureNoteView(); + attachments: AttachmentView[] = null; + fields: FieldView[] = null; + passwordHistory: PasswordHistoryView[] = null; + collectionIds: string[] = null; + revisionDate: Date = null; + creationDate: Date = null; + deletedDate: Date = null; + reprompt: CipherRepromptType = CipherRepromptType.None; + + keyIdentifier(): string | null { + return this.organizationId || null; + } + + async encrypt(encryptService: EncryptService, key: SymmetricCryptoKey): Promise { + const cipher = new Cipher(); + cipher.id = this.id; + cipher.organizationId = this.organizationId; + cipher.folderId = this.folderId; + cipher.name = this.name != null ? await encryptService.encrypt(this.name, key) : null; + cipher.notes = this.notes != null ? await encryptService.encrypt(this.notes, key) : null; + cipher.type = this.type; + cipher.favorite = this.favorite; + //cipher.organizationUseTotp = this.organizationUseTotp; + cipher.edit = this.edit; + //cipher.viewPassword = this.viewPassword; + //cipher.localData = this.localData; + + switch (this.type) { + case CipherType.Login: + cipher.login = await this.login.encrypt(encryptService, key); + break; + case CipherType.Identity: + cipher.identity = await this.identity.encrypt(encryptService, key); + break; + case CipherType.Card: + cipher.card = await this.card.encrypt(encryptService, key); + break; + case CipherType.SecureNote: + cipher.secureNote = await this.secureNote.encrypt(encryptService, key); + break; + default: + break; + } + + cipher.attachments = await Promise.all( + this.attachments?.map((a) => a.encrypt(encryptService, key)) ?? [] + ); + + cipher.fields = await Promise.all( + this.fields?.map((f) => f.encrypt(encryptService, key)) ?? [] + ); + + cipher.passwordHistory = await Promise.all( + this.passwordHistory?.map((p) => p.encrypt(encryptService, key)) ?? [] + ); + + cipher.collectionIds = this.collectionIds; + cipher.revisionDate = this.revisionDate; + //cipher.creationDate = this.creationDate; + //cipher.deletedDate = this.deletedDate; + cipher.reprompt = this.reprompt; + + return cipher; + } + + private get item() { + switch (this.type) { + case CipherType.Login: + return this.login; + case CipherType.SecureNote: + return this.secureNote; + case CipherType.Card: + return this.card; + case CipherType.Identity: + return this.identity; + default: + break; + } + + return null; + } + + get subTitle(): string { + return this.item.subTitle; + } + + get hasPasswordHistory(): boolean { + return this.passwordHistory && this.passwordHistory.length > 0; + } + + get hasAttachments(): boolean { + return this.attachments && this.attachments.length > 0; + } + + get hasOldAttachments(): boolean { + if (this.hasAttachments) { + for (let i = 0; i < this.attachments.length; i++) { + if (this.attachments[i].key == null) { + return true; + } + } + } + return false; + } + + get hasFields(): boolean { + return this.fields && this.fields.length > 0; + } + + get passwordRevisionDisplayDate(): Date { + if (this.type !== CipherType.Login || this.login == null) { + return null; + } else if (this.login.password == null || this.login.password === "") { + return null; + } + return this.login.passwordRevisionDate; + } + + get isDeleted(): boolean { + return this.deletedDate != null; + } + + get linkedFieldOptions() { + return this.item.linkedFieldOptions; + } + + linkedFieldValue(id: LinkedIdType) { + const linkedFieldOption = this.linkedFieldOptions?.get(id); + if (linkedFieldOption == null) { + return null; + } + + const item = this.item; + return this.item[linkedFieldOption.propertyKey as keyof typeof item]; + } + + linkedFieldI18nKey(id: LinkedIdType): string { + return this.linkedFieldOptions.get(id)?.i18nKey; + } + + static fromJSON(obj: Partial>): CipherView { + const view = new CipherView(); + const revisionDate = nullableFactory(Date, obj.revisionDate); + const deletedDate = nullableFactory(Date, obj.deletedDate); + const attachments = obj.attachments?.map((a: any) => AttachmentView.fromJSON(a)); + const fields = obj.fields?.map((f: any) => FieldView.fromJSON(f)); + const passwordHistory = obj.passwordHistory?.map((ph: any) => PasswordHistoryView.fromJSON(ph)); + + Object.assign(view, obj, { + revisionDate: revisionDate, + deletedDate: deletedDate, + attachments: attachments, + fields: fields, + passwordHistory: passwordHistory, + }); + + switch (obj.type) { + case CipherType.Card: + view.card = CardView.fromJSON(obj.card); + break; + case CipherType.Identity: + view.identity = IdentityView.fromJSON(obj.identity); + break; + case CipherType.Login: + view.login = LoginView.fromJSON(obj.login); + break; + case CipherType.SecureNote: + view.secureNote = SecureNoteView.fromJSON(obj.secureNote); + break; + default: + break; + } + + return view; + } + + static async decrypt(encryptService: EncryptService, key: SymmetricCryptoKey, model: Cipher) { + const view = new CipherView(); + + view.id = model.id; + view.organizationId = model.organizationId; + view.folderId = model.folderId; + view.favorite = model.favorite; + view.organizationUseTotp = model.organizationUseTotp; + view.edit = model.edit; + view.viewPassword = model.viewPassword; + view.type = model.type; + view.localData = model.localData; + view.collectionIds = model.collectionIds; + view.revisionDate = model.revisionDate; + view.creationDate = model.creationDate; + view.deletedDate = model.deletedDate; + // Old locally stored ciphers might have reprompt == null. If so set it to None. + view.reprompt = model.reprompt ?? CipherRepromptType.None; + + view.name = await model.name?.decryptWithEncryptService(encryptService, key); + view.notes = await model.notes?.decryptWithEncryptService(encryptService, key); + + switch (model.type) { + case CipherType.Login: + view.login = await LoginView.decrypt(encryptService, key, model.login); + break; + case CipherType.SecureNote: + view.secureNote = await SecureNoteView.decrypt(encryptService, key, model.secureNote); + break; + case CipherType.Card: + view.card = await CardView.decrypt(encryptService, key, model.card); + break; + case CipherType.Identity: + view.identity = await IdentityView.decrypt(encryptService, key, model.identity); + break; + default: + break; + } + + if (model.attachments?.length > 0) { + view.attachments = await Promise.all( + model.attachments.map((a) => { + return AttachmentView.decrypt(encryptService, key, a); + }) + ); + } + + if (model.fields?.length > 0) { + view.fields = await Promise.all( + model.fields.map((f) => { + return FieldView.decrypt(encryptService, key, f); + }) + ); + } + + if (model.passwordHistory?.length > 0) { + view.passwordHistory = await Promise.all( + model.passwordHistory.map((f) => { + return PasswordHistoryView.decrypt(encryptService, key, f); + }) + ); + } + + return view; + } +} diff --git a/libs/common/src/models/view/cipher/field.view.spec.ts b/libs/common/src/models/view/cipher/field.view.spec.ts new file mode 100644 index 000000000000..1fc2d74a2c53 --- /dev/null +++ b/libs/common/src/models/view/cipher/field.view.spec.ts @@ -0,0 +1,25 @@ +import { mockEnc } from "../../../../spec/utils"; +import { FieldType } from "../../../enums/fieldType"; +import { Field } from "../../domain"; + +import { FieldView } from "./field.view"; + +describe("FieldView", () => { + it("Decrypt", async () => { + const field = new Field(); + field.type = FieldType.Text; + field.name = mockEnc("encName"); + field.value = mockEnc("encValue"); + + const view = await FieldView.decrypt(null, null, field); + + expect(view).toEqual({ + type: 0, + name: "encName", + value: "encValue", + newField: false, + showCount: false, + showValue: false, + }); + }); +}); diff --git a/libs/common/src/models/view/cipher/field.view.ts b/libs/common/src/models/view/cipher/field.view.ts new file mode 100644 index 000000000000..6d450b448b64 --- /dev/null +++ b/libs/common/src/models/view/cipher/field.view.ts @@ -0,0 +1,53 @@ +import { Jsonify } from "type-fest"; + +import { EncryptService } from "../../../abstractions/encrypt.service"; +import { FieldType } from "../../../enums/fieldType"; +import { LinkedIdType } from "../../../enums/linkedIdType"; +import { Field, SymmetricCryptoKey } from "../../domain"; +import { View } from "../view"; + +export class FieldView implements View { + name: string = null; + value: string = null; + type: FieldType = null; + newField = false; // Marks if the field is new and hasn't been saved + showValue = false; + showCount = false; + linkedId: LinkedIdType = null; + + get maskedValue(): string { + return this.value != null ? "••••••••" : null; + } + + async encrypt(encryptService: EncryptService, key: SymmetricCryptoKey): Promise { + const field = new Field(); + + field.type = this.type; + field.linkedId = this.linkedId; + + // normalize boolean type field values + if (this.type === FieldType.Boolean && this.value !== "true") { + this.value = "false"; + } + + field.name = this.name != null ? await encryptService.encrypt(this.name, key) : null; + field.value = this.value != null ? await encryptService.encrypt(this.value, key) : null; + + return field; + } + + static fromJSON(obj: Partial>): FieldView { + return Object.assign(new FieldView(), obj); + } + + static async decrypt(encryptService: EncryptService, key: SymmetricCryptoKey, model: Field) { + const view = new FieldView(); + + view.type = model.type; + view.linkedId = model.linkedId; + view.name = await model.name?.decryptWithEncryptService(encryptService, key); + view.value = await model.value?.decryptWithEncryptService(encryptService, key); + + return view; + } +} diff --git a/libs/common/src/models/view/cipher/identity.view.spec.ts b/libs/common/src/models/view/cipher/identity.view.spec.ts new file mode 100644 index 000000000000..3ba792f15c82 --- /dev/null +++ b/libs/common/src/models/view/cipher/identity.view.spec.ts @@ -0,0 +1,53 @@ +import { mockEnc } from "../../../../spec/utils"; +import { Identity } from "../../domain"; + +import { IdentityView } from "./identity.view"; + +describe("IdentityView", () => { + it("Decrypt", async () => { + const identity = new Identity(); + + identity.title = mockEnc("mockTitle"); + identity.firstName = mockEnc("mockFirstName"); + identity.middleName = mockEnc("mockMiddleName"); + identity.lastName = mockEnc("mockLastName"); + identity.address1 = mockEnc("mockAddress1"); + identity.address2 = mockEnc("mockAddress2"); + identity.address3 = mockEnc("mockAddress3"); + identity.city = mockEnc("mockCity"); + identity.state = mockEnc("mockState"); + identity.postalCode = mockEnc("mockPostalCode"); + identity.country = mockEnc("mockCountry"); + identity.company = mockEnc("mockCompany"); + identity.email = mockEnc("mockEmail"); + identity.phone = mockEnc("mockPhone"); + identity.ssn = mockEnc("mockSsn"); + identity.username = mockEnc("mockUsername"); + identity.passportNumber = mockEnc("mockPassportNumber"); + identity.licenseNumber = mockEnc("mockLicenseNumber"); + + const view = await IdentityView.decrypt(null, null, identity); + + expect(view).toEqual({ + _firstName: "mockFirstName", + _lastName: "mockLastName", + _subTitle: null, + address1: "mockAddress1", + address2: "mockAddress2", + address3: "mockAddress3", + city: "mockCity", + company: "mockCompany", + country: "mockCountry", + email: "mockEmail", + licenseNumber: "mockLicenseNumber", + middleName: "mockMiddleName", + passportNumber: "mockPassportNumber", + phone: "mockPhone", + postalCode: "mockPostalCode", + ssn: "mockSsn", + state: "mockState", + title: "mockTitle", + username: "mockUsername", + }); + }); +}); diff --git a/libs/common/src/models/view/cipher/identity.view.ts b/libs/common/src/models/view/cipher/identity.view.ts new file mode 100644 index 000000000000..16da89f16347 --- /dev/null +++ b/libs/common/src/models/view/cipher/identity.view.ts @@ -0,0 +1,275 @@ +import { Jsonify } from "type-fest"; + +import { EncryptService } from "../../../abstractions/encrypt.service"; +import { IdentityLinkedId as LinkedId } from "../../../enums/linkedIdType"; +import { Utils } from "../../../misc/utils"; +import { Identity, SymmetricCryptoKey } from "../../domain"; + +import { ItemView } from "./item.view"; +import { linkedFieldOption } from "./linked-field-option.decorator"; + +export class IdentityView extends ItemView { + @linkedFieldOption(LinkedId.Title) + title: string = null; + @linkedFieldOption(LinkedId.MiddleName) + middleName: string = null; + @linkedFieldOption(LinkedId.Address1) + address1: string = null; + @linkedFieldOption(LinkedId.Address2) + address2: string = null; + @linkedFieldOption(LinkedId.Address3) + address3: string = null; + @linkedFieldOption(LinkedId.City, "cityTown") + city: string = null; + @linkedFieldOption(LinkedId.State, "stateProvince") + state: string = null; + @linkedFieldOption(LinkedId.PostalCode, "zipPostalCode") + postalCode: string = null; + @linkedFieldOption(LinkedId.Country) + country: string = null; + @linkedFieldOption(LinkedId.Company) + company: string = null; + @linkedFieldOption(LinkedId.Email) + email: string = null; + @linkedFieldOption(LinkedId.Phone) + phone: string = null; + @linkedFieldOption(LinkedId.Ssn) + ssn: string = null; + @linkedFieldOption(LinkedId.Username) + username: string = null; + @linkedFieldOption(LinkedId.PassportNumber) + passportNumber: string = null; + @linkedFieldOption(LinkedId.LicenseNumber) + licenseNumber: string = null; + + private _firstName: string = null; + private _lastName: string = null; + private _subTitle: string = null; + + constructor() { + super(); + } + + @linkedFieldOption(LinkedId.FirstName) + get firstName(): string { + return this._firstName; + } + set firstName(value: string) { + this._firstName = value; + this._subTitle = null; + } + + @linkedFieldOption(LinkedId.LastName) + get lastName(): string { + return this._lastName; + } + set lastName(value: string) { + this._lastName = value; + this._subTitle = null; + } + + get subTitle(): string { + if (this._subTitle == null && (this.firstName != null || this.lastName != null)) { + this._subTitle = ""; + if (this.firstName != null) { + this._subTitle = this.firstName; + } + if (this.lastName != null) { + if (this._subTitle !== "") { + this._subTitle += " "; + } + this._subTitle += this.lastName; + } + } + + return this._subTitle; + } + + @linkedFieldOption(LinkedId.FullName) + get fullName(): string { + if ( + this.title != null || + this.firstName != null || + this.middleName != null || + this.lastName != null + ) { + let name = ""; + if (this.title != null) { + name += this.title + " "; + } + if (this.firstName != null) { + name += this.firstName + " "; + } + if (this.middleName != null) { + name += this.middleName + " "; + } + if (this.lastName != null) { + name += this.lastName; + } + return name.trim(); + } + + return null; + } + + get fullAddress(): string { + let address = this.address1; + if (!Utils.isNullOrWhitespace(this.address2)) { + if (!Utils.isNullOrWhitespace(address)) { + address += ", "; + } + address += this.address2; + } + if (!Utils.isNullOrWhitespace(this.address3)) { + if (!Utils.isNullOrWhitespace(address)) { + address += ", "; + } + address += this.address3; + } + return address; + } + + get fullAddressPart2(): string { + if (this.city == null && this.state == null && this.postalCode == null) { + return null; + } + const city = this.city || "-"; + const state = this.state; + const postalCode = this.postalCode || "-"; + let addressPart2 = city; + if (!Utils.isNullOrWhitespace(state)) { + addressPart2 += ", " + state; + } + addressPart2 += ", " + postalCode; + return addressPart2; + } + + async encrypt(encryptService: EncryptService, key: SymmetricCryptoKey): Promise { + const identity = new Identity(); + + /* + const fields: (keyof Identity & keyof IdentityView)[] = [ + "title", + "firstName", + "middleName", + "lastName", + "address1", + "address2", + "address3", + "city", + "state", + "postalCode", + "country", + "company", + "email", + "phone", + "ssn", + "username", + "passportNumber", + "licenseNumber", + ]; + + await Promise.all( + fields.map((field) => { + if (this[field] != null) { + return encryptService.encrypt(this[field], key).then((encrypted) => { + identity[field] = encrypted; + }); + } + }) + ); + */ + + [ + identity.title, + identity.firstName, + identity.middleName, + identity.lastName, + identity.address1, + identity.address2, + identity.address3, + identity.city, + identity.state, + identity.postalCode, + identity.country, + identity.company, + identity.email, + identity.phone, + identity.ssn, + identity.username, + identity.passportNumber, + identity.licenseNumber, + ] = await Promise.all([ + this.title ? encryptService.encrypt(this.title, key) : null, + this.firstName ? encryptService.encrypt(this.firstName, key) : null, + this.middleName ? encryptService.encrypt(this.middleName, key) : null, + this.lastName ? encryptService.encrypt(this.lastName, key) : null, + this.address1 ? encryptService.encrypt(this.address1, key) : null, + this.address2 ? encryptService.encrypt(this.address2, key) : null, + this.address3 ? encryptService.encrypt(this.address3, key) : null, + this.city ? encryptService.encrypt(this.city, key) : null, + this.state ? encryptService.encrypt(this.state, key) : null, + this.postalCode ? encryptService.encrypt(this.postalCode, key) : null, + this.country ? encryptService.encrypt(this.country, key) : null, + this.company ? encryptService.encrypt(this.company, key) : null, + this.email ? encryptService.encrypt(this.email, key) : null, + this.phone ? encryptService.encrypt(this.phone, key) : null, + this.ssn ? encryptService.encrypt(this.ssn, key) : null, + this.username ? encryptService.encrypt(this.username, key) : null, + this.passportNumber ? encryptService.encrypt(this.passportNumber, key) : null, + this.licenseNumber ? encryptService.encrypt(this.licenseNumber, key) : null, + ]); + + return identity; + } + + static fromJSON(obj: Partial>): IdentityView { + return Object.assign(new IdentityView(), obj); + } + + static async decrypt(encryptService: EncryptService, key: SymmetricCryptoKey, model: Identity) { + const view = new IdentityView(); + + [ + view.title, + view.firstName, + view.middleName, + view.lastName, + view.address1, + view.address2, + view.address3, + view.city, + view.state, + view.postalCode, + view.country, + view.company, + view.email, + view.phone, + view.ssn, + view.username, + view.passportNumber, + view.licenseNumber, + ] = await Promise.all([ + model.title?.decryptWithEncryptService(encryptService, key), + model.firstName?.decryptWithEncryptService(encryptService, key), + model.middleName?.decryptWithEncryptService(encryptService, key), + model.lastName?.decryptWithEncryptService(encryptService, key), + model.address1?.decryptWithEncryptService(encryptService, key), + model.address2?.decryptWithEncryptService(encryptService, key), + model.address3?.decryptWithEncryptService(encryptService, key), + model.city?.decryptWithEncryptService(encryptService, key), + model.state?.decryptWithEncryptService(encryptService, key), + model.postalCode?.decryptWithEncryptService(encryptService, key), + model.country?.decryptWithEncryptService(encryptService, key), + model.company?.decryptWithEncryptService(encryptService, key), + model.email?.decryptWithEncryptService(encryptService, key), + model.phone?.decryptWithEncryptService(encryptService, key), + model.ssn?.decryptWithEncryptService(encryptService, key), + model.username?.decryptWithEncryptService(encryptService, key), + model.passportNumber?.decryptWithEncryptService(encryptService, key), + model.licenseNumber?.decryptWithEncryptService(encryptService, key), + ]); + + return view; + } +} diff --git a/libs/common/src/models/view/cipher/index.ts b/libs/common/src/models/view/cipher/index.ts new file mode 100644 index 000000000000..d80a49ea441c --- /dev/null +++ b/libs/common/src/models/view/cipher/index.ts @@ -0,0 +1,10 @@ +export * from "./attachment.view"; +export * from "./card.view"; +export * from "./cipher.view"; +export * from "./field.view"; +export * from "./identity.view"; +export * from "./item.view"; +export * from "./login-uri.view"; +export * from "./login.view"; +export * from "./password-history.view"; +export * from "./secure-note.view"; diff --git a/libs/common/src/models/view/item.view.ts b/libs/common/src/models/view/cipher/item.view.ts similarity index 57% rename from libs/common/src/models/view/item.view.ts rename to libs/common/src/models/view/cipher/item.view.ts index 3a557ffa8597..4fc6ae4aae7a 100644 --- a/libs/common/src/models/view/item.view.ts +++ b/libs/common/src/models/view/cipher/item.view.ts @@ -1,6 +1,6 @@ -import { LinkedMetadata } from "../../misc/linkedFieldOption.decorator"; +import { View } from "../view"; -import { View } from "./view"; +import { LinkedMetadata } from "./linked-field-option.decorator"; export abstract class ItemView implements View { linkedFieldOptions: Map; diff --git a/libs/common/src/misc/linkedFieldOption.decorator.ts b/libs/common/src/models/view/cipher/linked-field-option.decorator.ts similarity index 90% rename from libs/common/src/misc/linkedFieldOption.decorator.ts rename to libs/common/src/models/view/cipher/linked-field-option.decorator.ts index 5296698a1285..da193f145d9a 100644 --- a/libs/common/src/misc/linkedFieldOption.decorator.ts +++ b/libs/common/src/models/view/cipher/linked-field-option.decorator.ts @@ -1,5 +1,6 @@ -import { LinkedIdType } from "../enums/linkedIdType"; -import { ItemView } from "../models/view/item.view"; +import { LinkedIdType } from "../../../enums/linkedIdType"; + +import { ItemView } from "./item.view"; export class LinkedMetadata { constructor(readonly propertyKey: string, private readonly _i18nKey?: string) {} diff --git a/libs/common/src/models/view/login-uri.view.ts b/libs/common/src/models/view/cipher/login-uri.view.ts similarity index 83% rename from libs/common/src/models/view/login-uri.view.ts rename to libs/common/src/models/view/cipher/login-uri.view.ts index b02d36cb3a77..243d0ea09c65 100644 --- a/libs/common/src/models/view/login-uri.view.ts +++ b/libs/common/src/models/view/cipher/login-uri.view.ts @@ -1,10 +1,10 @@ import { Jsonify } from "type-fest"; -import { UriMatchType } from "../../enums/uriMatchType"; -import { Utils } from "../../misc/utils"; -import { LoginUri } from "../domain/login-uri"; - -import { View } from "./view"; +import { EncryptService } from "../../../abstractions/encrypt.service"; +import { UriMatchType } from "../../../enums/uriMatchType"; +import { Utils } from "../../../misc/utils"; +import { LoginUri } from "../../domain"; +import { SymmetricCryptoKey } from "../../domain/symmetric-crypto-key"; const CanLaunchWhitelist = [ "https://", @@ -22,7 +22,7 @@ const CanLaunchWhitelist = [ "androidapp://", ]; -export class LoginUriView implements View { +export class LoginUriView { match: UriMatchType = null; private _uri: string = null; @@ -31,14 +31,6 @@ export class LoginUriView implements View { private _host: string = null; private _canLaunch: boolean = null; - constructor(u?: LoginUri) { - if (!u) { - return; - } - - this.match = u.match; - } - get uri(): string { return this._uri; } @@ -130,4 +122,13 @@ export class LoginUriView implements View { static fromJSON(obj: Partial>): LoginUriView { return Object.assign(new LoginUriView(), obj); } + + static async decrypt(encryptService: EncryptService, key: SymmetricCryptoKey, model: LoginUri) { + const view = new LoginUriView(); + + view.match = model.match; + view.uri = await model.uri?.decryptWithEncryptService(encryptService, key); + + return view; + } } diff --git a/libs/common/spec/models/view/loginView.spec.ts b/libs/common/src/models/view/cipher/login.view.spec.ts similarity index 70% rename from libs/common/spec/models/view/loginView.spec.ts rename to libs/common/src/models/view/cipher/login.view.spec.ts index 3f6f7da841b0..479d21f950fb 100644 --- a/libs/common/spec/models/view/loginView.spec.ts +++ b/libs/common/src/models/view/cipher/login.view.spec.ts @@ -1,9 +1,9 @@ -import { LoginUriView } from "@bitwarden/common/models/view/login-uri.view"; -import { LoginView } from "@bitwarden/common/models/view/login.view"; +import { mockFromJson } from "../../../../spec/utils"; -import { mockFromJson } from "../../utils"; +import { LoginUriView } from "./login-uri.view"; +import { LoginView } from "./login.view"; -jest.mock("@bitwarden/common/models/view/login-uri.view"); +jest.mock("./login-uri.view"); describe("LoginView", () => { beforeEach(() => { diff --git a/libs/common/src/models/view/cipher/login.view.ts b/libs/common/src/models/view/cipher/login.view.ts new file mode 100644 index 000000000000..acde69cf3e18 --- /dev/null +++ b/libs/common/src/models/view/cipher/login.view.ts @@ -0,0 +1,113 @@ +import { Jsonify } from "type-fest"; + +import { EncryptService } from "../../../abstractions/encrypt.service"; +import { LoginLinkedId as LinkedId } from "../../../enums/linkedIdType"; +import { nullableFactory } from "../../../interfaces/crypto.interface"; +import { Utils } from "../../../misc/utils"; +import { Login, SymmetricCryptoKey } from "../../domain"; + +import { ItemView } from "./item.view"; +import { linkedFieldOption } from "./linked-field-option.decorator"; +import { LoginUriView } from "./login-uri.view"; + +export class LoginView extends ItemView { + @linkedFieldOption(LinkedId.Username) + username: string = null; + @linkedFieldOption(LinkedId.Password) + password: string = null; + + passwordRevisionDate?: Date = null; + totp: string = null; + uris: LoginUriView[] = null; + autofillOnPageLoad: boolean = null; + + constructor(l?: Login) { + super(); + if (!l) { + return; + } + + this.passwordRevisionDate = l.passwordRevisionDate; + this.autofillOnPageLoad = l.autofillOnPageLoad; + } + + get uri(): string { + return this.hasUris ? this.uris[0].uri : null; + } + + get maskedPassword(): string { + return this.password != null ? "••••••••" : null; + } + + get subTitle(): string { + return this.username; + } + + get canLaunch(): boolean { + return this.hasUris && this.uris.some((u) => u.canLaunch); + } + + get hasTotp(): boolean { + return !Utils.isNullOrWhitespace(this.totp); + } + + get launchUri(): string { + if (this.hasUris) { + const uri = this.uris.find((u) => u.canLaunch); + if (uri != null) { + return uri.launchUri; + } + } + return null; + } + + get hasUris(): boolean { + return this.uris != null && this.uris.length > 0; + } + + async encrypt(encryptService: EncryptService, key: SymmetricCryptoKey): Promise { + const login = new Login(); + + login.passwordRevisionDate = this.passwordRevisionDate; + login.autofillOnPageLoad = this.autofillOnPageLoad; + + [login.username, login.password, login.totp] = await Promise.all([ + this.username ? encryptService.encrypt(this.username, key) : null, + this.password ? encryptService.encrypt(this.password, key) : null, + this.totp ? encryptService.encrypt(this.totp, key) : null, + ]); + + return login; + } + + static fromJSON(obj: Partial>): LoginView { + const passwordRevisionDate = nullableFactory(Date, obj.passwordRevisionDate); + const uris = obj.uris?.map((uri: any) => LoginUriView.fromJSON(uri)); + + return Object.assign(new LoginView(), obj, { + passwordRevisionDate: passwordRevisionDate, + uris: uris, + }); + } + + static async decrypt(encryptService: EncryptService, key: SymmetricCryptoKey, model: Login) { + const view = new LoginView(); + + view.passwordRevisionDate = model.passwordRevisionDate; + view.autofillOnPageLoad = model.autofillOnPageLoad; + + view.username = await model.username?.decryptWithEncryptService(encryptService, key); + view.password = await model.username?.decryptWithEncryptService(encryptService, key); + view.totp = await model.totp?.decryptWithEncryptService(encryptService, key); + + if (model.uris?.length > 0) { + view.uris = await Promise.all( + model.uris?.map((uri) => LoginUriView.decrypt(encryptService, key, uri)) + ); + } else { + view.uris = []; + } + + return view; + } +} diff --git a/libs/common/src/models/view/cipher/password-history.view.spec.ts b/libs/common/src/models/view/cipher/password-history.view.spec.ts new file mode 100644 index 000000000000..b04fb0ece9bd --- /dev/null +++ b/libs/common/src/models/view/cipher/password-history.view.spec.ts @@ -0,0 +1,29 @@ +import { mockEnc } from "../../../../spec/utils"; +import { Password } from "../../domain"; + +import { PasswordHistoryView } from "./password-history.view"; + +describe("PasswordHistoryView", () => { + it("fromJSON initializes nested objects", () => { + const lastUsedDate = new Date(); + + const actual = PasswordHistoryView.fromJSON({ + lastUsedDate: lastUsedDate.toISOString(), + }); + + expect(actual.lastUsedDate).toEqual(lastUsedDate); + }); + + it("Decrypt", async () => { + const password = new Password(); + password.password = mockEnc("password"); + password.lastUsedDate = new Date("2022-01-31T12:00:00.000Z"); + + const view = await PasswordHistoryView.decrypt(null, null, password); + + expect(view).toEqual({ + password: "password", + lastUsedDate: new Date("2022-01-31T12:00:00.000Z"), + }); + }); +}); diff --git a/libs/common/src/models/view/cipher/password-history.view.ts b/libs/common/src/models/view/cipher/password-history.view.ts new file mode 100644 index 000000000000..e99c3c690f3c --- /dev/null +++ b/libs/common/src/models/view/cipher/password-history.view.ts @@ -0,0 +1,37 @@ +import { Jsonify } from "type-fest"; + +import { EncryptService } from "../../../abstractions/encrypt.service"; +import { Password, SymmetricCryptoKey } from "../../domain"; +import { View } from "../view"; + +export class PasswordHistoryView implements View { + password: string = null; + lastUsedDate: Date = null; + + async encrypt(encryptService: EncryptService, key: SymmetricCryptoKey): Promise { + const password = new Password(); + + password.lastUsedDate = this.lastUsedDate; + password.password = + this.password != null ? await encryptService.encrypt(this.password, key) : null; + + return password; + } + + static fromJSON(obj: Partial>): PasswordHistoryView { + const lastUsedDate = obj.lastUsedDate == null ? null : new Date(obj.lastUsedDate); + + return Object.assign(new PasswordHistoryView(), obj, { + lastUsedDate: lastUsedDate, + }); + } + + static async decrypt(encryptService: EncryptService, key: SymmetricCryptoKey, model: Password) { + const view = new PasswordHistoryView(); + + view.lastUsedDate = model.lastUsedDate; + view.password = await model.password?.decryptWithEncryptService(encryptService, key); + + return view; + } +} diff --git a/libs/common/src/models/view/cipher/secure-note.view.spec.ts b/libs/common/src/models/view/cipher/secure-note.view.spec.ts new file mode 100644 index 000000000000..ba1550f834ac --- /dev/null +++ b/libs/common/src/models/view/cipher/secure-note.view.spec.ts @@ -0,0 +1,17 @@ +import { SecureNoteType } from "../../../enums/secureNoteType"; +import { SecureNote } from "../../domain"; + +import { SecureNoteView } from "./secure-note.view"; + +describe("SecureNoteView", () => { + it("Decrypt", async () => { + const model = new SecureNote(); + model.type = SecureNoteType.Generic; + + const view = await SecureNoteView.decrypt(null, null, model); + + expect(view).toEqual({ + type: 0, + }); + }); +}); diff --git a/libs/common/src/models/view/cipher/secure-note.view.ts b/libs/common/src/models/view/cipher/secure-note.view.ts new file mode 100644 index 000000000000..0a5cd0afd4c8 --- /dev/null +++ b/libs/common/src/models/view/cipher/secure-note.view.ts @@ -0,0 +1,46 @@ +import { Jsonify } from "type-fest"; + +import { EncryptService } from "../../../abstractions/encrypt.service"; +import { SecureNoteType } from "../../../enums/secureNoteType"; +import { SecureNote, SymmetricCryptoKey } from "../../domain"; + +import { ItemView } from "./item.view"; + +export class SecureNoteView extends ItemView { + type: SecureNoteType = null; + + constructor(n?: SecureNote) { + super(); + if (!n) { + return; + } + + this.type = n.type; + } + + get subTitle(): string { + return null; + } + + async encrypt(encryptService: EncryptService, key: SymmetricCryptoKey): Promise { + const note = new SecureNote(); + + note.type = this.type; + + return note; + } + + static fromJSON(obj: Partial>): SecureNoteView { + return Object.assign(new SecureNoteView(), obj); + } + + static async decrypt(encryptService: EncryptService, key: SymmetricCryptoKey, model: SecureNote) { + if (model == null) { + return null; + } + + const secureNote = new SecureNoteView(); + secureNote.type = model.type; + return secureNote; + } +} diff --git a/libs/common/src/models/view/field.view.ts b/libs/common/src/models/view/field.view.ts deleted file mode 100644 index a022ad6f61bd..000000000000 --- a/libs/common/src/models/view/field.view.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { Jsonify } from "type-fest"; - -import { FieldType } from "../../enums/fieldType"; -import { LinkedIdType } from "../../enums/linkedIdType"; -import { Field } from "../domain/field"; - -import { View } from "./view"; - -export class FieldView implements View { - name: string = null; - value: string = null; - type: FieldType = null; - newField = false; // Marks if the field is new and hasn't been saved - showValue = false; - showCount = false; - linkedId: LinkedIdType = null; - - constructor(f?: Field) { - if (!f) { - return; - } - - this.type = f.type; - this.linkedId = f.linkedId; - } - - get maskedValue(): string { - return this.value != null ? "••••••••" : null; - } - - static fromJSON(obj: Partial>): FieldView { - return Object.assign(new FieldView(), obj); - } -} diff --git a/libs/common/src/models/view/identity.view.ts b/libs/common/src/models/view/identity.view.ts deleted file mode 100644 index 343135417d30..000000000000 --- a/libs/common/src/models/view/identity.view.ts +++ /dev/null @@ -1,148 +0,0 @@ -import { Jsonify } from "type-fest"; - -import { IdentityLinkedId as LinkedId } from "../../enums/linkedIdType"; -import { linkedFieldOption } from "../../misc/linkedFieldOption.decorator"; -import { Utils } from "../../misc/utils"; - -import { ItemView } from "./item.view"; - -export class IdentityView extends ItemView { - @linkedFieldOption(LinkedId.Title) - title: string = null; - @linkedFieldOption(LinkedId.MiddleName) - middleName: string = null; - @linkedFieldOption(LinkedId.Address1) - address1: string = null; - @linkedFieldOption(LinkedId.Address2) - address2: string = null; - @linkedFieldOption(LinkedId.Address3) - address3: string = null; - @linkedFieldOption(LinkedId.City, "cityTown") - city: string = null; - @linkedFieldOption(LinkedId.State, "stateProvince") - state: string = null; - @linkedFieldOption(LinkedId.PostalCode, "zipPostalCode") - postalCode: string = null; - @linkedFieldOption(LinkedId.Country) - country: string = null; - @linkedFieldOption(LinkedId.Company) - company: string = null; - @linkedFieldOption(LinkedId.Email) - email: string = null; - @linkedFieldOption(LinkedId.Phone) - phone: string = null; - @linkedFieldOption(LinkedId.Ssn) - ssn: string = null; - @linkedFieldOption(LinkedId.Username) - username: string = null; - @linkedFieldOption(LinkedId.PassportNumber) - passportNumber: string = null; - @linkedFieldOption(LinkedId.LicenseNumber) - licenseNumber: string = null; - - private _firstName: string = null; - private _lastName: string = null; - private _subTitle: string = null; - - constructor() { - super(); - } - - @linkedFieldOption(LinkedId.FirstName) - get firstName(): string { - return this._firstName; - } - set firstName(value: string) { - this._firstName = value; - this._subTitle = null; - } - - @linkedFieldOption(LinkedId.LastName) - get lastName(): string { - return this._lastName; - } - set lastName(value: string) { - this._lastName = value; - this._subTitle = null; - } - - get subTitle(): string { - if (this._subTitle == null && (this.firstName != null || this.lastName != null)) { - this._subTitle = ""; - if (this.firstName != null) { - this._subTitle = this.firstName; - } - if (this.lastName != null) { - if (this._subTitle !== "") { - this._subTitle += " "; - } - this._subTitle += this.lastName; - } - } - - return this._subTitle; - } - - @linkedFieldOption(LinkedId.FullName) - get fullName(): string { - if ( - this.title != null || - this.firstName != null || - this.middleName != null || - this.lastName != null - ) { - let name = ""; - if (this.title != null) { - name += this.title + " "; - } - if (this.firstName != null) { - name += this.firstName + " "; - } - if (this.middleName != null) { - name += this.middleName + " "; - } - if (this.lastName != null) { - name += this.lastName; - } - return name.trim(); - } - - return null; - } - - get fullAddress(): string { - let address = this.address1; - if (!Utils.isNullOrWhitespace(this.address2)) { - if (!Utils.isNullOrWhitespace(address)) { - address += ", "; - } - address += this.address2; - } - if (!Utils.isNullOrWhitespace(this.address3)) { - if (!Utils.isNullOrWhitespace(address)) { - address += ", "; - } - address += this.address3; - } - return address; - } - - get fullAddressPart2(): string { - if (this.city == null && this.state == null && this.postalCode == null) { - return null; - } - const city = this.city || "-"; - const state = this.state; - const postalCode = this.postalCode || "-"; - let addressPart2 = city; - if (!Utils.isNullOrWhitespace(state)) { - addressPart2 += ", " + state; - } - addressPart2 += ", " + postalCode; - return addressPart2; - } - - static fromJSON(obj: Partial>): IdentityView { - return Object.assign(new IdentityView(), obj); - } -} diff --git a/libs/common/src/models/view/index.ts b/libs/common/src/models/view/index.ts new file mode 100644 index 000000000000..18c1e49b9c3d --- /dev/null +++ b/libs/common/src/models/view/index.ts @@ -0,0 +1 @@ +export * from "./cipher"; diff --git a/libs/common/src/models/view/login.view.ts b/libs/common/src/models/view/login.view.ts deleted file mode 100644 index ee4035d2dbc6..000000000000 --- a/libs/common/src/models/view/login.view.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { Jsonify } from "type-fest"; - -import { LoginLinkedId as LinkedId } from "../../enums/linkedIdType"; -import { linkedFieldOption } from "../../misc/linkedFieldOption.decorator"; -import { Utils } from "../../misc/utils"; -import { Login } from "../domain/login"; - -import { ItemView } from "./item.view"; -import { LoginUriView } from "./login-uri.view"; - -export class LoginView extends ItemView { - @linkedFieldOption(LinkedId.Username) - username: string = null; - @linkedFieldOption(LinkedId.Password) - password: string = null; - - passwordRevisionDate?: Date = null; - totp: string = null; - uris: LoginUriView[] = null; - autofillOnPageLoad: boolean = null; - - constructor(l?: Login) { - super(); - if (!l) { - return; - } - - this.passwordRevisionDate = l.passwordRevisionDate; - this.autofillOnPageLoad = l.autofillOnPageLoad; - } - - get uri(): string { - return this.hasUris ? this.uris[0].uri : null; - } - - get maskedPassword(): string { - return this.password != null ? "••••••••" : null; - } - - get subTitle(): string { - return this.username; - } - - get canLaunch(): boolean { - return this.hasUris && this.uris.some((u) => u.canLaunch); - } - - get hasTotp(): boolean { - return !Utils.isNullOrWhitespace(this.totp); - } - - get launchUri(): string { - if (this.hasUris) { - const uri = this.uris.find((u) => u.canLaunch); - if (uri != null) { - return uri.launchUri; - } - } - return null; - } - - get hasUris(): boolean { - return this.uris != null && this.uris.length > 0; - } - - static fromJSON(obj: Partial>): LoginView { - const passwordRevisionDate = - obj.passwordRevisionDate == null ? null : new Date(obj.passwordRevisionDate); - const uris = obj.uris?.map((uri: any) => LoginUriView.fromJSON(uri)); - - return Object.assign(new LoginView(), obj, { - passwordRevisionDate: passwordRevisionDate, - uris: uris, - }); - } -} diff --git a/libs/common/src/models/view/password-history.view.ts b/libs/common/src/models/view/password-history.view.ts deleted file mode 100644 index 1d0b9eb8dda5..000000000000 --- a/libs/common/src/models/view/password-history.view.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { Jsonify } from "type-fest"; - -import { Password } from "../domain/password"; - -import { View } from "./view"; - -export class PasswordHistoryView implements View { - password: string = null; - lastUsedDate: Date = null; - - constructor(ph?: Password) { - if (!ph) { - return; - } - - this.lastUsedDate = ph.lastUsedDate; - } - - static fromJSON(obj: Partial>): PasswordHistoryView { - const lastUsedDate = obj.lastUsedDate == null ? null : new Date(obj.lastUsedDate); - - return Object.assign(new PasswordHistoryView(), obj, { - lastUsedDate: lastUsedDate, - }); - } -} diff --git a/libs/common/src/models/view/secure-note.view.ts b/libs/common/src/models/view/secure-note.view.ts deleted file mode 100644 index 20174f985562..000000000000 --- a/libs/common/src/models/view/secure-note.view.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { Jsonify } from "type-fest"; - -import { SecureNoteType } from "../../enums/secureNoteType"; -import { SecureNote } from "../domain/secure-note"; - -import { ItemView } from "./item.view"; - -export class SecureNoteView extends ItemView { - type: SecureNoteType = null; - - constructor(n?: SecureNote) { - super(); - if (!n) { - return; - } - - this.type = n.type; - } - - get subTitle(): string { - return null; - } - - static fromJSON(obj: Partial>): SecureNoteView { - return Object.assign(new SecureNoteView(), obj); - } -} diff --git a/libs/common/src/services/cipher.service.ts b/libs/common/src/services/cipher.service.ts index b93c60d62285..f871f416eb34 100644 --- a/libs/common/src/services/cipher.service.ts +++ b/libs/common/src/services/cipher.service.ts @@ -11,24 +11,15 @@ import { SearchService } from "../abstractions/search.service"; import { SettingsService } from "../abstractions/settings.service"; import { StateService } from "../abstractions/state.service"; import { CipherType } from "../enums/cipherType"; -import { FieldType } from "../enums/fieldType"; import { UriMatchType } from "../enums/uriMatchType"; import { sequentialize } from "../misc/sequentialize"; import { Utils } from "../misc/utils"; import { CipherData } from "../models/data/cipher.data"; +import { Cipher } from "../models/domain"; import { AccountSettingsSettings } from "../models/domain/account"; -import { Attachment } from "../models/domain/attachment"; -import { Card } from "../models/domain/card"; -import { Cipher } from "../models/domain/cipher"; import Domain from "../models/domain/domain-base"; import { EncArrayBuffer } from "../models/domain/enc-array-buffer"; import { EncString } from "../models/domain/enc-string"; -import { Field } from "../models/domain/field"; -import { Identity } from "../models/domain/identity"; -import { Login } from "../models/domain/login"; -import { LoginUri } from "../models/domain/login-uri"; -import { Password } from "../models/domain/password"; -import { SecureNote } from "../models/domain/secure-note"; import { SortedCiphersCache } from "../models/domain/sorted-ciphers-cache"; import { SymmetricCryptoKey } from "../models/domain/symmetric-crypto-key"; import { AttachmentRequest } from "../models/request/attachment.request"; @@ -43,10 +34,7 @@ import { CipherShareRequest } from "../models/request/cipher-share.request"; import { CipherRequest } from "../models/request/cipher.request"; import { CipherResponse } from "../models/response/cipher.response"; import { ErrorResponse } from "../models/response/error.response"; -import { AttachmentView } from "../models/view/attachment.view"; -import { CipherView } from "../models/view/cipher.view"; -import { FieldView } from "../models/view/field.view"; -import { PasswordHistoryView } from "../models/view/password-history.view"; +import { CipherView, AttachmentView } from "../models/view"; import { View } from "../models/view/view"; const DomainMatchBlacklist = new Map>([ @@ -90,219 +78,16 @@ export class CipherService implements CipherServiceAbstraction { await this.clearDecryptedCiphersState(userId); } - async encrypt( - model: CipherView, - key?: SymmetricCryptoKey, - originalCipher: Cipher = null - ): Promise { - // Adjust password history - if (model.id != null) { - if (originalCipher == null) { - originalCipher = await this.get(model.id); - } - if (originalCipher != null) { - const existingCipher = await originalCipher.decrypt(); - model.passwordHistory = existingCipher.passwordHistory || []; - if (model.type === CipherType.Login && existingCipher.type === CipherType.Login) { - if ( - existingCipher.login.password != null && - existingCipher.login.password !== "" && - existingCipher.login.password !== model.login.password - ) { - const ph = new PasswordHistoryView(); - ph.password = existingCipher.login.password; - ph.lastUsedDate = model.login.passwordRevisionDate = new Date(); - model.passwordHistory.splice(0, 0, ph); - } else { - model.login.passwordRevisionDate = existingCipher.login.passwordRevisionDate; - } - } - if (existingCipher.hasFields) { - const existingHiddenFields = existingCipher.fields.filter( - (f) => - f.type === FieldType.Hidden && - f.name != null && - f.name !== "" && - f.value != null && - f.value !== "" - ); - const hiddenFields = - model.fields == null - ? [] - : model.fields.filter( - (f) => f.type === FieldType.Hidden && f.name != null && f.name !== "" - ); - existingHiddenFields.forEach((ef) => { - const matchedField = hiddenFields.find((f) => f.name === ef.name); - if (matchedField == null || matchedField.value !== ef.value) { - const ph = new PasswordHistoryView(); - ph.password = ef.name + ": " + ef.value; - ph.lastUsedDate = new Date(); - model.passwordHistory.splice(0, 0, ph); - } - }); - } - } - if (model.passwordHistory != null && model.passwordHistory.length === 0) { - model.passwordHistory = null; - } else if (model.passwordHistory != null && model.passwordHistory.length > 5) { - // only save last 5 history - model.passwordHistory = model.passwordHistory.slice(0, 5); - } - } - - const cipher = new Cipher(); - cipher.id = model.id; - cipher.folderId = model.folderId; - cipher.favorite = model.favorite; - cipher.organizationId = model.organizationId; - cipher.type = model.type; - cipher.collectionIds = model.collectionIds; - cipher.revisionDate = model.revisionDate; - cipher.reprompt = model.reprompt; - cipher.edit = model.edit; - - if (key == null && cipher.organizationId != null) { - key = await this.cryptoService.getOrgKey(cipher.organizationId); - if (key == null) { - throw new Error("Cannot encrypt cipher for organization. No key."); - } - } - await Promise.all([ - this.encryptObjProperty( - model, - cipher, - { - name: null, - notes: null, - }, - key - ), - this.encryptCipherData(cipher, model, key), - this.encryptFields(model.fields, key).then((fields) => { - cipher.fields = fields; - }), - this.encryptPasswordHistories(model.passwordHistory, key).then((ph) => { - cipher.passwordHistory = ph; - }), - this.encryptAttachments(model.attachments, key).then((attachments) => { - cipher.attachments = attachments; - }), - ]); - - return cipher; - } - - async encryptAttachments( - attachmentsModel: AttachmentView[], - key: SymmetricCryptoKey - ): Promise { - if (attachmentsModel == null || attachmentsModel.length === 0) { - return null; - } - - const promises: Promise[] = []; - const encAttachments: Attachment[] = []; - attachmentsModel.forEach(async (model) => { - const attachment = new Attachment(); - attachment.id = model.id; - attachment.size = model.size; - attachment.sizeName = model.sizeName; - attachment.url = model.url; - const promise = this.encryptObjProperty( - model, - attachment, - { - fileName: null, - }, - key - ).then(async () => { - if (model.key != null) { - attachment.key = await this.cryptoService.encrypt(model.key.key, key); - } - encAttachments.push(attachment); - }); - promises.push(promise); - }); - - await Promise.all(promises); - return encAttachments; - } - - async encryptFields(fieldsModel: FieldView[], key: SymmetricCryptoKey): Promise { - if (!fieldsModel || !fieldsModel.length) { - return null; - } - - const self = this; - const encFields: Field[] = []; - await fieldsModel.reduce(async (promise, field) => { - await promise; - const encField = await self.encryptField(field, key); - encFields.push(encField); - }, Promise.resolve()); - - return encFields; - } - - async encryptField(fieldModel: FieldView, key: SymmetricCryptoKey): Promise { - const field = new Field(); - field.type = fieldModel.type; - field.linkedId = fieldModel.linkedId; - // normalize boolean type field values - if (fieldModel.type === FieldType.Boolean && fieldModel.value !== "true") { - fieldModel.value = "false"; - } - - await this.encryptObjProperty( - fieldModel, - field, - { - name: null, - value: null, - }, - key - ); - - return field; - } - - async encryptPasswordHistories( - phModels: PasswordHistoryView[], - key: SymmetricCryptoKey - ): Promise { - if (!phModels || !phModels.length) { - return null; - } - - const self = this; - const encPhs: Password[] = []; - await phModels.reduce(async (promise, ph) => { - await promise; - const encPh = await self.encryptPasswordHistory(ph, key); - encPhs.push(encPh); - }, Promise.resolve()); - - return encPhs; - } - - async encryptPasswordHistory( - phModel: PasswordHistoryView, - key: SymmetricCryptoKey - ): Promise { - const ph = new Password(); - ph.lastUsedDate = phModel.lastUsedDate; - - await this.encryptObjProperty( - phModel, - ph, - { - password: null, - }, - key - ); + /** + * Update the password history and encrypt the CipherView + * + * @param cipher The CipherView to encrypt + * @param originalCipher The original Cipher + */ + async updateHistoryAndEncrypt(view: CipherView, originalCipher: Cipher): Promise { + // TODO: Update history - return ph; + return await this.cryptoService.encryptView(view); } async get(id: string): Promise { @@ -355,7 +140,11 @@ export class CipherService implements CipherServiceAbstraction { const decCiphers = ( await Promise.all( Object.entries(grouped).map(([orgId, groupedCiphers]) => - this.encryptService.decryptItems(groupedCiphers, orgKeys.get(orgId) ?? userKey) + this.encryptService.decryptItems( + CipherView, + groupedCiphers, + orgKeys.get(orgId) ?? userKey + ) ) ) ) @@ -512,7 +301,7 @@ export class CipherService implements CipherServiceAbstraction { const ciphers = response.data.map((cr) => new Cipher(new CipherData(cr))); const key = await this.cryptoService.getOrgKey(organizationId); - const decCiphers = await this.encryptService.decryptItems(ciphers, key); + const decCiphers = await this.encryptService.decryptItems(CipherView, ciphers, key); decCiphers.sort(this.getLocaleSortingFunction()); return decCiphers; @@ -657,7 +446,7 @@ export class CipherService implements CipherServiceAbstraction { cipher.organizationId = organizationId; cipher.collectionIds = collectionIds; - const encCipher = await this.encrypt(cipher); + const encCipher = await this.cryptoService.encryptView(cipher); const request = new CipherShareRequest(encCipher); const response = await this.apiService.putShareCipher(cipher.id, request); const data = new CipherData(response, collectionIds); @@ -675,7 +464,7 @@ export class CipherService implements CipherServiceAbstraction { cipher.organizationId = organizationId; cipher.collectionIds = collectionIds; promises.push( - this.encrypt(cipher).then((c) => { + this.cryptoService.encryptView(cipher).then((c) => { encCiphers.push(c); }) ); @@ -1162,93 +951,6 @@ export class CipherService implements CipherServiceAbstraction { await Promise.all(promises); } - private async encryptCipherData(cipher: Cipher, model: CipherView, key: SymmetricCryptoKey) { - switch (cipher.type) { - case CipherType.Login: - cipher.login = new Login(); - cipher.login.passwordRevisionDate = model.login.passwordRevisionDate; - cipher.login.autofillOnPageLoad = model.login.autofillOnPageLoad; - await this.encryptObjProperty( - model.login, - cipher.login, - { - username: null, - password: null, - totp: null, - }, - key - ); - - if (model.login.uris != null) { - cipher.login.uris = []; - for (let i = 0; i < model.login.uris.length; i++) { - const loginUri = new LoginUri(); - loginUri.match = model.login.uris[i].match; - await this.encryptObjProperty( - model.login.uris[i], - loginUri, - { - uri: null, - }, - key - ); - cipher.login.uris.push(loginUri); - } - } - return; - case CipherType.SecureNote: - cipher.secureNote = new SecureNote(); - cipher.secureNote.type = model.secureNote.type; - return; - case CipherType.Card: - cipher.card = new Card(); - await this.encryptObjProperty( - model.card, - cipher.card, - { - cardholderName: null, - brand: null, - number: null, - expMonth: null, - expYear: null, - code: null, - }, - key - ); - return; - case CipherType.Identity: - cipher.identity = new Identity(); - await this.encryptObjProperty( - model.identity, - cipher.identity, - { - title: null, - firstName: null, - middleName: null, - lastName: null, - address1: null, - address2: null, - address3: null, - city: null, - state: null, - postalCode: null, - country: null, - company: null, - email: null, - phone: null, - ssn: null, - username: null, - passportNumber: null, - licenseNumber: null, - }, - key - ); - return; - default: - throw new Error("Unknown cipher type."); - } - } - private async getCipherForUrl( url: string, lastUsed: boolean, diff --git a/libs/common/src/services/cryptography/encrypt.service.implementation.ts b/libs/common/src/services/cryptography/encrypt.service.implementation.ts index e9e5aee6b669..10648df05ca3 100644 --- a/libs/common/src/services/cryptography/encrypt.service.implementation.ts +++ b/libs/common/src/services/cryptography/encrypt.service.implementation.ts @@ -9,7 +9,6 @@ import { Encryptable, EncryptableDomain, } from "../../interfaces/crypto.interface"; -import { OldDecryptable } from "../../interfaces/decryptable.interface"; import { InitializerMetadata } from "../../interfaces/initializer-metadata.interface"; import { Utils } from "../../misc/utils"; import { EncArrayBuffer } from "../../models/domain/enc-array-buffer"; @@ -156,15 +155,16 @@ export class EncryptServiceImplementation implements EncryptService { return result ?? null; } - async decryptItems( - items: OldDecryptable[], + async decryptItems( + view: Decryptable & InitializerMetadata, + items: D[], key: SymmetricCryptoKey - ): Promise { + ): Promise { if (items == null || items.length < 1) { return []; } - return await Promise.all(items.map((item) => item.decrypt(key))); + return await Promise.all(items.map((item) => this.decryptDomain(view, item, key))); } async decryptDomain( diff --git a/libs/common/src/services/cryptography/encrypt.worker.ts b/libs/common/src/services/cryptography/encrypt.worker.ts index 8d15286883f0..2ee38a3402cc 100644 --- a/libs/common/src/services/cryptography/encrypt.worker.ts +++ b/libs/common/src/services/cryptography/encrypt.worker.ts @@ -1,13 +1,15 @@ import { Jsonify } from "type-fest"; -import { OldDecryptable } from "../../interfaces/decryptable.interface"; +import { Decryptable, DecryptableDomain } from "../../interfaces/crypto.interface"; +import { InitializerMetadata } from "../../interfaces/initializer-metadata.interface"; import { SymmetricCryptoKey } from "../../models/domain/symmetric-crypto-key"; import { ConsoleLogService } from "../../services/consoleLog.service"; import { ContainerService } from "../../services/container.service"; import { WebCryptoFunctionService } from "../../services/webCryptoFunction.service"; import { EncryptServiceImplementation } from "./encrypt.service.implementation"; -import { getClassInitializer } from "./get-class-initializer"; +import { getClass, getClassInitializer } from "./get-class-initializer"; +import { InitializerKey } from "./initializer-key"; const workerApi: Worker = self as any; @@ -38,16 +40,22 @@ workerApi.addEventListener("message", async (event: { data: string }) => { const request: { id: string; - items: Jsonify>[]; + view: InitializerKey; + items: Jsonify[]; key: Jsonify; } = JSON.parse(event.data); const key = SymmetricCryptoKey.fromJSON(request.key); const items = request.items.map((jsonItem) => { - const initializer = getClassInitializer>(jsonItem.initializerKey); + const initializer = getClassInitializer(jsonItem.initializerKey); return initializer(jsonItem); }); - const result = await encryptService.decryptItems(items, key); + + const view = getClass & InitializerMetadata>( + request.view + ); + + const result = await encryptService.decryptItems(view as any, items as any, key); workerApi.postMessage({ id: request.id, diff --git a/libs/common/src/services/cryptography/get-class-initializer.ts b/libs/common/src/services/cryptography/get-class-initializer.ts index accdb1c4a4fc..5b6371566364 100644 --- a/libs/common/src/services/cryptography/get-class-initializer.ts +++ b/libs/common/src/services/cryptography/get-class-initializer.ts @@ -2,7 +2,7 @@ import { Jsonify } from "type-fest"; import { InitializerMetadata } from "../../interfaces/initializer-metadata.interface"; import { Cipher } from "../../models/domain/cipher"; -import { CipherView } from "../../models/view/cipher.view"; +import { CipherView } from "../../models/view"; import { InitializerKey } from "./initializer-key"; @@ -15,8 +15,16 @@ const classInitializers: Record any> = { [InitializerKey.CipherView]: CipherView.fromJSON, }; +const classes: Partial> = { + [InitializerKey.CipherView]: CipherView, +}; + export function getClassInitializer( className: InitializerKey ): (obj: Jsonify) => T { return classInitializers[className]; } + +export function getClass(className: InitializerKey): (a: any) => T { + return classes[className]; +} diff --git a/libs/common/src/services/cryptography/multithread-encrypt.service.implementation.ts b/libs/common/src/services/cryptography/multithread-encrypt.service.implementation.ts index 28b4a705f40d..18f984a714a3 100644 --- a/libs/common/src/services/cryptography/multithread-encrypt.service.implementation.ts +++ b/libs/common/src/services/cryptography/multithread-encrypt.service.implementation.ts @@ -1,13 +1,12 @@ import { defaultIfEmpty, filter, firstValueFrom, fromEvent, map, Subject, takeUntil } from "rxjs"; import { Jsonify } from "type-fest"; -import { OldDecryptable } from "../../interfaces/decryptable.interface"; +import { Decryptable, DecryptableDomain } from "../../interfaces/crypto.interface"; import { InitializerMetadata } from "../../interfaces/initializer-metadata.interface"; import { Utils } from "../../misc/utils"; import { SymmetricCryptoKey } from "../../models/domain/symmetric-crypto-key"; import { EncryptServiceImplementation } from "./encrypt.service.implementation"; -import { getClassInitializer } from "./get-class-initializer"; // TTL (time to live) is not strictly required but avoids tying up memory resources if inactive const workerTTL = 3 * 60000; // 3 minutes @@ -22,10 +21,11 @@ export class MultithreadEncryptServiceImplementation extends EncryptServiceImple * Sends items to a web worker to decrypt them. * This utilises multithreading to decrypt items faster without interrupting other operations (e.g. updating UI). */ - async decryptItems( - items: OldDecryptable[], + async decryptItems( + view: Decryptable & InitializerMetadata, + items: D[], key: SymmetricCryptoKey - ): Promise { + ): Promise { if (items == null || items.length < 1) { return []; } @@ -44,6 +44,7 @@ export class MultithreadEncryptServiceImplementation extends EncryptServiceImple const request = { id: Utils.newGuid(), + view: view.initializerKey, items: items, key: key, }; @@ -55,9 +56,8 @@ export class MultithreadEncryptServiceImplementation extends EncryptServiceImple filter((response: MessageEvent) => response.data?.id === request.id), map((response) => JSON.parse(response.data.items)), map((items) => - items.map((jsonItem: Jsonify) => { - const initializer = getClassInitializer(jsonItem.initializerKey); - return initializer(jsonItem); + items.map((jsonItem: Jsonify) => { + return view.fromJSON(jsonItem); }) ), takeUntil(this.clear$), diff --git a/libs/common/src/services/export.service.ts b/libs/common/src/services/export.service.ts index 690701b83eae..60ebc1e5621a 100644 --- a/libs/common/src/services/export.service.ts +++ b/libs/common/src/services/export.service.ts @@ -14,7 +14,7 @@ import { DEFAULT_KDF_ITERATIONS, KdfType } from "../enums/kdfType"; import { Utils } from "../misc/utils"; import { CipherData } from "../models/data/cipher.data"; import { CollectionData } from "../models/data/collection.data"; -import { Cipher } from "../models/domain/cipher"; +import { Cipher } from "../models/domain"; import { Collection } from "../models/domain/collection"; import { Folder } from "../models/domain/folder"; import { CipherWithIdExport as CipherExport } from "../models/export/cipher-with-ids.export"; @@ -22,7 +22,7 @@ import { CollectionWithIdExport as CollectionExport } from "../models/export/col import { EventExport } from "../models/export/event.export"; import { FolderWithIdExport as FolderExport } from "../models/export/folder-with-id.export"; import { CollectionDetailsResponse } from "../models/response/collection.response"; -import { CipherView } from "../models/view/cipher.view"; +import { CipherView } from "../models/view"; import { CollectionView } from "../models/view/collection.view"; import { EventView } from "../models/view/event.view"; import { FolderView } from "../models/view/folder.view"; @@ -262,11 +262,7 @@ export class ExportService implements ExportServiceAbstraction { .filter((c) => c.deletedDate === null) .forEach((c) => { const cipher = new Cipher(new CipherData(c)); - exportPromises.push( - cipher.decrypt().then((decCipher) => { - decCiphers.push(decCipher); - }) - ); + exportPromises.push(this.cryptoService.decryptDomain(CipherView, cipher)); }); } } diff --git a/libs/common/src/services/import.service.ts b/libs/common/src/services/import.service.ts index e6c653002035..92a10f467b4f 100644 --- a/libs/common/src/services/import.service.ts +++ b/libs/common/src/services/import.service.ts @@ -2,7 +2,6 @@ import { ApiService } from "../abstractions/api.service"; import { CipherService } from "../abstractions/cipher.service"; import { CollectionService } from "../abstractions/collection.service"; import { CryptoService } from "../abstractions/crypto.service"; -import { FolderService } from "../abstractions/folder/folder.service.abstraction"; import { I18nService } from "../abstractions/i18n.service"; import { ImportService as ImportServiceAbstraction } from "../abstractions/import.service"; import { CipherType } from "../enums/cipherType"; @@ -80,7 +79,7 @@ import { ImportCiphersRequest } from "../models/request/import-ciphers.request"; import { ImportOrganizationCiphersRequest } from "../models/request/import-organization-ciphers.request"; import { KvpRequest } from "../models/request/kvp.request"; import { ErrorResponse } from "../models/response/error.response"; -import { CipherView } from "../models/view/cipher.view"; +import { CipherView } from "../models/view"; export class ImportService implements ImportServiceAbstraction { featuredImportOptions = featuredImportOptions as readonly ImportOption[]; @@ -89,7 +88,6 @@ export class ImportService implements ImportServiceAbstraction { constructor( private cipherService: CipherService, - private folderService: FolderService, private apiService: ApiService, private i18nService: I18nService, private collectionService: CollectionService, @@ -291,7 +289,7 @@ export class ImportService implements ImportServiceAbstraction { if (organizationId == null) { const request = new ImportCiphersRequest(); for (let i = 0; i < importResult.ciphers.length; i++) { - const c = await this.cipherService.encrypt(importResult.ciphers[i]); + const c = await this.cryptoService.encryptView(importResult.ciphers[i]); request.ciphers.push(new CipherRequest(c)); } if (importResult.folders != null) { @@ -310,7 +308,7 @@ export class ImportService implements ImportServiceAbstraction { const request = new ImportOrganizationCiphersRequest(); for (let i = 0; i < importResult.ciphers.length; i++) { importResult.ciphers[i].organizationId = organizationId; - const c = await this.cipherService.encrypt(importResult.ciphers[i]); + const c = await this.cryptoService.encryptView(importResult.ciphers[i]); request.ciphers.push(new CipherRequest(c)); } if (importResult.collections != null) { diff --git a/libs/common/src/services/search.service.ts b/libs/common/src/services/search.service.ts index 05f2423b17b9..72add7ff99a6 100644 --- a/libs/common/src/services/search.service.ts +++ b/libs/common/src/services/search.service.ts @@ -7,7 +7,7 @@ import { SearchService as SearchServiceAbstraction } from "../abstractions/searc import { CipherType } from "../enums/cipherType"; import { FieldType } from "../enums/fieldType"; import { UriMatchType } from "../enums/uriMatchType"; -import { CipherView } from "../models/view/cipher.view"; +import { CipherView } from "../models/view"; import { SendView } from "../models/view/send.view"; export class SearchService implements SearchServiceAbstraction { diff --git a/libs/common/src/services/state.service.ts b/libs/common/src/services/state.service.ts index f55ccc393141..3d6347c8374b 100644 --- a/libs/common/src/services/state.service.ts +++ b/libs/common/src/services/state.service.ts @@ -41,7 +41,7 @@ import { State } from "../models/domain/state"; import { StorageOptions } from "../models/domain/storage-options"; import { SymmetricCryptoKey } from "../models/domain/symmetric-crypto-key"; import { WindowState } from "../models/domain/window-state"; -import { CipherView } from "../models/view/cipher.view"; +import { CipherView } from "../models/view"; import { CollectionView } from "../models/view/collection.view"; import { SendView } from "../models/view/send.view";