refactor: application dependency management (#2363)

This commit is contained in:
Mo
2023-07-23 15:54:31 -05:00
committed by GitHub
parent e698b1c990
commit a77535456c
299 changed files with 7415 additions and 4890 deletions

View File

@@ -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(

View File

@@ -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

View File

@@ -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)

View File

@@ -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)
}
}
}

View File

@@ -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,

View File

@@ -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
}

View File

@@ -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()
}
}