From 596e041c42882475ef7e30282ec77991c703d420 Mon Sep 17 00:00:00 2001 From: Mo Date: Tue, 25 Jul 2023 07:40:28 -0500 Subject: [PATCH] tests: vault tests (#2366) --- .../Application/ApplicationInterface.ts | 37 +++-- .../AsymmetricMessageService.spec.ts | 2 +- .../AsymmetricMessageService.ts | 2 +- .../UseCase/HandleRootKeyChangedMessage.ts | 2 +- .../SharedVaults/SharedVaultService.spec.ts | 2 +- .../Domain/SharedVaults/SharedVaultService.ts | 4 +- .../UseCase/ConvertToSharedVault.ts | 2 +- .../SharedVaults/UseCase/CreateSharedVault.ts | 4 +- .../SharedVaults/UseCase/DeleteSharedVault.ts | 2 +- .../SharedVaults/UseCase/GetSharedVaults.ts | 2 +- .../UseCase/ChangeVaultKeyOptions.ts | 4 +- .../UseCase/ChangeVaultKeyOptionsDTO.ts} | 2 +- .../{Vaults => Vault}/UseCase/CreateVault.ts | 2 +- .../{Vaults => Vault}/UseCase/DeleteVault.ts | 0 .../{Vaults => Vault}/UseCase/GetVault.ts | 2 +- .../{Vaults => Vault}/UseCase/GetVaults.ts | 0 .../UseCase/MoveItemsToVault.ts | 0 .../UseCase/RemoveItemFromVault.ts | 0 .../UseCase/RotateVaultKey.ts | 0 .../Domain/{Vaults => Vault}/VaultService.ts | 156 ++++-------------- .../{Vaults => Vault}/VaultServiceEvent.ts | 8 - .../VaultServiceInterface.ts | 14 +- .../Domain/VaultInvite/VaultInviteService.ts | 2 +- .../src/Domain/VaultLock/VaultLockService.ts | 133 +++++++++++++++ .../Domain/VaultLock/VaultLockServiceEvent.ts | 15 ++ .../VaultLock/VaultLockServiceInterface.ts | 12 ++ .../src/Domain/VaultUser/VaultUserService.ts | 8 +- packages/services/src/Domain/index.ts | 27 +-- packages/snjs/lib/Application/Application.ts | 29 ++-- .../Application/Dependencies/Dependencies.ts | 15 +- .../lib/Application/Dependencies/Types.ts | 1 + .../snjs/mocha/TestRegistry/VaultTests.js | 1 + packages/snjs/mocha/lib/AppContext.js | 12 +- packages/snjs/mocha/lib/Collaboration.js | 22 ++- packages/snjs/mocha/test.html | 2 +- packages/snjs/mocha/vaults/deletion.test.js | 12 +- packages/snjs/mocha/vaults/invites.test.js | 4 - packages/snjs/mocha/vaults/items.test.js | 24 ++- .../snjs/mocha/vaults/key_rotation.test.js | 32 ---- packages/snjs/mocha/vaults/locking.test.js | 108 ++++++++++++ packages/snjs/mocha/vaults/vaults.test.js | 11 -- .../src/Vaults/VaultDisplayService.ts | 24 +-- .../Panes/Vaults/Vaults/VaultItem.tsx | 4 +- .../Vaults/VaultModal/EditVaultModal.tsx | 7 +- .../ManyVaultSelectionMenu.tsx | 2 +- .../SingleVaultSelectionMenu.tsx | 2 +- .../Vaults/AddToVaultMenuOption.tsx | 12 +- 47 files changed, 479 insertions(+), 289 deletions(-) rename packages/services/src/Domain/{Vaults => Vault}/UseCase/ChangeVaultKeyOptions.ts (97%) rename packages/services/src/Domain/{Vaults/ChangeVaultOptionsDTO.ts => Vault/UseCase/ChangeVaultKeyOptionsDTO.ts} (90%) rename packages/services/src/Domain/{Vaults => Vault}/UseCase/CreateVault.ts (98%) rename packages/services/src/Domain/{Vaults => Vault}/UseCase/DeleteVault.ts (100%) rename packages/services/src/Domain/{Vaults => Vault}/UseCase/GetVault.ts (93%) rename packages/services/src/Domain/{Vaults => Vault}/UseCase/GetVaults.ts (100%) rename packages/services/src/Domain/{Vaults => Vault}/UseCase/MoveItemsToVault.ts (100%) rename packages/services/src/Domain/{Vaults => Vault}/UseCase/RemoveItemFromVault.ts (100%) rename packages/services/src/Domain/{Vaults => Vault}/UseCase/RotateVaultKey.ts (100%) rename packages/services/src/Domain/{Vaults => Vault}/VaultService.ts (64%) rename packages/services/src/Domain/{Vaults => Vault}/VaultServiceEvent.ts (55%) rename packages/services/src/Domain/{Vaults => Vault}/VaultServiceInterface.ts (74%) create mode 100644 packages/services/src/Domain/VaultLock/VaultLockService.ts create mode 100644 packages/services/src/Domain/VaultLock/VaultLockServiceEvent.ts create mode 100644 packages/services/src/Domain/VaultLock/VaultLockServiceInterface.ts create mode 100644 packages/snjs/mocha/vaults/locking.test.js diff --git a/packages/services/src/Domain/Application/ApplicationInterface.ts b/packages/services/src/Domain/Application/ApplicationInterface.ts index 99ed39023..62484c4db 100644 --- a/packages/services/src/Domain/Application/ApplicationInterface.ts +++ b/packages/services/src/Domain/Application/ApplicationInterface.ts @@ -1,3 +1,5 @@ +import { VaultUserServiceInterface, VaultInviteServiceInterface } from '@standardnotes/services' +import { VaultLockServiceInterface } from './../VaultLock/VaultLockServiceInterface' import { HistoryServiceInterface } from './../History/HistoryServiceInterface' import { InternalEventBusInterface } from './../Internal/InternalEventBusInterface' import { PreferenceServiceInterface } from './../Preferences/PreferenceServiceInterface' @@ -5,7 +7,7 @@ import { AsymmetricMessageServiceInterface } from './../AsymmetricMessage/Asymme import { SyncOptions } from './../Sync/SyncOptions' import { ImportDataReturnType } from './../Mutator/ImportDataUseCase' import { ChallengeServiceInterface } from './../Challenge/ChallengeServiceInterface' -import { VaultServiceInterface } from './../Vaults/VaultServiceInterface' +import { VaultServiceInterface } from '../Vault/VaultServiceInterface' import { ApplicationIdentifier } from '@standardnotes/common' import { BackupFile, @@ -95,24 +97,27 @@ export interface ApplicationInterface { syncOptions?: SyncOptions, ): Promise - get features(): FeaturesClientInterface - get componentManager(): ComponentManagerInterface - get items(): ItemManagerInterface - get mutator(): MutatorClientInterface - get user(): UserClientInterface - get files(): FilesClientInterface - get subscriptions(): SubscriptionManagerInterface - get fileBackups(): BackupServiceInterface | undefined - get sessions(): SessionsClientInterface - get homeServer(): HomeServerServiceInterface | undefined - get vaults(): VaultServiceInterface - get challenges(): ChallengeServiceInterface get alerts(): AlertService get asymmetric(): AsymmetricMessageServiceInterface - get preferences(): PreferenceServiceInterface - get events(): InternalEventBusInterface - get history(): HistoryServiceInterface + get challenges(): ChallengeServiceInterface + get componentManager(): ComponentManagerInterface get encryption(): EncryptionProviderInterface + get events(): InternalEventBusInterface + get features(): FeaturesClientInterface + get fileBackups(): BackupServiceInterface | undefined + get files(): FilesClientInterface + get history(): HistoryServiceInterface + get homeServer(): HomeServerServiceInterface | undefined + get items(): ItemManagerInterface + get mutator(): MutatorClientInterface + get preferences(): PreferenceServiceInterface + get sessions(): SessionsClientInterface + get subscriptions(): SubscriptionManagerInterface + get user(): UserClientInterface + get vaults(): VaultServiceInterface + get vaultLocks(): VaultLockServiceInterface + get vaultUsers(): VaultUserServiceInterface + get vaultInvites(): VaultInviteServiceInterface readonly identifier: ApplicationIdentifier readonly platform: Platform diff --git a/packages/services/src/Domain/AsymmetricMessage/AsymmetricMessageService.spec.ts b/packages/services/src/Domain/AsymmetricMessage/AsymmetricMessageService.spec.ts index 9f91cd3e4..a33f06c8b 100644 --- a/packages/services/src/Domain/AsymmetricMessage/AsymmetricMessageService.spec.ts +++ b/packages/services/src/Domain/AsymmetricMessage/AsymmetricMessageService.spec.ts @@ -1,3 +1,4 @@ +import { GetVault } from './../Vault/UseCase/GetVault' import { SessionsClientInterface } from './../Session/SessionsClientInterface' import { EncryptionProviderInterface } from './../Encryption/EncryptionProviderInterface' import { GetUntrustedPayload } from './UseCase/GetUntrustedPayload' @@ -5,7 +6,6 @@ import { GetInboundMessages } from './UseCase/GetInboundMessages' import { GetOutboundMessages } from './UseCase/GetOutboundMessages' import { SendOwnContactChangeMessage } from './UseCase/SendOwnContactChangeMessage' import { HandleRootKeyChangedMessage } from './UseCase/HandleRootKeyChangedMessage' -import { GetVault } from './../Vaults/UseCase/GetVault' import { GetTrustedPayload } from './UseCase/GetTrustedPayload' import { ReplaceContactData } from './../Contacts/UseCase/ReplaceContactData' import { GetAllContacts } from './../Contacts/UseCase/GetAllContacts' diff --git a/packages/services/src/Domain/AsymmetricMessage/AsymmetricMessageService.ts b/packages/services/src/Domain/AsymmetricMessage/AsymmetricMessageService.ts index c9cc013ca..a28ab8bcf 100644 --- a/packages/services/src/Domain/AsymmetricMessage/AsymmetricMessageService.ts +++ b/packages/services/src/Domain/AsymmetricMessage/AsymmetricMessageService.ts @@ -26,7 +26,7 @@ import { UserKeyPairChangedEventData } from '../Session/UserKeyPairChangedEventD import { SendOwnContactChangeMessage } from './UseCase/SendOwnContactChangeMessage' import { GetOutboundMessages } from './UseCase/GetOutboundMessages' import { GetInboundMessages } from './UseCase/GetInboundMessages' -import { GetVault } from '../Vaults/UseCase/GetVault' +import { GetVault } from '../Vault/UseCase/GetVault' import { AsymmetricMessageServiceInterface } from './AsymmetricMessageServiceInterface' import { GetUntrustedPayload } from './UseCase/GetUntrustedPayload' import { FindContact } from '../Contacts/UseCase/FindContact' diff --git a/packages/services/src/Domain/AsymmetricMessage/UseCase/HandleRootKeyChangedMessage.ts b/packages/services/src/Domain/AsymmetricMessage/UseCase/HandleRootKeyChangedMessage.ts index 042b4039b..48b8c5d7e 100644 --- a/packages/services/src/Domain/AsymmetricMessage/UseCase/HandleRootKeyChangedMessage.ts +++ b/packages/services/src/Domain/AsymmetricMessage/UseCase/HandleRootKeyChangedMessage.ts @@ -10,7 +10,7 @@ import { } from '@standardnotes/models' import { ContentType } from '@standardnotes/domain-core' -import { GetVault } from '../../Vaults/UseCase/GetVault' +import { GetVault } from '../../Vault/UseCase/GetVault' import { EncryptionProviderInterface } from '../../Encryption/EncryptionProviderInterface' export class HandleRootKeyChangedMessage { diff --git a/packages/services/src/Domain/SharedVaults/SharedVaultService.spec.ts b/packages/services/src/Domain/SharedVaults/SharedVaultService.spec.ts index c96bc8e17..fa77f5109 100644 --- a/packages/services/src/Domain/SharedVaults/SharedVaultService.spec.ts +++ b/packages/services/src/Domain/SharedVaults/SharedVaultService.spec.ts @@ -11,7 +11,7 @@ import { SendVaultDataChangedMessage } from './UseCase/SendVaultDataChangedMessa import { NotifyVaultUsersOfKeyRotation } from './UseCase/NotifyVaultUsersOfKeyRotation' import { HandleKeyPairChange } from './../Contacts/UseCase/HandleKeyPairChange' import { CreateSharedVault } from './UseCase/CreateSharedVault' -import { GetVault } from './../Vaults/UseCase/GetVault' +import { GetVault } from './../Vault/UseCase/GetVault' import { SharedVaultService } from './SharedVaultService' import { SyncServiceInterface } from '../Sync/SyncServiceInterface' import { ItemManagerInterface } from '../Item/ItemManagerInterface' diff --git a/packages/services/src/Domain/SharedVaults/SharedVaultService.ts b/packages/services/src/Domain/SharedVaults/SharedVaultService.ts index c31516fac..346e8720a 100644 --- a/packages/services/src/Domain/SharedVaults/SharedVaultService.ts +++ b/packages/services/src/Domain/SharedVaults/SharedVaultService.ts @@ -21,13 +21,13 @@ import { InternalEventInterface } from '../Internal/InternalEventInterface' import { UserEventServiceEvent, UserEventServiceEventPayload } from '../UserEvent/UserEventServiceEvent' import { DeleteThirdPartyVault } from './UseCase/DeleteExternalSharedVault' import { DeleteSharedVault } from './UseCase/DeleteSharedVault' -import { VaultServiceEvent, VaultServiceEventPayload } from '../Vaults/VaultServiceEvent' +import { VaultServiceEvent, VaultServiceEventPayload } from '../Vault/VaultServiceEvent' import { ShareContactWithVault } from './UseCase/ShareContactWithVault' import { NotifyVaultUsersOfKeyRotation } from './UseCase/NotifyVaultUsersOfKeyRotation' import { CreateSharedVault } from './UseCase/CreateSharedVault' import { SendVaultDataChangedMessage } from './UseCase/SendVaultDataChangedMessage' import { ConvertToSharedVault } from './UseCase/ConvertToSharedVault' -import { GetVault } from '../Vaults/UseCase/GetVault' +import { GetVault } from '../Vault/UseCase/GetVault' import { ContentType } from '@standardnotes/domain-core' import { HandleKeyPairChange } from '../Contacts/UseCase/HandleKeyPairChange' import { FindContact } from '../Contacts/UseCase/FindContact' diff --git a/packages/services/src/Domain/SharedVaults/UseCase/ConvertToSharedVault.ts b/packages/services/src/Domain/SharedVaults/UseCase/ConvertToSharedVault.ts index 4842c9b07..6d4c89dd9 100644 --- a/packages/services/src/Domain/SharedVaults/UseCase/ConvertToSharedVault.ts +++ b/packages/services/src/Domain/SharedVaults/UseCase/ConvertToSharedVault.ts @@ -2,7 +2,7 @@ import { SharedVaultListingInterface, VaultListingInterface, VaultListingMutator import { ClientDisplayableError, isErrorResponse } from '@standardnotes/responses' import { SharedVaultServerInterface } from '@standardnotes/api' import { ItemManagerInterface } from '../../Item/ItemManagerInterface' -import { MoveItemsToVault } from '../../Vaults/UseCase/MoveItemsToVault' +import { MoveItemsToVault } from '../../Vault/UseCase/MoveItemsToVault' import { MutatorClientInterface } from '../../Mutator/MutatorClientInterface' export class ConvertToSharedVault { diff --git a/packages/services/src/Domain/SharedVaults/UseCase/CreateSharedVault.ts b/packages/services/src/Domain/SharedVaults/UseCase/CreateSharedVault.ts index f36ef933b..759099675 100644 --- a/packages/services/src/Domain/SharedVaults/UseCase/CreateSharedVault.ts +++ b/packages/services/src/Domain/SharedVaults/UseCase/CreateSharedVault.ts @@ -7,8 +7,8 @@ import { import { ClientDisplayableError, isErrorResponse } from '@standardnotes/responses' import { SharedVaultServerInterface } from '@standardnotes/api' import { ItemManagerInterface } from '../../Item/ItemManagerInterface' -import { CreateVault } from '../../Vaults/UseCase/CreateVault' -import { MoveItemsToVault } from '../../Vaults/UseCase/MoveItemsToVault' +import { CreateVault } from '../../Vault/UseCase/CreateVault' +import { MoveItemsToVault } from '../../Vault/UseCase/MoveItemsToVault' import { MutatorClientInterface } from '../../Mutator/MutatorClientInterface' export class CreateSharedVault { diff --git a/packages/services/src/Domain/SharedVaults/UseCase/DeleteSharedVault.ts b/packages/services/src/Domain/SharedVaults/UseCase/DeleteSharedVault.ts index 328a237ad..80f192617 100644 --- a/packages/services/src/Domain/SharedVaults/UseCase/DeleteSharedVault.ts +++ b/packages/services/src/Domain/SharedVaults/UseCase/DeleteSharedVault.ts @@ -2,7 +2,7 @@ import { ClientDisplayableError, isErrorResponse } from '@standardnotes/response import { SharedVaultServerInterface } from '@standardnotes/api' import { SharedVaultListingInterface } from '@standardnotes/models' import { SyncServiceInterface } from '../../Sync/SyncServiceInterface' -import { DeleteVault } from '../../Vaults/UseCase/DeleteVault' +import { DeleteVault } from '../../Vault/UseCase/DeleteVault' export class DeleteSharedVault { constructor( diff --git a/packages/services/src/Domain/SharedVaults/UseCase/GetSharedVaults.ts b/packages/services/src/Domain/SharedVaults/UseCase/GetSharedVaults.ts index 8a7eb6ce1..d399e28a8 100644 --- a/packages/services/src/Domain/SharedVaults/UseCase/GetSharedVaults.ts +++ b/packages/services/src/Domain/SharedVaults/UseCase/GetSharedVaults.ts @@ -1,4 +1,4 @@ -import { GetVaults } from './../../Vaults/UseCase/GetVaults' +import { GetVaults } from '../../Vault/UseCase/GetVaults' import { Result, SyncUseCaseInterface } from '@standardnotes/domain-core' import { SharedVaultListingInterface } from '@standardnotes/models' diff --git a/packages/services/src/Domain/Vaults/UseCase/ChangeVaultKeyOptions.ts b/packages/services/src/Domain/Vault/UseCase/ChangeVaultKeyOptions.ts similarity index 97% rename from packages/services/src/Domain/Vaults/UseCase/ChangeVaultKeyOptions.ts rename to packages/services/src/Domain/Vault/UseCase/ChangeVaultKeyOptions.ts index b44a4ed12..bef67da8e 100644 --- a/packages/services/src/Domain/Vaults/UseCase/ChangeVaultKeyOptions.ts +++ b/packages/services/src/Domain/Vault/UseCase/ChangeVaultKeyOptions.ts @@ -5,7 +5,7 @@ import { VaultListingInterface, VaultListingMutator, } from '@standardnotes/models' -import { ChangeVaultOptionsDTO } from '../ChangeVaultOptionsDTO' +import { ChangeVaultKeyOptionsDTO } from './ChangeVaultKeyOptionsDTO' import { GetVault } from './GetVault' import { EncryptionProviderInterface } from '../../Encryption/EncryptionProviderInterface' import { KeySystemKeyManagerInterface } from '../../KeySystem/KeySystemKeyManagerInterface' @@ -19,7 +19,7 @@ export class ChangeVaultKeyOptions { private getVault: GetVault, ) {} - async execute(dto: ChangeVaultOptionsDTO): Promise { + async execute(dto: ChangeVaultKeyOptionsDTO): Promise { const useStorageMode = dto.newKeyStorageMode ?? dto.vault.keyStorageMode if (dto.newPasswordType) { diff --git a/packages/services/src/Domain/Vaults/ChangeVaultOptionsDTO.ts b/packages/services/src/Domain/Vault/UseCase/ChangeVaultKeyOptionsDTO.ts similarity index 90% rename from packages/services/src/Domain/Vaults/ChangeVaultOptionsDTO.ts rename to packages/services/src/Domain/Vault/UseCase/ChangeVaultKeyOptionsDTO.ts index 2001dd8c3..af80d0624 100644 --- a/packages/services/src/Domain/Vaults/ChangeVaultOptionsDTO.ts +++ b/packages/services/src/Domain/Vault/UseCase/ChangeVaultKeyOptionsDTO.ts @@ -1,6 +1,6 @@ import { KeySystemRootKeyPasswordType, KeySystemRootKeyStorageMode, VaultListingInterface } from '@standardnotes/models' -export type ChangeVaultOptionsDTO = { +export type ChangeVaultKeyOptionsDTO = { vault: VaultListingInterface newPasswordType: | { passwordType: KeySystemRootKeyPasswordType.Randomized } diff --git a/packages/services/src/Domain/Vaults/UseCase/CreateVault.ts b/packages/services/src/Domain/Vault/UseCase/CreateVault.ts similarity index 98% rename from packages/services/src/Domain/Vaults/UseCase/CreateVault.ts rename to packages/services/src/Domain/Vault/UseCase/CreateVault.ts index 656211981..b98dbcf56 100644 --- a/packages/services/src/Domain/Vaults/UseCase/CreateVault.ts +++ b/packages/services/src/Domain/Vault/UseCase/CreateVault.ts @@ -1,4 +1,4 @@ -import { SyncServiceInterface } from './../../Sync/SyncServiceInterface' +import { SyncServiceInterface } from '../../Sync/SyncServiceInterface' import { UuidGenerator } from '@standardnotes/utils' import { KeySystemRootKeyParamsInterface, diff --git a/packages/services/src/Domain/Vaults/UseCase/DeleteVault.ts b/packages/services/src/Domain/Vault/UseCase/DeleteVault.ts similarity index 100% rename from packages/services/src/Domain/Vaults/UseCase/DeleteVault.ts rename to packages/services/src/Domain/Vault/UseCase/DeleteVault.ts diff --git a/packages/services/src/Domain/Vaults/UseCase/GetVault.ts b/packages/services/src/Domain/Vault/UseCase/GetVault.ts similarity index 93% rename from packages/services/src/Domain/Vaults/UseCase/GetVault.ts rename to packages/services/src/Domain/Vault/UseCase/GetVault.ts index 1930bd702..62ed834cc 100644 --- a/packages/services/src/Domain/Vaults/UseCase/GetVault.ts +++ b/packages/services/src/Domain/Vault/UseCase/GetVault.ts @@ -1,5 +1,5 @@ import { VaultListingInterface } from '@standardnotes/models' -import { ItemManagerInterface } from './../../Item/ItemManagerInterface' +import { ItemManagerInterface } from '../../Item/ItemManagerInterface' import { ContentType, Result, SyncUseCaseInterface } from '@standardnotes/domain-core' export class GetVault implements SyncUseCaseInterface { diff --git a/packages/services/src/Domain/Vaults/UseCase/GetVaults.ts b/packages/services/src/Domain/Vault/UseCase/GetVaults.ts similarity index 100% rename from packages/services/src/Domain/Vaults/UseCase/GetVaults.ts rename to packages/services/src/Domain/Vault/UseCase/GetVaults.ts diff --git a/packages/services/src/Domain/Vaults/UseCase/MoveItemsToVault.ts b/packages/services/src/Domain/Vault/UseCase/MoveItemsToVault.ts similarity index 100% rename from packages/services/src/Domain/Vaults/UseCase/MoveItemsToVault.ts rename to packages/services/src/Domain/Vault/UseCase/MoveItemsToVault.ts diff --git a/packages/services/src/Domain/Vaults/UseCase/RemoveItemFromVault.ts b/packages/services/src/Domain/Vault/UseCase/RemoveItemFromVault.ts similarity index 100% rename from packages/services/src/Domain/Vaults/UseCase/RemoveItemFromVault.ts rename to packages/services/src/Domain/Vault/UseCase/RemoveItemFromVault.ts diff --git a/packages/services/src/Domain/Vaults/UseCase/RotateVaultKey.ts b/packages/services/src/Domain/Vault/UseCase/RotateVaultKey.ts similarity index 100% rename from packages/services/src/Domain/Vaults/UseCase/RotateVaultKey.ts rename to packages/services/src/Domain/Vault/UseCase/RotateVaultKey.ts diff --git a/packages/services/src/Domain/Vaults/VaultService.ts b/packages/services/src/Domain/Vault/VaultService.ts similarity index 64% rename from packages/services/src/Domain/Vaults/VaultService.ts rename to packages/services/src/Domain/Vault/VaultService.ts index d6f038aaf..50a75764b 100644 --- a/packages/services/src/Domain/Vaults/VaultService.ts +++ b/packages/services/src/Domain/Vault/VaultService.ts @@ -3,14 +3,13 @@ import { DecryptedItemInterface, FileItem, KeySystemIdentifier, - KeySystemRootKeyPasswordType, KeySystemRootKeyStorageMode, VaultListingInterface, VaultListingMutator, isNote, } from '@standardnotes/models' import { VaultServiceInterface } from './VaultServiceInterface' -import { ChangeVaultOptionsDTO } from './ChangeVaultOptionsDTO' +import { ChangeVaultKeyOptionsDTO } from './UseCase/ChangeVaultKeyOptionsDTO' import { VaultServiceEvent, VaultServiceEventPayload } from './VaultServiceEvent' import { CreateVault } from './UseCase/CreateVault' import { AbstractService } from '../Service/AbstractService' @@ -25,23 +24,18 @@ import { GetVault } from './UseCase/GetVault' import { ChangeVaultKeyOptions } from './UseCase/ChangeVaultKeyOptions' import { MutatorClientInterface } from '../Mutator/MutatorClientInterface' import { AlertService } from '../Alert/AlertService' -import { ContentType } from '@standardnotes/domain-core' -import { EncryptionProviderInterface } from '../Encryption/EncryptionProviderInterface' -import { KeySystemKeyManagerInterface } from '../KeySystem/KeySystemKeyManagerInterface' import { GetVaults } from './UseCase/GetVaults' +import { VaultLockServiceInterface } from '../VaultLock/VaultLockServiceInterface' export class VaultService extends AbstractService implements VaultServiceInterface { - private lockMap = new Map() - constructor( private sync: SyncServiceInterface, private items: ItemManagerInterface, private mutator: MutatorClientInterface, - private encryption: EncryptionProviderInterface, - private keys: KeySystemKeyManagerInterface, + private vaultLocks: VaultLockServiceInterface, private alerts: AlertService, private _getVault: GetVault, private _getVaults: GetVaults, @@ -49,29 +43,34 @@ export class VaultService private _moveItemsToVault: MoveItemsToVault, private _createVault: CreateVault, private _removeItemFromVault: RemoveItemFromVault, - private _deleteVaultUse: DeleteVault, + private _deleteVault: DeleteVault, private _rotateVaultKey: RotateVaultKey, eventBus: InternalEventBusInterface, ) { super(eventBus) + } - items.addObserver( - [ContentType.TYPES.KeySystemItemsKey, ContentType.TYPES.KeySystemRootKey, ContentType.TYPES.VaultListing], - () => { - void this.recomputeAllVaultsLockingState() - }, - ) + override deinit(): void { + super.deinit() + ;(this.sync as unknown) = undefined + ;(this.items as unknown) = undefined + ;(this.mutator as unknown) = undefined + ;(this.vaultLocks as unknown) = undefined + ;(this.alerts as unknown) = undefined + ;(this._getVault as unknown) = undefined + ;(this._getVaults as unknown) = undefined + ;(this._changeVaultKeyOptions as unknown) = undefined + ;(this._moveItemsToVault as unknown) = undefined + ;(this._createVault as unknown) = undefined + ;(this._removeItemFromVault as unknown) = undefined + ;(this._deleteVault as unknown) = undefined + ;(this._rotateVaultKey as unknown) = undefined } getVaults(): VaultListingInterface[] { return this._getVaults.execute().getValue() } - getLockedvaults(): VaultListingInterface[] { - const vaults = this.getVaults() - return vaults.filter((vault) => this.isVaultLocked(vault)) - } - public getVault(dto: { keySystemIdentifier: KeySystemIdentifier }): VaultListingInterface | undefined { const result = this._getVault.execute(dto) if (result.isFailed()) { @@ -90,16 +89,12 @@ export class VaultService return vault } - async createRandomizedVault(dto: { - name: string - description?: string - storagePreference: KeySystemRootKeyStorageMode - }): Promise { + async createRandomizedVault(dto: { name: string; description?: string }): Promise { return this.createVaultWithParameters({ name: dto.name, description: dto.description, userInputtedPassword: undefined, - storagePreference: dto.storagePreference, + storagePreference: KeySystemRootKeyStorageMode.Synced, }) } @@ -132,7 +127,7 @@ export class VaultService vault: VaultListingInterface, item: DecryptedItemInterface, ): Promise { - if (this.isVaultLocked(vault)) { + if (this.vaultLocks.isVaultLocked(vault)) { throw new Error('Attempting to add item to locked vault') } @@ -162,7 +157,7 @@ export class VaultService throw new Error('Cannot find vault to remove item from') } - if (this.isVaultLocked(vault)) { + if (this.vaultLocks.isVaultLocked(vault)) { throw new Error('Attempting to remove item from locked vault') } @@ -175,7 +170,7 @@ export class VaultService throw new Error('Shared vault must be deleted through SharedVaultService') } - const error = await this._deleteVaultUse.execute(vault) + const error = await this._deleteVault.execute(vault) if (isClientDisplayableError(error)) { return false @@ -200,7 +195,7 @@ export class VaultService } async rotateVaultRootKey(vault: VaultListingInterface): Promise { - if (this.computeVaultLockState(vault) === 'locked') { + if (this.vaultLocks.isVaultLocked(vault)) { throw new Error('Cannot rotate root key of locked vault') } @@ -232,8 +227,8 @@ export class VaultService return this.getVault({ keySystemIdentifier: latestItem.key_system_identifier }) } - async changeVaultOptions(dto: ChangeVaultOptionsDTO): Promise { - if (this.isVaultLocked(dto.vault)) { + async changeVaultOptions(dto: ChangeVaultKeyOptionsDTO): Promise { + if (this.vaultLocks.isVaultLocked(dto.vault)) { throw new Error('Attempting to change vault options on a locked vault') } @@ -243,99 +238,4 @@ export class VaultService await this.notifyEventSync(VaultServiceEvent.VaultRootKeyRotated, { vault: dto.vault }) } } - - public isVaultLocked(vault: VaultListingInterface): boolean { - return this.lockMap.get(vault.uuid) === true - } - - public async lockNonPersistentVault(vault: VaultListingInterface): Promise { - if (vault.keyStorageMode === KeySystemRootKeyStorageMode.Synced) { - throw new Error('Vault uses synced root key and cannot be locked') - } - - this.keys.clearMemoryOfKeysRelatedToVault(vault) - - this.lockMap.set(vault.uuid, true) - void this.notifyEventSync(VaultServiceEvent.VaultLocked, { vault }) - } - - public async unlockNonPersistentVault(vault: VaultListingInterface, password: string): Promise { - if (vault.keyPasswordType !== KeySystemRootKeyPasswordType.UserInputted) { - throw new Error('Vault uses randomized password and cannot be unlocked with user inputted password') - } - - if (vault.keyStorageMode === KeySystemRootKeyStorageMode.Synced) { - throw new Error('Vault uses synced root key and cannot be unlocked with user inputted password') - } - - const derivedRootKey = this.encryption.deriveUserInputtedKeySystemRootKey({ - keyParams: vault.rootKeyParams, - userInputtedPassword: password, - }) - - this.keys.intakeNonPersistentKeySystemRootKey(derivedRootKey, vault.keyStorageMode) - - await this.encryption.decryptErroredPayloads() - - if (this.computeVaultLockState(vault) === 'locked') { - this.keys.undoIntakeNonPersistentKeySystemRootKey(vault.systemIdentifier) - return false - } - - this.lockMap.set(vault.uuid, false) - void this.notifyEventSync(VaultServiceEvent.VaultUnlocked, { vault }) - - return true - } - - private recomputeAllVaultsLockingState = async (): Promise => { - const vaults = this.getVaults() - - for (const vault of vaults) { - const locked = this.computeVaultLockState(vault) === 'locked' - - if (this.lockMap.get(vault.uuid) !== locked) { - this.lockMap.set(vault.uuid, locked) - - if (locked) { - void this.notifyEvent(VaultServiceEvent.VaultLocked, { vault }) - } else { - void this.notifyEvent(VaultServiceEvent.VaultUnlocked, { vault }) - } - } - } - } - - private computeVaultLockState(vault: VaultListingInterface): 'locked' | 'unlocked' { - const rootKey = this.keys.getPrimaryKeySystemRootKey(vault.systemIdentifier) - if (!rootKey) { - return 'locked' - } - - const itemsKey = this.keys.getPrimaryKeySystemItemsKey(vault.systemIdentifier) - if (!itemsKey) { - return 'locked' - } - - return 'unlocked' - } - - override deinit(): void { - super.deinit() - ;(this.sync as unknown) = undefined - ;(this.items as unknown) = undefined - ;(this.mutator as unknown) = undefined - ;(this.encryption as unknown) = undefined - ;(this.alerts as unknown) = undefined - ;(this._getVault as unknown) = undefined - ;(this._getVaults as unknown) = undefined - ;(this._changeVaultKeyOptions as unknown) = undefined - ;(this._moveItemsToVault as unknown) = undefined - ;(this._createVault as unknown) = undefined - ;(this._removeItemFromVault as unknown) = undefined - ;(this._deleteVaultUse as unknown) = undefined - ;(this._rotateVaultKey as unknown) = undefined - - this.lockMap.clear() - } } diff --git a/packages/services/src/Domain/Vaults/VaultServiceEvent.ts b/packages/services/src/Domain/Vault/VaultServiceEvent.ts similarity index 55% rename from packages/services/src/Domain/Vaults/VaultServiceEvent.ts rename to packages/services/src/Domain/Vault/VaultServiceEvent.ts index 4d18f146c..cd3ef6224 100644 --- a/packages/services/src/Domain/Vaults/VaultServiceEvent.ts +++ b/packages/services/src/Domain/Vault/VaultServiceEvent.ts @@ -2,18 +2,10 @@ import { VaultListingInterface } from '@standardnotes/models' export enum VaultServiceEvent { VaultRootKeyRotated = 'VaultRootKeyRotated', - VaultUnlocked = 'VaultUnlocked', - VaultLocked = 'VaultLocked', } export type VaultServiceEventPayload = { [VaultServiceEvent.VaultRootKeyRotated]: { vault: VaultListingInterface } - [VaultServiceEvent.VaultUnlocked]: { - vault: VaultListingInterface - } - [VaultServiceEvent.VaultLocked]: { - vault: VaultListingInterface - } } diff --git a/packages/services/src/Domain/Vaults/VaultServiceInterface.ts b/packages/services/src/Domain/Vault/VaultServiceInterface.ts similarity index 74% rename from packages/services/src/Domain/Vaults/VaultServiceInterface.ts rename to packages/services/src/Domain/Vault/VaultServiceInterface.ts index e9eddc255..21c04f456 100644 --- a/packages/services/src/Domain/Vaults/VaultServiceInterface.ts +++ b/packages/services/src/Domain/Vault/VaultServiceInterface.ts @@ -6,15 +6,11 @@ import { } from '@standardnotes/models' import { AbstractService } from '../Service/AbstractService' import { VaultServiceEvent, VaultServiceEventPayload } from './VaultServiceEvent' -import { ChangeVaultOptionsDTO } from './ChangeVaultOptionsDTO' +import { ChangeVaultKeyOptionsDTO } from './UseCase/ChangeVaultKeyOptionsDTO' export interface VaultServiceInterface extends AbstractService { - createRandomizedVault(dto: { - name: string - description?: string - storagePreference: KeySystemRootKeyStorageMode - }): Promise + createRandomizedVault(dto: { name: string; description?: string }): Promise createUserInputtedPasswordVault(dto: { name: string description?: string @@ -24,7 +20,6 @@ export interface VaultServiceInterface getVaults(): VaultListingInterface[] getVault(dto: { keySystemIdentifier: KeySystemIdentifier }): VaultListingInterface | undefined - getLockedvaults(): VaultListingInterface[] deleteVault(vault: VaultListingInterface): Promise moveItemToVault( @@ -40,8 +35,5 @@ export interface VaultServiceInterface params: { name: string; description: string }, ): Promise rotateVaultRootKey(vault: VaultListingInterface): Promise - changeVaultOptions(dto: ChangeVaultOptionsDTO): Promise - - isVaultLocked(vault: VaultListingInterface): boolean - unlockNonPersistentVault(vault: VaultListingInterface, password: string): Promise + changeVaultOptions(dto: ChangeVaultKeyOptionsDTO): Promise } diff --git a/packages/services/src/Domain/VaultInvite/VaultInviteService.ts b/packages/services/src/Domain/VaultInvite/VaultInviteService.ts index 066f48f2f..da3e1e36c 100644 --- a/packages/services/src/Domain/VaultInvite/VaultInviteService.ts +++ b/packages/services/src/Domain/VaultInvite/VaultInviteService.ts @@ -9,7 +9,7 @@ import { GetUntrustedPayload } from './../AsymmetricMessage/UseCase/GetUntrusted import { GetTrustedPayload } from './../AsymmetricMessage/UseCase/GetTrustedPayload' import { InviteRecord } from './InviteRecord' import { VaultUserServiceInterface } from './../VaultUser/VaultUserServiceInterface' -import { GetVault } from './../Vaults/UseCase/GetVault' +import { GetVault } from '../Vault/UseCase/GetVault' import { InviteToVault } from './UseCase/InviteToVault' import { GetVaultContacts } from '../VaultUser/UseCase/GetVaultContacts' import { SyncServiceInterface } from './../Sync/SyncServiceInterface' diff --git a/packages/services/src/Domain/VaultLock/VaultLockService.ts b/packages/services/src/Domain/VaultLock/VaultLockService.ts new file mode 100644 index 000000000..06603802b --- /dev/null +++ b/packages/services/src/Domain/VaultLock/VaultLockService.ts @@ -0,0 +1,133 @@ +import { GetVaults } from '../Vault/UseCase/GetVaults' +import { KeySystemRootKeyPasswordType, KeySystemRootKeyStorageMode, VaultListingInterface } from '@standardnotes/models' +import { VaultLockServiceInterface } from './VaultLockServiceInterface' +import { VaultLockServiceEvent, VaultLockServiceEventPayload } from './VaultLockServiceEvent' +import { AbstractService } from '../Service/AbstractService' +import { ItemManagerInterface } from '../Item/ItemManagerInterface' +import { InternalEventBusInterface } from '../Internal/InternalEventBusInterface' +import { ContentType } from '@standardnotes/domain-core' +import { EncryptionProviderInterface } from '../Encryption/EncryptionProviderInterface' +import { KeySystemKeyManagerInterface } from '../KeySystem/KeySystemKeyManagerInterface' + +export class VaultLockService + extends AbstractService + implements VaultLockServiceInterface +{ + private lockMap = new Map() + + constructor( + items: ItemManagerInterface, + private encryption: EncryptionProviderInterface, + private keys: KeySystemKeyManagerInterface, + private _getVaults: GetVaults, + eventBus: InternalEventBusInterface, + ) { + super(eventBus) + + items.addObserver( + [ContentType.TYPES.KeySystemItemsKey, ContentType.TYPES.KeySystemRootKey, ContentType.TYPES.VaultListing], + () => { + void this.recomputeAllVaultsLockingState() + }, + ) + } + + override deinit(): void { + super.deinit() + ;(this.encryption as unknown) = undefined + ;(this.keys as unknown) = undefined + ;(this._getVaults as unknown) = undefined + + this.lockMap.clear() + } + + public getLockedvaults(): VaultListingInterface[] { + const vaults = this._getVaults.execute().getValue() + return vaults.filter((vault) => this.isVaultLocked(vault)) + } + + public isVaultLocked(vault: VaultListingInterface): boolean { + return this.lockMap.get(vault.uuid) === true + } + + public isVaultLockable(vault: VaultListingInterface): boolean { + return vault.keyPasswordType === KeySystemRootKeyPasswordType.UserInputted + } + + public lockNonPersistentVault(vault: VaultListingInterface): void { + if (vault.keyStorageMode === KeySystemRootKeyStorageMode.Synced) { + throw new Error('Vault uses synced key storage and cannot be locked') + } + + if (vault.keyPasswordType !== KeySystemRootKeyPasswordType.UserInputted) { + throw new Error('Vault uses randomized password and cannot be locked') + } + + this.keys.clearMemoryOfKeysRelatedToVault(vault) + + this.lockMap.set(vault.uuid, true) + + void this.notifyEventSync(VaultLockServiceEvent.VaultLocked, { vault }) + } + + public async unlockNonPersistentVault(vault: VaultListingInterface, password: string): Promise { + if (vault.keyPasswordType !== KeySystemRootKeyPasswordType.UserInputted) { + throw new Error('Vault uses randomized password and cannot be unlocked with user inputted password') + } + + if (vault.keyStorageMode === KeySystemRootKeyStorageMode.Synced) { + throw new Error('Vault uses synced root key and cannot be unlocked with user inputted password') + } + + const derivedRootKey = this.encryption.deriveUserInputtedKeySystemRootKey({ + keyParams: vault.rootKeyParams, + userInputtedPassword: password, + }) + + this.keys.intakeNonPersistentKeySystemRootKey(derivedRootKey, vault.keyStorageMode) + + await this.encryption.decryptErroredPayloads() + + if (this.computeVaultLockState(vault) === 'locked') { + this.keys.undoIntakeNonPersistentKeySystemRootKey(vault.systemIdentifier) + return false + } + + this.lockMap.set(vault.uuid, false) + void this.notifyEventSync(VaultLockServiceEvent.VaultUnlocked, { vault }) + + return true + } + + private recomputeAllVaultsLockingState = async (): Promise => { + const vaults = this._getVaults.execute().getValue() + + for (const vault of vaults) { + const locked = this.computeVaultLockState(vault) === 'locked' + + if (this.lockMap.get(vault.uuid) !== locked) { + this.lockMap.set(vault.uuid, locked) + + if (locked) { + void this.notifyEvent(VaultLockServiceEvent.VaultLocked, { vault }) + } else { + void this.notifyEvent(VaultLockServiceEvent.VaultUnlocked, { vault }) + } + } + } + } + + private computeVaultLockState(vault: VaultListingInterface): 'locked' | 'unlocked' { + const rootKey = this.keys.getPrimaryKeySystemRootKey(vault.systemIdentifier) + if (!rootKey) { + return 'locked' + } + + const itemsKey = this.keys.getPrimaryKeySystemItemsKey(vault.systemIdentifier) + if (!itemsKey) { + return 'locked' + } + + return 'unlocked' + } +} diff --git a/packages/services/src/Domain/VaultLock/VaultLockServiceEvent.ts b/packages/services/src/Domain/VaultLock/VaultLockServiceEvent.ts new file mode 100644 index 000000000..835bcfc86 --- /dev/null +++ b/packages/services/src/Domain/VaultLock/VaultLockServiceEvent.ts @@ -0,0 +1,15 @@ +import { VaultListingInterface } from '@standardnotes/models' + +export enum VaultLockServiceEvent { + VaultUnlocked = 'VaultUnlocked', + VaultLocked = 'VaultLocked', +} + +export type VaultLockServiceEventPayload = { + [VaultLockServiceEvent.VaultUnlocked]: { + vault: VaultListingInterface + } + [VaultLockServiceEvent.VaultLocked]: { + vault: VaultListingInterface + } +} diff --git a/packages/services/src/Domain/VaultLock/VaultLockServiceInterface.ts b/packages/services/src/Domain/VaultLock/VaultLockServiceInterface.ts new file mode 100644 index 000000000..814961e18 --- /dev/null +++ b/packages/services/src/Domain/VaultLock/VaultLockServiceInterface.ts @@ -0,0 +1,12 @@ +import { VaultListingInterface } from '@standardnotes/models' +import { AbstractService } from '../Service/AbstractService' +import { VaultLockServiceEvent, VaultLockServiceEventPayload } from './VaultLockServiceEvent' + +export interface VaultLockServiceInterface + extends AbstractService { + getLockedvaults(): VaultListingInterface[] + isVaultLocked(vault: VaultListingInterface): boolean + isVaultLockable(vault: VaultListingInterface): boolean + lockNonPersistentVault(vault: VaultListingInterface): void + unlockNonPersistentVault(vault: VaultListingInterface, password: string): Promise +} diff --git a/packages/services/src/Domain/VaultUser/VaultUserService.ts b/packages/services/src/Domain/VaultUser/VaultUserService.ts index c34d853e9..d94f0847b 100644 --- a/packages/services/src/Domain/VaultUser/VaultUserService.ts +++ b/packages/services/src/Domain/VaultUser/VaultUserService.ts @@ -1,8 +1,9 @@ +import { VaultLockServiceInterface } from './../VaultLock/VaultLockServiceInterface' import { LeaveVault } from './UseCase/LeaveSharedVault' -import { GetVault } from './../Vaults/UseCase/GetVault' +import { GetVault } from '../Vault/UseCase/GetVault' import { InternalEventBusInterface } from './../Internal/InternalEventBusInterface' import { RemoveVaultMember } from './UseCase/RemoveSharedVaultMember' -import { VaultServiceInterface } from './../Vaults/VaultServiceInterface' +import { VaultServiceInterface } from '../Vault/VaultServiceInterface' import { SessionsClientInterface } from './../Session/SessionsClientInterface' import { GetVaultUsers } from './UseCase/GetVaultUsers' import { SharedVaultListingInterface } from '@standardnotes/models' @@ -17,6 +18,7 @@ export class VaultUserService extends AbstractService imp constructor( private session: SessionsClientInterface, private vaults: VaultServiceInterface, + private vaultLocks: VaultLockServiceInterface, private _getVaultUsers: GetVaultUsers, private _removeVaultMember: RemoveVaultMember, private _isVaultOwner: IsVaultOwner, @@ -66,7 +68,7 @@ export class VaultUserService extends AbstractService imp throw new Error('Only vault admins can remove users') } - if (this.vaults.isVaultLocked(sharedVault)) { + if (this.vaultLocks.isVaultLocked(sharedVault)) { throw new Error('Cannot remove user from locked vault') } diff --git a/packages/services/src/Domain/index.ts b/packages/services/src/Domain/index.ts index d39dff9ae..888daa965 100644 --- a/packages/services/src/Domain/index.ts +++ b/packages/services/src/Domain/index.ts @@ -187,18 +187,21 @@ export * from './VaultInvite/UseCase/SendVaultInvite' export * from './VaultInvite/VaultInviteService' export * from './VaultInvite/VaultInviteServiceEvent' export * from './VaultInvite/VaultInviteServiceInterface' -export * from './Vaults/ChangeVaultOptionsDTO' -export * from './Vaults/UseCase/ChangeVaultKeyOptions' -export * from './Vaults/UseCase/CreateVault' -export * from './Vaults/UseCase/DeleteVault' -export * from './Vaults/UseCase/GetVault' -export * from './Vaults/UseCase/GetVaults' -export * from './Vaults/UseCase/MoveItemsToVault' -export * from './Vaults/UseCase/RemoveItemFromVault' -export * from './Vaults/UseCase/RotateVaultKey' -export * from './Vaults/VaultService' -export * from './Vaults/VaultServiceEvent' -export * from './Vaults/VaultServiceInterface' +export * from './Vault/UseCase/ChangeVaultKeyOptionsDTO' +export * from './Vault/UseCase/ChangeVaultKeyOptions' +export * from './Vault/UseCase/CreateVault' +export * from './Vault/UseCase/DeleteVault' +export * from './Vault/UseCase/GetVault' +export * from './Vault/UseCase/GetVaults' +export * from './Vault/UseCase/MoveItemsToVault' +export * from './Vault/UseCase/RemoveItemFromVault' +export * from './Vault/UseCase/RotateVaultKey' +export * from './Vault/VaultService' +export * from './Vault/VaultServiceEvent' +export * from './Vault/VaultServiceInterface' +export * from './VaultLock/VaultLockService' +export * from './VaultLock/VaultLockServiceEvent' +export * from './VaultLock/VaultLockServiceInterface' export * from './VaultUser/UseCase/GetVaultContacts' export * from './VaultUser/UseCase/GetVaultContacts' export * from './VaultUser/UseCase/GetVaultUsers' diff --git a/packages/snjs/lib/Application/Application.ts b/packages/snjs/lib/Application/Application.ts index 49b503f1a..b86cb9ccd 100644 --- a/packages/snjs/lib/Application/Application.ts +++ b/packages/snjs/lib/Application/Application.ts @@ -75,6 +75,7 @@ import { VaultInviteServiceInterface, UserEventServiceEvent, VaultServiceEvent, + VaultLockServiceInterface, } from '@standardnotes/services' import { PayloadEmitSource, @@ -1324,18 +1325,6 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli return this.dependencies.get(TYPES.HomeServerService) } - public get vaults(): VaultServiceInterface { - return this.dependencies.get(TYPES.VaultService) - } - - public get contacts(): ContactServiceInterface { - return this.dependencies.get(TYPES.ContactService) - } - - public get sharedVaults(): SharedVaultServiceInterface { - return this.dependencies.get(TYPES.SharedVaultService) - } - public get preferences(): PreferenceServiceInterface { return this.dependencies.get(TYPES.PreferencesService) } @@ -1352,6 +1341,14 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli return this.dependencies.get(TYPES.InternalEventBus) } + public get vaults(): VaultServiceInterface { + return this.dependencies.get(TYPES.VaultService) + } + + public get vaultLocks(): VaultLockServiceInterface { + return this.dependencies.get(TYPES.VaultLockService) + } + public get vaultUsers(): VaultUserServiceInterface { return this.dependencies.get(TYPES.VaultUserService) } @@ -1360,6 +1357,14 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli return this.dependencies.get(TYPES.VaultInviteService) } + public get contacts(): ContactServiceInterface { + return this.dependencies.get(TYPES.ContactService) + } + + public get sharedVaults(): SharedVaultServiceInterface { + return this.dependencies.get(TYPES.SharedVaultService) + } + private get migrations(): MigrationService { return this.dependencies.get(TYPES.MigrationService) } diff --git a/packages/snjs/lib/Application/Dependencies/Dependencies.ts b/packages/snjs/lib/Application/Dependencies/Dependencies.ts index 0a245dc77..b0e0a994f 100644 --- a/packages/snjs/lib/Application/Dependencies/Dependencies.ts +++ b/packages/snjs/lib/Application/Dependencies/Dependencies.ts @@ -117,6 +117,7 @@ import { GetOwnedSharedVaults, ContactBelongsToVault, DeleteContact, + VaultLockService, } from '@standardnotes/services' import { ItemManager } from '../../Services/Items/ItemManager' import { PayloadManager } from '../../Services/Payloads/PayloadManager' @@ -650,6 +651,7 @@ export class Dependencies { return new VaultUserService( this.get(TYPES.SessionManager), this.get(TYPES.VaultService), + this.get(TYPES.VaultLockService), this.get(TYPES.GetVaultUsers), this.get(TYPES.RemoveVaultMember), this.get(TYPES.IsVaultOwner), @@ -725,13 +727,22 @@ export class Dependencies { ) }) + this.factory.set(TYPES.VaultLockService, () => { + return new VaultLockService( + this.get(TYPES.ItemManager), + this.get(TYPES.EncryptionService), + this.get(TYPES.KeySystemKeyManager), + this.get(TYPES.GetVaults), + this.get(TYPES.InternalEventBus), + ) + }) + this.factory.set(TYPES.VaultService, () => { return new VaultService( this.get(TYPES.SyncService), this.get(TYPES.ItemManager), this.get(TYPES.MutatorService), - this.get(TYPES.EncryptionService), - this.get(TYPES.KeySystemKeyManager), + this.get(TYPES.VaultLockService), this.get(TYPES.AlertService), this.get(TYPES.GetVault), this.get(TYPES.GetVaults), diff --git a/packages/snjs/lib/Application/Dependencies/Types.ts b/packages/snjs/lib/Application/Dependencies/Types.ts index c1b55ec50..3c8593e1b 100644 --- a/packages/snjs/lib/Application/Dependencies/Types.ts +++ b/packages/snjs/lib/Application/Dependencies/Types.ts @@ -62,6 +62,7 @@ export const TYPES = { VaultUserService: Symbol.for('VaultUserService'), VaultInviteService: Symbol.for('VaultInviteService'), VaultUserCache: Symbol.for('VaultUserCache'), + VaultLockService: Symbol.for('VaultLockService'), // Servers RevisionServer: Symbol.for('RevisionServer'), diff --git a/packages/snjs/mocha/TestRegistry/VaultTests.js b/packages/snjs/mocha/TestRegistry/VaultTests.js index ecaa6743e..acb1b54a9 100644 --- a/packages/snjs/mocha/TestRegistry/VaultTests.js +++ b/packages/snjs/mocha/TestRegistry/VaultTests.js @@ -11,6 +11,7 @@ export const VaultTests = { 'vaults/signatures.test.js', 'vaults/shared_vaults.test.js', 'vaults/invites.test.js', + 'vaults/locking.test.js', 'vaults/items.test.js', 'vaults/conflicts.test.js', 'vaults/deletion.test.js', diff --git a/packages/snjs/mocha/lib/AppContext.js b/packages/snjs/mocha/lib/AppContext.js index 625d46533..a8dd99d60 100644 --- a/packages/snjs/mocha/lib/AppContext.js +++ b/packages/snjs/mocha/lib/AppContext.js @@ -49,10 +49,6 @@ export class AppContext { ) } - get vaults() { - return this.application.vaults - } - get sessions() { return this.application.sessions } @@ -97,6 +93,14 @@ export class AppContext { return this.application.sharedVaults } + get vaults() { + return this.application.vaults + } + + get vaultLocks() { + return this.application.vaultLocks + } + get vaultUsers() { return this.application.vaultUsers } diff --git a/packages/snjs/mocha/lib/Collaboration.js b/packages/snjs/mocha/lib/Collaboration.js index d3e79b951..1f1d54f7b 100644 --- a/packages/snjs/mocha/lib/Collaboration.js +++ b/packages/snjs/mocha/lib/Collaboration.js @@ -82,6 +82,27 @@ export const createSharedVaultWithUnacceptedButTrustedInvite = async ( return { sharedVault, contact, contactContext, deinitContactContext, invite } } +export const createSharedVaultAndInviteContact = async ( + createInContext, + inviteContext, + inviteContact, + permissions = SharedVaultPermission.Write, +) => { + const sharedVault = await createSharedVault(createInContext) + + await createInContext.vaultInvites.inviteContactToSharedVault(sharedVault, inviteContact, permissions) + + const promise = inviteContext.awaitNextSyncSharedVaultFromScratchEvent() + + await inviteContext.sync() + + await acceptAllInvites(inviteContext) + + await promise + + return { sharedVault } +} + export const createSharedVaultWithUnacceptedAndUntrustedInvite = async ( context, permissions = SharedVaultPermission.Write, @@ -113,7 +134,6 @@ export const inviteNewPartyToSharedVault = async (context, sharedVault, permissi export const createPrivateVault = async (context) => { const privateVault = await context.vaults.createRandomizedVault({ name: 'My Private Vault', - storagePreference: KeySystemRootKeyStorageMode.Synced, }) return privateVault diff --git a/packages/snjs/mocha/test.html b/packages/snjs/mocha/test.html index cd06a91be..15410a724 100644 --- a/packages/snjs/mocha/test.html +++ b/packages/snjs/mocha/test.html @@ -61,7 +61,7 @@ await loadTests(MainRegistry.VaultTests.files); } - if (!MainRegistry.VaultTests.enabled.exclusive) { + if (!MainRegistry.VaultTests.enabled || !MainRegistry.VaultTests.enabled.exclusive) { await loadTests(MainRegistry.BaseTests); } diff --git a/packages/snjs/mocha/vaults/deletion.test.js b/packages/snjs/mocha/vaults/deletion.test.js index 65b8fe7d1..f20b88947 100644 --- a/packages/snjs/mocha/vaults/deletion.test.js +++ b/packages/snjs/mocha/vaults/deletion.test.js @@ -153,6 +153,16 @@ describe('shared vault deletion', function () { }) it('being removed from a shared vault should delete respective vault listing', async () => { - console.error('TODO: implement test') + const { sharedVault, contactContext, deinitContactContext } = + await Collaboration.createSharedVaultWithAcceptedInvite(context) + + await context.vaultUsers.removeUserFromSharedVault(sharedVault, contactContext.userUuid) + + await contactContext.sync() + + const vault = contactContext.vaults.getVault({ keySystemIdentifier: sharedVault.systemIdentifier }) + expect(vault).to.be.undefined + + await deinitContactContext() }) }) diff --git a/packages/snjs/mocha/vaults/invites.test.js b/packages/snjs/mocha/vaults/invites.test.js index fdc0af35f..d0b4c5fc2 100644 --- a/packages/snjs/mocha/vaults/invites.test.js +++ b/packages/snjs/mocha/vaults/invites.test.js @@ -200,10 +200,6 @@ describe('shared vault invites', function () { await deinitContactContext() }) - it('when inviter keypair changes, recipient should still be able to trust and decrypt previous invite', async () => { - console.error('TODO: implement test') - }) - it('should delete all inbound invites after changing user password', async () => { /** Invites to user are encrypted with old keypair and are no longer decryptable */ const { contactContext, deinitContactContext } = diff --git a/packages/snjs/mocha/vaults/items.test.js b/packages/snjs/mocha/vaults/items.test.js index ed7fa48a6..aa206e25c 100644 --- a/packages/snjs/mocha/vaults/items.test.js +++ b/packages/snjs/mocha/vaults/items.test.js @@ -117,6 +117,28 @@ describe('shared vault items', function () { }) it('adding item to vault while belonging to other vault should move the item to new vault', async () => { - console.error('TODO: implement test') + const { note, sharedVault, contactContext, contact, deinitContactContext } = + await Collaboration.createSharedVaultWithAcceptedInviteAndNote(context) + + const { sharedVault: otherSharedVault } = await Collaboration.createSharedVaultAndInviteContact( + context, + contactContext, + contact, + ) + + const updatedNote = await Collaboration.moveItemToVault(context, otherSharedVault, note) + + expect(updatedNote.key_system_identifier).to.equal(otherSharedVault.systemIdentifier) + expect(updatedNote.shared_vault_uuid).to.equal(otherSharedVault.sharing.sharedVaultUuid) + + await contactContext.sync() + + const receivedNote = contactContext.items.findItem(note.uuid) + expect(receivedNote).to.not.be.undefined + expect(receivedNote.title).to.equal(note.title) + expect(receivedNote.key_system_identifier).to.equal(otherSharedVault.systemIdentifier) + expect(receivedNote.shared_vault_uuid).to.equal(otherSharedVault.sharing.sharedVaultUuid) + + await deinitContactContext() }) }) diff --git a/packages/snjs/mocha/vaults/key_rotation.test.js b/packages/snjs/mocha/vaults/key_rotation.test.js index f27fc4c50..c5094742c 100644 --- a/packages/snjs/mocha/vaults/key_rotation.test.js +++ b/packages/snjs/mocha/vaults/key_rotation.test.js @@ -229,36 +229,4 @@ describe('shared vault key rotation', function () { await deinitContactContext() }) - - it('should throw if attempting to change password of locked vault', async () => { - console.error('TODO: implement') - }) - - it('should respect storage preference when rotating key system root key', async () => { - console.error('TODO: implement') - }) - - it('should change storage preference from synced to local', async () => { - console.error('TODO: implement') - }) - - it('should change storage preference from local to synced', async () => { - console.error('TODO: implement') - }) - - it('should resync key system items key if it is encrypted with noncurrent key system root key', async () => { - console.error('TODO: implement') - }) - - it('should change password type from user inputted to randomized', async () => { - console.error('TODO: implement') - }) - - it('should change password type from randomized to user inputted', async () => { - console.error('TODO: implement') - }) - - it('should not be able to change storage mode of third party vault', async () => { - console.error('TODO: implement') - }) }) diff --git a/packages/snjs/mocha/vaults/locking.test.js b/packages/snjs/mocha/vaults/locking.test.js new file mode 100644 index 000000000..f737e1f2a --- /dev/null +++ b/packages/snjs/mocha/vaults/locking.test.js @@ -0,0 +1,108 @@ +import * as Factory from '../lib/factory.js' +import * as Collaboration from '../lib/Collaboration.js' + +chai.use(chaiAsPromised) +const expect = chai.expect + +describe('vault locking', function () { + this.timeout(Factory.TwentySecondTimeout) + + let context + + afterEach(async function () { + await context.deinit() + localStorage.clear() + }) + + beforeEach(async function () { + localStorage.clear() + + context = await Factory.createAppContextWithRealCrypto() + + await context.launch() + await context.register() + }) + + it('should lock non-persistent vault', async () => { + const vault = await context.vaults.createUserInputtedPasswordVault({ + name: 'test vault', + description: 'test vault description', + userInputtedPassword: 'test password', + storagePreference: KeySystemRootKeyStorageMode.Ephemeral, + }) + + context.vaultLocks.lockNonPersistentVault(vault) + + expect(context.vaultLocks.isVaultLocked(vault)).to.be.true + }) + + it('should not be able to lock user-inputted vault with synced key', async () => { + const vault = await context.vaults.createUserInputtedPasswordVault({ + name: 'test vault', + description: 'test vault description', + userInputtedPassword: 'test password', + storagePreference: KeySystemRootKeyStorageMode.Synced, + }) + + expect(() => context.vaultLocks.lockNonPersistentVault(vault)).to.throw( + Error, + 'Vault uses synced key storage and cannot be locked', + ) + }) + + it('should not be able to lock randomized vault', async () => { + const vault = await context.vaults.createRandomizedVault({ + name: 'test vault', + description: 'test vault description', + }) + + expect(() => context.vaultLocks.lockNonPersistentVault(vault)).to.throw( + Error, + 'Vault uses synced key storage and cannot be locked', + ) + }) + + it('should throw if attempting to change password of locked vault', async () => { + const vault = await context.vaults.createUserInputtedPasswordVault({ + name: 'test vault', + description: 'test vault description', + userInputtedPassword: 'test password', + storagePreference: KeySystemRootKeyStorageMode.Ephemeral, + }) + + context.vaultLocks.lockNonPersistentVault(vault) + + await Factory.expectThrowsAsync( + () => context.vaults.changeVaultOptions({ vault }), + 'Attempting to change vault options on a locked vault', + ) + }) + + it('should respect storage preference when rotating key system root key', async () => { + console.error('TODO: implement') + }) + + it('should change storage preference from synced to local', async () => { + console.error('TODO: implement') + }) + + it('should change storage preference from local to synced', async () => { + console.error('TODO: implement') + }) + + it('should resync key system items key if it is encrypted with noncurrent key system root key', async () => { + console.error('TODO: implement') + }) + + it('should change password type from user inputted to randomized', async () => { + console.error('TODO: implement') + }) + + it('should change password type from randomized to user inputted', async () => { + console.error('TODO: implement') + }) + + it('should not be able to change storage mode of third party vault', async () => { + console.error('TODO: implement') + }) +}) diff --git a/packages/snjs/mocha/vaults/vaults.test.js b/packages/snjs/mocha/vaults/vaults.test.js index 4f2fad311..2d5973130 100644 --- a/packages/snjs/mocha/vaults/vaults.test.js +++ b/packages/snjs/mocha/vaults/vaults.test.js @@ -42,7 +42,6 @@ describe('vaults', function () { it('should be able to create an offline vault', async () => { const vault = await vaults.createRandomizedVault({ name: 'My Vault', - storagePreference: KeySystemRootKeyStorageMode.Synced, }) expect(vault.systemIdentifier).to.not.be.undefined @@ -59,7 +58,6 @@ describe('vaults', function () { await context.application.addPasscode('123') const vault = await vaults.createRandomizedVault({ name: 'My Vault', - storagePreference: KeySystemRootKeyStorageMode.Synced, }) expect(vault.systemIdentifier).to.not.be.undefined @@ -75,7 +73,6 @@ describe('vaults', function () { it('should add item to offline vault', async () => { const vault = await vaults.createRandomizedVault({ name: 'My Vault', - storagePreference: KeySystemRootKeyStorageMode.Synced, }) const item = await context.createSyncedNote() @@ -89,7 +86,6 @@ describe('vaults', function () { const appIdentifier = context.identifier const vault = await vaults.createRandomizedVault({ name: 'My Vault', - storagePreference: KeySystemRootKeyStorageMode.Synced, }) const note = await context.createSyncedNote('foo', 'bar') await vaults.moveItemToVault(vault, note) @@ -110,7 +106,6 @@ describe('vaults', function () { const appIdentifier = context.identifier const vault = await vaults.createRandomizedVault({ name: 'My Vault', - storagePreference: KeySystemRootKeyStorageMode.Synced, }) const note = await context.createSyncedNote('foo', 'bar') await vaults.moveItemToVault(vault, note) @@ -138,7 +133,6 @@ describe('vaults', function () { const appIdentifier = context.identifier const vault = await vaults.createRandomizedVault({ name: 'My Vault', - storagePreference: KeySystemRootKeyStorageMode.Synced, }) const note = await context.createSyncedNote('foo', 'bar') await vaults.moveItemToVault(vault, note) @@ -168,7 +162,6 @@ describe('vaults', function () { it('should create a vault', async () => { const vault = await vaults.createRandomizedVault({ name: 'My Vault', - storagePreference: KeySystemRootKeyStorageMode.Synced, }) expect(vault).to.not.be.undefined @@ -184,7 +177,6 @@ describe('vaults', function () { const note = await context.createSyncedNote('foo', 'bar') const vault = await vaults.createRandomizedVault({ name: 'My Vault', - storagePreference: KeySystemRootKeyStorageMode.Synced, }) await vaults.moveItemToVault(vault, note) @@ -198,7 +190,6 @@ describe('vaults', function () { const appIdentifier = context.identifier const vault = await vaults.createRandomizedVault({ name: 'My Vault', - storagePreference: KeySystemRootKeyStorageMode.Synced, }) const note = await context.createSyncedNote('foo', 'bar') await vaults.moveItemToVault(vault, note) @@ -219,7 +210,6 @@ describe('vaults', function () { it('rotating a key system root key should create a new vault items key', async () => { const vault = await vaults.createRandomizedVault({ name: 'My Vault', - storagePreference: KeySystemRootKeyStorageMode.Synced, }) const keySystemItemsKey = context.keys.getKeySystemItemsKeys(vault.systemIdentifier)[0] @@ -235,7 +225,6 @@ describe('vaults', function () { it('deleting a vault should delete all its items', async () => { const vault = await vaults.createRandomizedVault({ name: 'My Vault', - storagePreference: KeySystemRootKeyStorageMode.Synced, }) const note = await context.createSyncedNote('foo', 'bar') await vaults.moveItemToVault(vault, note) diff --git a/packages/ui-services/src/Vaults/VaultDisplayService.ts b/packages/ui-services/src/Vaults/VaultDisplayService.ts index d02a23911..13be7355e 100644 --- a/packages/ui-services/src/Vaults/VaultDisplayService.ts +++ b/packages/ui-services/src/Vaults/VaultDisplayService.ts @@ -11,7 +11,7 @@ import { InternalEventHandlerInterface, InternalEventInterface, StorageKey, - VaultServiceEvent, + VaultLockServiceEvent, } from '@standardnotes/services' import { VaultDisplayOptions, VaultDisplayOptionsPersistable, VaultListingInterface } from '@standardnotes/models' import { VaultDisplayServiceEvent } from './VaultDisplayServiceEvent' @@ -33,8 +33,8 @@ export class VaultDisplayService this.options = new VaultDisplayOptions({ exclude: [], locked: [] }) - internalEventBus.addEventHandler(this, VaultServiceEvent.VaultLocked) - internalEventBus.addEventHandler(this, VaultServiceEvent.VaultUnlocked) + internalEventBus.addEventHandler(this, VaultLockServiceEvent.VaultLocked) + internalEventBus.addEventHandler(this, VaultLockServiceEvent.VaultUnlocked) internalEventBus.addEventHandler(this, ApplicationEvent.ApplicationStageChanged) makeObservable(this, { @@ -51,7 +51,7 @@ export class VaultDisplayService } async handleEvent(event: InternalEventInterface): Promise { - if (event.type === VaultServiceEvent.VaultLocked || event.type === VaultServiceEvent.VaultUnlocked) { + if (event.type === VaultLockServiceEvent.VaultLocked || event.type === VaultLockServiceEvent.VaultUnlocked) { this.handleVaultLockingStatusChanged() } else if (event.type === ApplicationEvent.ApplicationStageChanged) { const stage = (event.payload as ApplicationStageChangedEventPayload).stage @@ -62,7 +62,7 @@ export class VaultDisplayService } private handleVaultLockingStatusChanged(): void { - const lockedVaults = this.application.vaults.getLockedvaults() + const lockedVaults = this.application.vaultLocks.getLockedvaults() const options = this.options.newOptionsByIntakingLockedVaults(lockedVaults) this.setVaultSelectionOptions(options) @@ -90,7 +90,7 @@ export class VaultDisplayService changeToMultipleVaultDisplayMode(): void { const vaults = this.application.vaults.getVaults() - const lockedVaults = this.application.vaults.getLockedvaults() + const lockedVaults = this.application.vaultLocks.getLockedvaults() const newOptions = new VaultDisplayOptions({ exclude: vaults @@ -103,26 +103,26 @@ export class VaultDisplayService } hideVault = (vault: VaultListingInterface) => { - const lockedVaults = this.application.vaults.getLockedvaults() + const lockedVaults = this.application.vaultLocks.getLockedvaults() const newOptions = this.options.newOptionsByExcludingVault(vault, lockedVaults) this.setVaultSelectionOptions(newOptions) } unhideVault = async (vault: VaultListingInterface) => { - if (this.application.vaults.isVaultLocked(vault)) { + if (this.application.vaultLocks.isVaultLocked(vault)) { const unlocked = await this.unlockVault(vault) if (!unlocked) { return } } - const lockedVaults = this.application.vaults.getLockedvaults() + const lockedVaults = this.application.vaultLocks.getLockedvaults() const newOptions = this.options.newOptionsByUnexcludingVault(vault, lockedVaults) this.setVaultSelectionOptions(newOptions) } showOnlyVault = async (vault: VaultListingInterface) => { - if (this.application.vaults.isVaultLocked(vault)) { + if (this.application.vaultLocks.isVaultLocked(vault)) { const unlocked = await this.unlockVault(vault) if (!unlocked) { return @@ -134,7 +134,7 @@ export class VaultDisplayService } async unlockVault(vault: VaultListingInterface): Promise { - if (!this.application.vaults.isVaultLocked(vault)) { + if (!this.application.vaultLocks.isVaultLocked(vault)) { throw new Error('Attempting to unlock a vault that is not locked.') } @@ -161,7 +161,7 @@ export class VaultDisplayService const password = value.value as string - const unlocked = await this.application.vaults.unlockNonPersistentVault(vault, password) + const unlocked = await this.application.vaultLocks.unlockNonPersistentVault(vault, password) if (!unlocked) { this.application.challenges.setValidationStatusForChallenge(challenge, value, false) resolve(false) diff --git a/packages/web/src/javascripts/Components/Preferences/Panes/Vaults/Vaults/VaultItem.tsx b/packages/web/src/javascripts/Components/Preferences/Panes/Vaults/Vaults/VaultItem.tsx index 62daa8648..b49d625d7 100644 --- a/packages/web/src/javascripts/Components/Preferences/Panes/Vaults/Vaults/VaultItem.tsx +++ b/packages/web/src/javascripts/Components/Preferences/Panes/Vaults/Vaults/VaultItem.tsx @@ -72,12 +72,12 @@ const VaultItem = ({ vault }: Props) => { }, [application.sharedVaults, vault]) const ensureVaultIsUnlocked = useCallback(async () => { - if (!application.vaults.isVaultLocked(vault)) { + if (!application.vaultLocks.isVaultLocked(vault)) { return true } const unlocked = await application.vaultDisplayService.unlockVault(vault) return unlocked - }, [application.vaultDisplayService, application.vaults, vault]) + }, [application, vault]) const openEditModal = useCallback(async () => { if (!(await ensureVaultIsUnlocked())) { diff --git a/packages/web/src/javascripts/Components/Preferences/Panes/Vaults/Vaults/VaultModal/EditVaultModal.tsx b/packages/web/src/javascripts/Components/Preferences/Panes/Vaults/Vaults/VaultModal/EditVaultModal.tsx index 9c5425e6d..2eb60d53f 100644 --- a/packages/web/src/javascripts/Components/Preferences/Panes/Vaults/Vaults/VaultModal/EditVaultModal.tsx +++ b/packages/web/src/javascripts/Components/Preferences/Panes/Vaults/Vaults/VaultModal/EditVaultModal.tsx @@ -3,7 +3,7 @@ import Modal, { ModalAction } from '@/Components/Modal/Modal' import DecoratedInput from '@/Components/Input/DecoratedInput' import { useApplication } from '@/Components/ApplicationProvider' import { - ChangeVaultOptionsDTO, + ChangeVaultKeyOptionsDTO, KeySystemRootKeyPasswordType, KeySystemRootKeyStorageMode, SharedVaultInviteServerHash, @@ -89,7 +89,7 @@ const EditVaultModal: FunctionComponent = ({ onCloseDialog, existingVault const isChangingPasswordType = vault.keyPasswordType !== passwordType const isChangingKeyStorageMode = vault.keyStorageMode !== keyStorageMode - const getPasswordTypeParams = (): ChangeVaultOptionsDTO['newPasswordType'] => { + const getPasswordTypeParams = (): ChangeVaultKeyOptionsDTO['newPasswordType'] => { if (!isChangingPasswordType) { throw new Error('Password type is not changing') } @@ -135,7 +135,6 @@ const EditVaultModal: FunctionComponent = ({ onCloseDialog, existingVault await application.vaults.createRandomizedVault({ name, description, - storagePreference: keyStorageMode, }) } @@ -169,7 +168,7 @@ const EditVaultModal: FunctionComponent = ({ onCloseDialog, existingVault [existingVault, handleDialogClose, handleSubmit], ) - if (existingVault && application.vaults.isVaultLocked(existingVault)) { + if (existingVault && application.vaultLocks.isVaultLocked(existingVault)) { return
Vault is locked.
} diff --git a/packages/web/src/javascripts/Components/VaultSelectionMenu/ManyVaultSelectionMenu.tsx b/packages/web/src/javascripts/Components/VaultSelectionMenu/ManyVaultSelectionMenu.tsx index a999bf9dc..69836415d 100644 --- a/packages/web/src/javascripts/Components/VaultSelectionMenu/ManyVaultSelectionMenu.tsx +++ b/packages/web/src/javascripts/Components/VaultSelectionMenu/ManyVaultSelectionMenu.tsx @@ -41,7 +41,7 @@ const ManyVaultSelectionMenu: FunctionComponent = () => {
{vault.name} - {application.vaults.isVaultLocked(vault) && } + {application.vaultLocks.isVaultLocked(vault) && }
))} diff --git a/packages/web/src/javascripts/Components/VaultSelectionMenu/SingleVaultSelectionMenu.tsx b/packages/web/src/javascripts/Components/VaultSelectionMenu/SingleVaultSelectionMenu.tsx index cfb4122b6..688107370 100644 --- a/packages/web/src/javascripts/Components/VaultSelectionMenu/SingleVaultSelectionMenu.tsx +++ b/packages/web/src/javascripts/Components/VaultSelectionMenu/SingleVaultSelectionMenu.tsx @@ -30,7 +30,7 @@ const SingleVaultSelectionMenu: FunctionComponent = () => { selectVault(vault)}>
{vault.name} - {application.vaults.isVaultLocked(vault) && } + {application.vaultLocks.isVaultLocked(vault) && }
))} diff --git a/packages/web/src/javascripts/Components/Vaults/AddToVaultMenuOption.tsx b/packages/web/src/javascripts/Components/Vaults/AddToVaultMenuOption.tsx index 15ac9a367..d5830b74c 100644 --- a/packages/web/src/javascripts/Components/Vaults/AddToVaultMenuOption.tsx +++ b/packages/web/src/javascripts/Components/Vaults/AddToVaultMenuOption.tsx @@ -29,7 +29,7 @@ const AddToVaultMenuOption: FunctionComponent = ({ iconClassName, items } const addItemsToVault = useCallback( async (vault: VaultListingInterface) => { - if (application.vaults.isVaultLocked(vault)) { + if (application.vaultLocks.isVaultLocked(vault)) { const unlocked = await application.vaultDisplayService.unlockVault(vault) if (!unlocked) { return @@ -40,7 +40,7 @@ const AddToVaultMenuOption: FunctionComponent = ({ iconClassName, items } await application.vaults.moveItemToVault(vault, item) } }, - [application.vaultDisplayService, application.vaults, items], + [application, items], ) const removeItemsFromVault = useCallback(async () => { @@ -50,7 +50,7 @@ const AddToVaultMenuOption: FunctionComponent = ({ iconClassName, items } continue } - if (application.vaults.isVaultLocked(vault)) { + if (application.vaultLocks.isVaultLocked(vault)) { const unlocked = await application.vaultDisplayService.unlockVault(vault) if (!unlocked) { return @@ -58,7 +58,7 @@ const AddToVaultMenuOption: FunctionComponent = ({ iconClassName, items } } await application.vaults.removeItemFromVault(item) } - }, [application.vaultDisplayService, application.vaults, items]) + }, [application, items]) const doesVaultContainItems = (vault: VaultListingInterface) => { return items.every((item) => item.key_system_identifier === vault.systemIdentifier) @@ -140,7 +140,9 @@ const AddToVaultMenuOption: FunctionComponent = ({ iconClassName, items } />
{vault.name} - {application.vaults.isVaultLocked(vault) && } + {application.vaultLocks.isVaultLocked(vault) && ( + + )}