refactor: application dependency management (#2363)
This commit is contained in:
@@ -1,28 +1,24 @@
|
||||
import { MutatorClientInterface, SyncServiceInterface } from '@standardnotes/services'
|
||||
import { ItemManagerInterface } from '../../Item/ItemManagerInterface'
|
||||
import {
|
||||
KeySystemRootKeyPasswordType,
|
||||
KeySystemRootKeyStorageMode,
|
||||
VaultListingInterface,
|
||||
VaultListingMutator,
|
||||
} from '@standardnotes/models'
|
||||
import { EncryptionProviderInterface, KeySystemKeyManagerInterface } from '@standardnotes/encryption'
|
||||
import { ChangeVaultOptionsDTO } from '../ChangeVaultOptionsDTO'
|
||||
import { GetVaultUseCase } from './GetVault'
|
||||
import { assert } from '@standardnotes/utils'
|
||||
import { GetVault } from './GetVault'
|
||||
import { EncryptionProviderInterface } from '../../Encryption/EncryptionProviderInterface'
|
||||
import { KeySystemKeyManagerInterface } from '../../KeySystem/KeySystemKeyManagerInterface'
|
||||
|
||||
export class ChangeVaultKeyOptionsUseCase {
|
||||
export class ChangeVaultKeyOptions {
|
||||
constructor(
|
||||
private items: ItemManagerInterface,
|
||||
private mutator: MutatorClientInterface,
|
||||
private sync: SyncServiceInterface,
|
||||
private encryption: EncryptionProviderInterface,
|
||||
private keys: KeySystemKeyManagerInterface,
|
||||
private getVault: GetVault,
|
||||
) {}
|
||||
|
||||
private get keys(): KeySystemKeyManagerInterface {
|
||||
return this.encryption.keys
|
||||
}
|
||||
|
||||
async execute(dto: ChangeVaultOptionsDTO): Promise<void> {
|
||||
const useStorageMode = dto.newKeyStorageMode ?? dto.vault.keyStorageMode
|
||||
|
||||
@@ -42,9 +38,13 @@ export class ChangeVaultKeyOptionsUseCase {
|
||||
}
|
||||
|
||||
if (dto.newKeyStorageMode) {
|
||||
const usecase = new GetVaultUseCase(this.items)
|
||||
const latestVault = usecase.execute({ keySystemIdentifier: dto.vault.systemIdentifier })
|
||||
assert(latestVault)
|
||||
const result = this.getVault.execute({ keySystemIdentifier: dto.vault.systemIdentifier })
|
||||
|
||||
if (result.isFailed()) {
|
||||
throw new Error('Vault not found')
|
||||
}
|
||||
|
||||
const latestVault = result.getValue()
|
||||
|
||||
if (latestVault.rootKeyParams.passwordType !== KeySystemRootKeyPasswordType.UserInputted) {
|
||||
throw new Error('Vault uses randomized password and cannot change its storage preference')
|
||||
@@ -80,14 +80,14 @@ export class ChangeVaultKeyOptionsUseCase {
|
||||
if (storageMode === KeySystemRootKeyStorageMode.Synced) {
|
||||
await this.mutator.insertItem(newRootKey, true)
|
||||
} else {
|
||||
this.encryption.keys.intakeNonPersistentKeySystemRootKey(newRootKey, storageMode)
|
||||
this.keys.intakeNonPersistentKeySystemRootKey(newRootKey, storageMode)
|
||||
}
|
||||
|
||||
await this.mutator.changeItem<VaultListingMutator>(vault, (mutator) => {
|
||||
mutator.rootKeyParams = newRootKey.keyParams
|
||||
})
|
||||
|
||||
await this.encryption.reencryptKeySystemItemsKeysForVault(vault.systemIdentifier)
|
||||
await this.keys.reencryptKeySystemItemsKeysForVault(vault.systemIdentifier)
|
||||
}
|
||||
|
||||
private async changePasswordTypeToRandomized(
|
||||
@@ -108,7 +108,7 @@ export class ChangeVaultKeyOptionsUseCase {
|
||||
|
||||
await this.mutator.insertItem(newRootKey, true)
|
||||
|
||||
await this.encryption.reencryptKeySystemItemsKeysForVault(vault.systemIdentifier)
|
||||
await this.keys.reencryptKeySystemItemsKeysForVault(vault.systemIdentifier)
|
||||
}
|
||||
|
||||
private async changeStorageModeToLocalOrEphemeral(
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { SyncServiceInterface } from './../../Sync/SyncServiceInterface'
|
||||
import { EncryptionProviderInterface } from '@standardnotes/encryption'
|
||||
import { UuidGenerator } from '@standardnotes/utils'
|
||||
import {
|
||||
KeySystemRootKeyParamsInterface,
|
||||
@@ -12,11 +11,14 @@ import {
|
||||
} from '@standardnotes/models'
|
||||
import { MutatorClientInterface } from '../../Mutator/MutatorClientInterface'
|
||||
import { ContentType } from '@standardnotes/domain-core'
|
||||
import { EncryptionProviderInterface } from '../../Encryption/EncryptionProviderInterface'
|
||||
import { KeySystemKeyManagerInterface } from '../../KeySystem/KeySystemKeyManagerInterface'
|
||||
|
||||
export class CreateVaultUseCase {
|
||||
export class CreateVault {
|
||||
constructor(
|
||||
private mutator: MutatorClientInterface,
|
||||
private encryption: EncryptionProviderInterface,
|
||||
private keys: KeySystemKeyManagerInterface,
|
||||
private sync: SyncServiceInterface,
|
||||
) {}
|
||||
|
||||
@@ -107,7 +109,7 @@ export class CreateVaultUseCase {
|
||||
if (dto.storagePreference === KeySystemRootKeyStorageMode.Synced) {
|
||||
await this.mutator.insertItem(newRootKey, true)
|
||||
} else {
|
||||
this.encryption.keys.intakeNonPersistentKeySystemRootKey(newRootKey, dto.storagePreference)
|
||||
this.keys.intakeNonPersistentKeySystemRootKey(newRootKey, dto.storagePreference)
|
||||
}
|
||||
|
||||
return newRootKey
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import { ClientDisplayableError } from '@standardnotes/responses'
|
||||
import { ItemManagerInterface } from '../../Item/ItemManagerInterface'
|
||||
import { VaultListingInterface } from '@standardnotes/models'
|
||||
import { EncryptionProviderInterface } from '@standardnotes/encryption'
|
||||
import { MutatorClientInterface } from '../../Mutator/MutatorClientInterface'
|
||||
import { KeySystemKeyManagerInterface } from '../../KeySystem/KeySystemKeyManagerInterface'
|
||||
|
||||
export class DeleteVaultUseCase {
|
||||
export class DeleteVault {
|
||||
constructor(
|
||||
private items: ItemManagerInterface,
|
||||
private mutator: MutatorClientInterface,
|
||||
private encryption: EncryptionProviderInterface,
|
||||
private keys: KeySystemKeyManagerInterface,
|
||||
) {}
|
||||
|
||||
async execute(vault: VaultListingInterface): Promise<ClientDisplayableError | void> {
|
||||
@@ -16,12 +16,12 @@ export class DeleteVaultUseCase {
|
||||
throw new Error('Vault system identifier is missing')
|
||||
}
|
||||
|
||||
await this.encryption.keys.deleteNonPersistentSystemRootKeysForVault(vault.systemIdentifier)
|
||||
await this.keys.deleteNonPersistentSystemRootKeysForVault(vault.systemIdentifier)
|
||||
|
||||
const rootKeys = this.encryption.keys.getSyncedKeySystemRootKeysForVault(vault.systemIdentifier)
|
||||
const rootKeys = this.keys.getSyncedKeySystemRootKeysForVault(vault.systemIdentifier)
|
||||
await this.mutator.setItemsToBeDeleted(rootKeys)
|
||||
|
||||
const itemsKeys = this.encryption.keys.getKeySystemItemsKeys(vault.systemIdentifier)
|
||||
const itemsKeys = this.keys.getKeySystemItemsKeys(vault.systemIdentifier)
|
||||
await this.mutator.setItemsToBeDeleted(itemsKeys)
|
||||
|
||||
const vaultItems = this.items.itemsBelongingToKeySystem(vault.systemIdentifier)
|
||||
|
||||
@@ -1,17 +1,29 @@
|
||||
import { VaultListingInterface } from '@standardnotes/models'
|
||||
import { ItemManagerInterface } from './../../Item/ItemManagerInterface'
|
||||
import { ContentType } from '@standardnotes/domain-core'
|
||||
import { ContentType, Result, SyncUseCaseInterface } from '@standardnotes/domain-core'
|
||||
|
||||
export class GetVaultUseCase<T extends VaultListingInterface> {
|
||||
export class GetVault implements SyncUseCaseInterface<VaultListingInterface> {
|
||||
constructor(private items: ItemManagerInterface) {}
|
||||
|
||||
execute(query: { keySystemIdentifier: string } | { sharedVaultUuid: string }): T | undefined {
|
||||
execute<T extends VaultListingInterface>(
|
||||
query: { keySystemIdentifier: string } | { sharedVaultUuid: string },
|
||||
): Result<T> {
|
||||
const vaults = this.items.getItems<VaultListingInterface>(ContentType.TYPES.VaultListing)
|
||||
|
||||
if ('keySystemIdentifier' in query) {
|
||||
return vaults.find((listing) => listing.systemIdentifier === query.keySystemIdentifier) as T
|
||||
const result = vaults.find((listing) => listing.systemIdentifier === query.keySystemIdentifier) as T
|
||||
if (!result) {
|
||||
return Result.fail('Vault not found')
|
||||
}
|
||||
|
||||
return Result.ok(result)
|
||||
} else {
|
||||
return vaults.find((listing) => listing.sharing?.sharedVaultUuid === query.sharedVaultUuid) as T
|
||||
const result = vaults.find((listing) => listing.sharing?.sharedVaultUuid === query.sharedVaultUuid) as T
|
||||
if (!result) {
|
||||
return Result.fail('Vault not found')
|
||||
}
|
||||
|
||||
return Result.ok(result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import { DecryptedItemInterface, FileItem, VaultListingInterface } from '@standa
|
||||
import { FilesClientInterface } from '@standardnotes/files'
|
||||
import { ContentType } from '@standardnotes/domain-core'
|
||||
|
||||
export class MoveItemsToVaultUseCase {
|
||||
export class MoveItemsToVault {
|
||||
constructor(
|
||||
private mutator: MutatorClientInterface,
|
||||
private sync: SyncServiceInterface,
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { UuidGenerator, assert } from '@standardnotes/utils'
|
||||
import { EncryptionProviderInterface } from '@standardnotes/encryption'
|
||||
import { ClientDisplayableError, isClientDisplayableError } from '@standardnotes/responses'
|
||||
import {
|
||||
KeySystemIdentifier,
|
||||
@@ -10,16 +9,22 @@ import {
|
||||
VaultListingMutator,
|
||||
} from '@standardnotes/models'
|
||||
import { MutatorClientInterface } from '../../Mutator/MutatorClientInterface'
|
||||
import { EncryptionProviderInterface } from '../../Encryption/EncryptionProviderInterface'
|
||||
import { KeySystemKeyManagerInterface } from '../../KeySystem/KeySystemKeyManagerInterface'
|
||||
|
||||
export class RotateVaultRootKeyUseCase {
|
||||
constructor(private mutator: MutatorClientInterface, private encryption: EncryptionProviderInterface) {}
|
||||
export class RotateVaultKey {
|
||||
constructor(
|
||||
private mutator: MutatorClientInterface,
|
||||
private encryption: EncryptionProviderInterface,
|
||||
private keys: KeySystemKeyManagerInterface,
|
||||
) {}
|
||||
|
||||
async execute(params: {
|
||||
vault: VaultListingInterface
|
||||
sharedVaultUuid: string | undefined
|
||||
userInputtedPassword: string | undefined
|
||||
}): Promise<undefined | ClientDisplayableError[]> {
|
||||
const currentRootKey = this.encryption.keys.getPrimaryKeySystemRootKey(params.vault.systemIdentifier)
|
||||
const currentRootKey = this.keys.getPrimaryKeySystemRootKey(params.vault.systemIdentifier)
|
||||
if (!currentRootKey) {
|
||||
throw new Error('Cannot rotate key system root key; key system root key not found')
|
||||
}
|
||||
@@ -48,7 +53,7 @@ export class RotateVaultRootKeyUseCase {
|
||||
if (params.vault.keyStorageMode === KeySystemRootKeyStorageMode.Synced) {
|
||||
await this.mutator.insertItem(newRootKey, true)
|
||||
} else {
|
||||
this.encryption.keys.intakeNonPersistentKeySystemRootKey(newRootKey, params.vault.keyStorageMode)
|
||||
this.keys.intakeNonPersistentKeySystemRootKey(newRootKey, params.vault.keyStorageMode)
|
||||
}
|
||||
|
||||
await this.mutator.changeItem<VaultListingMutator>(params.vault, (mutator) => {
|
||||
@@ -68,7 +73,7 @@ export class RotateVaultRootKeyUseCase {
|
||||
errors.push(updateKeySystemItemsKeyResult)
|
||||
}
|
||||
|
||||
await this.encryption.reencryptKeySystemItemsKeysForVault(params.vault.systemIdentifier)
|
||||
await this.keys.reencryptKeySystemItemsKeysForVault(params.vault.systemIdentifier)
|
||||
|
||||
return errors
|
||||
}
|
||||
@@ -12,23 +12,22 @@ import {
|
||||
import { VaultServiceInterface } from './VaultServiceInterface'
|
||||
import { ChangeVaultOptionsDTO } from './ChangeVaultOptionsDTO'
|
||||
import { VaultServiceEvent, VaultServiceEventPayload } from './VaultServiceEvent'
|
||||
import { EncryptionProviderInterface } from '@standardnotes/encryption'
|
||||
import { CreateVaultUseCase } from './UseCase/CreateVault'
|
||||
import { CreateVault } from './UseCase/CreateVault'
|
||||
import { AbstractService } from '../Service/AbstractService'
|
||||
import { SyncServiceInterface } from '../Sync/SyncServiceInterface'
|
||||
import { ItemManagerInterface } from '../Item/ItemManagerInterface'
|
||||
import { InternalEventBusInterface } from '../Internal/InternalEventBusInterface'
|
||||
import { RemoveItemFromVault } from './UseCase/RemoveItemFromVault'
|
||||
import { DeleteVaultUseCase } from './UseCase/DeleteVault'
|
||||
import { MoveItemsToVaultUseCase } from './UseCase/MoveItemsToVault'
|
||||
|
||||
import { RotateVaultRootKeyUseCase } from './UseCase/RotateVaultRootKey'
|
||||
import { FilesClientInterface } from '@standardnotes/files'
|
||||
import { GetVaultUseCase } from './UseCase/GetVault'
|
||||
import { ChangeVaultKeyOptionsUseCase } from './UseCase/ChangeVaultKeyOptions'
|
||||
import { DeleteVault } from './UseCase/DeleteVault'
|
||||
import { MoveItemsToVault } from './UseCase/MoveItemsToVault'
|
||||
import { RotateVaultKey } from './UseCase/RotateVaultKey'
|
||||
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'
|
||||
|
||||
export class VaultService
|
||||
extends AbstractService<VaultServiceEvent, VaultServiceEventPayload[VaultServiceEvent]>
|
||||
@@ -41,8 +40,15 @@ export class VaultService
|
||||
private items: ItemManagerInterface,
|
||||
private mutator: MutatorClientInterface,
|
||||
private encryption: EncryptionProviderInterface,
|
||||
private files: FilesClientInterface,
|
||||
private keys: KeySystemKeyManagerInterface,
|
||||
private alerts: AlertService,
|
||||
private _getVault: GetVault,
|
||||
private _changeVaultKeyOptions: ChangeVaultKeyOptions,
|
||||
private _moveItemsToVault: MoveItemsToVault,
|
||||
private _createVault: CreateVault,
|
||||
private _removeItemFromVaultUseCase: RemoveItemFromVault,
|
||||
private _deleteVaultUseCase: DeleteVault,
|
||||
private _rotateVaultKey: RotateVaultKey,
|
||||
eventBus: InternalEventBusInterface,
|
||||
) {
|
||||
super(eventBus)
|
||||
@@ -67,8 +73,12 @@ export class VaultService
|
||||
}
|
||||
|
||||
public getVault(dto: { keySystemIdentifier: KeySystemIdentifier }): VaultListingInterface | undefined {
|
||||
const usecase = new GetVaultUseCase(this.items)
|
||||
return usecase.execute(dto)
|
||||
const result = this._getVault.execute(dto)
|
||||
if (result.isFailed()) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
return result.getValue()
|
||||
}
|
||||
|
||||
public getSureVault(dto: { keySystemIdentifier: KeySystemIdentifier }): VaultListingInterface {
|
||||
@@ -108,8 +118,7 @@ export class VaultService
|
||||
userInputtedPassword: string | undefined
|
||||
storagePreference: KeySystemRootKeyStorageMode
|
||||
}): Promise<VaultListingInterface> {
|
||||
const createVault = new CreateVaultUseCase(this.mutator, this.encryption, this.sync)
|
||||
const result = await createVault.execute({
|
||||
const result = await this._createVault.execute({
|
||||
vaultName: dto.name,
|
||||
vaultDescription: dto.description,
|
||||
userInputtedPassword: dto.userInputtedPassword,
|
||||
@@ -142,8 +151,7 @@ export class VaultService
|
||||
}
|
||||
}
|
||||
|
||||
const useCase = new MoveItemsToVaultUseCase(this.mutator, this.sync, this.files)
|
||||
await useCase.execute({ vault, items: [item, ...linkedFiles] })
|
||||
await this._moveItemsToVault.execute({ vault, items: [item, ...linkedFiles] })
|
||||
|
||||
return this.items.findSureItem(item.uuid)
|
||||
}
|
||||
@@ -158,8 +166,7 @@ export class VaultService
|
||||
throw new Error('Attempting to remove item from locked vault')
|
||||
}
|
||||
|
||||
const useCase = new RemoveItemFromVault(this.mutator, this.sync, this.files)
|
||||
await useCase.execute({ item })
|
||||
await this._removeItemFromVaultUseCase.execute({ item })
|
||||
return this.items.findSureItem(item.uuid)
|
||||
}
|
||||
|
||||
@@ -168,8 +175,7 @@ export class VaultService
|
||||
throw new Error('Shared vault must be deleted through SharedVaultService')
|
||||
}
|
||||
|
||||
const useCase = new DeleteVaultUseCase(this.items, this.mutator, this.encryption)
|
||||
const error = await useCase.execute(vault)
|
||||
const error = await this._deleteVaultUseCase.execute(vault)
|
||||
|
||||
if (isClientDisplayableError(error)) {
|
||||
return false
|
||||
@@ -198,8 +204,7 @@ export class VaultService
|
||||
throw new Error('Cannot rotate root key of locked vault')
|
||||
}
|
||||
|
||||
const useCase = new RotateVaultRootKeyUseCase(this.mutator, this.encryption)
|
||||
await useCase.execute({
|
||||
await this._rotateVaultKey.execute({
|
||||
vault,
|
||||
sharedVaultUuid: vault.isSharedVaultListing() ? vault.sharing.sharedVaultUuid : undefined,
|
||||
userInputtedPassword: undefined,
|
||||
@@ -232,8 +237,7 @@ export class VaultService
|
||||
throw new Error('Attempting to change vault options on a locked vault')
|
||||
}
|
||||
|
||||
const usecase = new ChangeVaultKeyOptionsUseCase(this.items, this.mutator, this.sync, this.encryption)
|
||||
await usecase.execute(dto)
|
||||
await this._changeVaultKeyOptions.execute(dto)
|
||||
|
||||
if (dto.newPasswordType) {
|
||||
await this.notifyEventSync(VaultServiceEvent.VaultRootKeyRotated, { vault: dto.vault })
|
||||
@@ -249,7 +253,7 @@ export class VaultService
|
||||
throw new Error('Vault uses synced root key and cannot be locked')
|
||||
}
|
||||
|
||||
this.encryption.keys.clearMemoryOfKeysRelatedToVault(vault)
|
||||
this.keys.clearMemoryOfKeysRelatedToVault(vault)
|
||||
|
||||
this.lockMap.set(vault.uuid, true)
|
||||
void this.notifyEventSync(VaultServiceEvent.VaultLocked, { vault })
|
||||
@@ -269,12 +273,12 @@ export class VaultService
|
||||
userInputtedPassword: password,
|
||||
})
|
||||
|
||||
this.encryption.keys.intakeNonPersistentKeySystemRootKey(derivedRootKey, vault.keyStorageMode)
|
||||
this.keys.intakeNonPersistentKeySystemRootKey(derivedRootKey, vault.keyStorageMode)
|
||||
|
||||
await this.encryption.decryptErroredPayloads()
|
||||
|
||||
if (this.computeVaultLockState(vault) === 'locked') {
|
||||
this.encryption.keys.undoIntakeNonPersistentKeySystemRootKey(vault.systemIdentifier)
|
||||
this.keys.undoIntakeNonPersistentKeySystemRootKey(vault.systemIdentifier)
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -303,12 +307,12 @@ export class VaultService
|
||||
}
|
||||
|
||||
private computeVaultLockState(vault: VaultListingInterface): 'locked' | 'unlocked' {
|
||||
const rootKey = this.encryption.keys.getPrimaryKeySystemRootKey(vault.systemIdentifier)
|
||||
const rootKey = this.keys.getPrimaryKeySystemRootKey(vault.systemIdentifier)
|
||||
if (!rootKey) {
|
||||
return 'locked'
|
||||
}
|
||||
|
||||
const itemsKey = this.encryption.keys.getPrimaryKeySystemItemsKey(vault.systemIdentifier)
|
||||
const itemsKey = this.keys.getPrimaryKeySystemItemsKey(vault.systemIdentifier)
|
||||
if (!itemsKey) {
|
||||
return 'locked'
|
||||
}
|
||||
@@ -319,7 +323,18 @@ export class VaultService
|
||||
override deinit(): void {
|
||||
super.deinit()
|
||||
;(this.sync as unknown) = undefined
|
||||
;(this.encryption 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._changeVaultKeyOptions as unknown) = undefined
|
||||
;(this._moveItemsToVault as unknown) = undefined
|
||||
;(this._createVault as unknown) = undefined
|
||||
;(this._removeItemFromVaultUseCase as unknown) = undefined
|
||||
;(this._deleteVaultUseCase as unknown) = undefined
|
||||
;(this._rotateVaultKey as unknown) = undefined
|
||||
|
||||
this.lockMap.clear()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user