diff --git a/packages/encryption/src/Domain/Service/Encryption/EncryptionProviderInterface.ts b/packages/encryption/src/Domain/Service/Encryption/EncryptionProviderInterface.ts index 39d62fb4c..8f72c3a19 100644 --- a/packages/encryption/src/Domain/Service/Encryption/EncryptionProviderInterface.ts +++ b/packages/encryption/src/Domain/Service/Encryption/EncryptionProviderInterface.ts @@ -72,7 +72,6 @@ export interface EncryptionProviderInterface { } > - decryptErroredPayloads(): Promise deleteWorkspaceSpecificKeyStateFromDevice(): Promise computeRootKey(password: string, keyParams: SNRootKeyParams): Promise diff --git a/packages/services/src/Domain/AsymmetricMessage/AsymmetricMessageService.ts b/packages/services/src/Domain/AsymmetricMessage/AsymmetricMessageService.ts index f7609b374..4759f2428 100644 --- a/packages/services/src/Domain/AsymmetricMessage/AsymmetricMessageService.ts +++ b/packages/services/src/Domain/AsymmetricMessage/AsymmetricMessageService.ts @@ -19,7 +19,6 @@ import { } from '@standardnotes/models' import { HandleTrustedSharedVaultRootKeyChangedMessage } from './UseCase/HandleTrustedSharedVaultRootKeyChangedMessage' import { ItemManagerInterface } from '../Item/ItemManagerInterface' -import { SyncServiceInterface } from '../Sync/SyncServiceInterface' import { SessionEvent } from '../Session/SessionEvent' import { AsymmetricMessageServer, HttpServiceInterface } from '@standardnotes/api' import { UserKeyPairChangedEventData } from '../Session/UserKeyPairChangedEventData' @@ -41,7 +40,7 @@ export class AsymmetricMessageService private contacts: ContactServiceInterface, private items: ItemManagerInterface, private mutator: MutatorClientInterface, - private sync: SyncServiceInterface, + private handleTrustedSharedVaultRootKeyChangedMessageUseCase: HandleTrustedSharedVaultRootKeyChangedMessage, eventBus: InternalEventBusInterface, ) { super(eventBus) @@ -189,12 +188,9 @@ export class AsymmetricMessageService _message: AsymmetricMessageServerHash, trustedPayload: AsymmetricMessageSharedVaultRootKeyChanged, ): Promise { - const useCase = new HandleTrustedSharedVaultRootKeyChangedMessage( - this.mutator, - this.items, - this.sync, - this.encryption, - ) - await useCase.execute(trustedPayload) + const resultOrError = await this.handleTrustedSharedVaultRootKeyChangedMessageUseCase.execute(trustedPayload) + if (resultOrError.isFailed()) { + throw new Error(resultOrError.getError()) + } } } diff --git a/packages/services/src/Domain/AsymmetricMessage/UseCase/HandleTrustedSharedVaultRootKeyChangedMessage.ts b/packages/services/src/Domain/AsymmetricMessage/UseCase/HandleTrustedSharedVaultRootKeyChangedMessage.ts index b2cc1ed22..c2f6363b6 100644 --- a/packages/services/src/Domain/AsymmetricMessage/UseCase/HandleTrustedSharedVaultRootKeyChangedMessage.ts +++ b/packages/services/src/Domain/AsymmetricMessage/UseCase/HandleTrustedSharedVaultRootKeyChangedMessage.ts @@ -1,6 +1,3 @@ -import { ItemManagerInterface } from './../../Item/ItemManagerInterface' -import { MutatorClientInterface } from './../../Mutator/MutatorClientInterface' -import { SyncServiceInterface } from '../../Sync/SyncServiceInterface' import { KeySystemRootKeyInterface, AsymmetricMessageSharedVaultRootKeyChanged, @@ -8,20 +5,23 @@ import { KeySystemRootKeyContent, VaultListingMutator, } from '@standardnotes/models' +import { ContentType, UseCaseInterface, Result } from '@standardnotes/domain-core' -import { ContentType } from '@standardnotes/domain-core' +import { ItemManagerInterface } from './../../Item/ItemManagerInterface' +import { MutatorClientInterface } from './../../Mutator/MutatorClientInterface' +import { SyncServiceInterface } from '../../Sync/SyncServiceInterface' import { GetVaultUseCase } from '../../Vaults/UseCase/GetVault' -import { EncryptionProviderInterface } from '@standardnotes/encryption' +import { EmitDecryptedErroredPayloads } from '../../Encryption/UseCase/EmitDecryptedErroredPayloads/EmitDecryptedErroredPayloads' -export class HandleTrustedSharedVaultRootKeyChangedMessage { +export class HandleTrustedSharedVaultRootKeyChangedMessage implements UseCaseInterface { constructor( private mutator: MutatorClientInterface, private items: ItemManagerInterface, private sync: SyncServiceInterface, - private encryption: EncryptionProviderInterface, + private emitDecryptedErroredPayloadsUseCase: EmitDecryptedErroredPayloads, ) {} - async execute(message: AsymmetricMessageSharedVaultRootKeyChanged): Promise { + async execute(message: AsymmetricMessageSharedVaultRootKeyChanged): Promise> { const rootKeyContent = message.data.rootKey await this.mutator.createItem( @@ -37,8 +37,13 @@ export class HandleTrustedSharedVaultRootKeyChangedMessage { }) } - await this.encryption.decryptErroredPayloads() + const emitedOrFailed = await this.emitDecryptedErroredPayloadsUseCase.execute() + if (emitedOrFailed.isFailed()) { + return Result.fail(emitedOrFailed.getError()) + } void this.sync.sync({ sourceDescription: 'Not awaiting due to this event handler running from sync response' }) + + return Result.ok() } } diff --git a/packages/services/src/Domain/Encryption/EncryptionService.ts b/packages/services/src/Domain/Encryption/EncryptionService.ts index db0a4d905..7ec5a52f9 100644 --- a/packages/services/src/Domain/Encryption/EncryptionService.ts +++ b/packages/services/src/Domain/Encryption/EncryptionService.ts @@ -49,14 +49,13 @@ import { RootKeyParamsInterface, } from '@standardnotes/models' import { ClientDisplayableError } from '@standardnotes/responses' -import { PkcKeyPair, PureCryptoInterface } from '@standardnotes/sncrypto-common' +import { PkcKeyPair } from '@standardnotes/sncrypto-common' import { extendArray, isNotUndefined, isNullOrUndefined, isReactNativeEnvironment, isWebCryptoAvailable, - UuidGenerator, } from '@standardnotes/utils' import { AnyKeyParamsContent, @@ -83,15 +82,12 @@ import { DecryptedParameters } from '@standardnotes/encryption/src/Domain/Types/ import { RootKeyManager } from './RootKey/RootKeyManager' import { RootKeyManagerEvent } from './RootKey/RootKeyManagerEvent' import { CreateNewItemsKeyWithRollbackUseCase } from './UseCase/ItemsKey/CreateNewItemsKeyWithRollback' -import { DecryptErroredRootPayloadsUseCase } from './UseCase/RootEncryption/DecryptErroredPayloads' import { CreateNewDefaultItemsKeyUseCase } from './UseCase/ItemsKey/CreateNewDefaultItemsKey' -import { RootKeyDecryptPayloadUseCase } from './UseCase/RootEncryption/DecryptPayload' -import { RootKeyDecryptPayloadWithKeyLookupUseCase } from './UseCase/RootEncryption/DecryptPayloadWithKeyLookup' -import { RootKeyEncryptPayloadWithKeyLookupUseCase } from './UseCase/RootEncryption/EncryptPayloadWithKeyLookup' -import { RootKeyEncryptPayloadUseCase } from './UseCase/RootEncryption/EncryptPayload' import { ValidateAccountPasswordResult } from './RootKey/ValidateAccountPasswordResult' import { ValidatePasscodeResult } from './RootKey/ValidatePasscodeResult' import { ContentType } from '@standardnotes/domain-core' +import { EncryptPayloads } from './UseCase/EncryptPayloads/EncryptPayloads' +import { DecryptPayloads } from './UseCase/DecryptPayloads/DecryptPayloads' /** * The encryption service is responsible for the encryption and decryption of payloads, and @@ -124,9 +120,7 @@ export class EncryptionService extends AbstractService implements EncryptionProviderInterface, InternalEventHandlerInterface { - private operators: OperatorManager private readonly itemsEncryption: ItemsEncryptionService - private readonly rootKeyManager: RootKeyManager constructor( private items: ItemManagerInterface, @@ -135,30 +129,18 @@ export class EncryptionService public device: DeviceInterface, private storage: StorageServiceInterface, public readonly keys: KeySystemKeyManagerInterface, - identifier: ApplicationIdentifier, - public crypto: PureCryptoInterface, + private rootKeyManager: RootKeyManager, + public identifier: ApplicationIdentifier, + private encryptPayloadsUseCase: EncryptPayloads, + private decryptPayloadsUseCase: DecryptPayloads, + private operators: OperatorManager, protected override internalEventBus: InternalEventBusInterface, ) { super(internalEventBus) - this.crypto = crypto - - this.operators = new OperatorManager(crypto) - - this.rootKeyManager = new RootKeyManager( - device, - storage, - items, - mutator, - this.operators, - identifier, - internalEventBus, - ) internalEventBus.addEventHandler(this, RootKeyManagerEvent.RootKeyManagerKeyStatusChanged) this.itemsEncryption = new ItemsEncryptionService(items, payloads, storage, this.operators, keys, internalEventBus) - - UuidGenerator.SetGenerator(this.crypto.generateUUID) } async handleEvent(event: InternalEventInterface): Promise { @@ -179,7 +161,6 @@ export class EncryptionService ;(this.payloads as unknown) = undefined ;(this.device as unknown) = undefined ;(this.storage as unknown) = undefined - ;(this.crypto as unknown) = undefined ;(this.operators as unknown) = undefined this.itemsEncryption.deinit() @@ -290,13 +271,6 @@ export class EncryptionService return usecase.execute() } - public async decryptErroredPayloads(): Promise { - const usecase = new DecryptErroredRootPayloadsUseCase(this.payloads, this.operators, this.keys, this.rootKeyManager) - await usecase.execute() - - await this.itemsEncryption.decryptErroredItemPayloads() - } - public itemsKeyForEncryptedPayload( payload: EncryptedPayloadInterface, ): ItemsKeyInterface | KeySystemItemsKeyInterface | undefined { @@ -326,47 +300,41 @@ export class EncryptionService usesKeySystemRootKeyWithKeyLookup, } = split - const rootKeyEncryptWithKeyLookupUsecase = new RootKeyEncryptPayloadWithKeyLookupUseCase( - this.operators, - this.keys, - this.rootKeyManager, - ) - - const rootKeyEncryptUsecase = new RootKeyEncryptPayloadUseCase(this.operators) - const signingKeyPair = this.hasSigningKeyPair() ? this.getSigningKeyPair() : undefined if (usesRootKey) { - const rootKeyEncrypted = await rootKeyEncryptUsecase.executeMany( - usesRootKey.items, - usesRootKey.key, + const rootKeyEncrypted = await this.encryptPayloads({ + payloads: usesRootKey.items, + key: usesRootKey.key, signingKeyPair, - ) + }) + extendArray(allEncryptedParams, rootKeyEncrypted) } if (usesRootKeyWithKeyLookup) { - const rootKeyEncrypted = await rootKeyEncryptWithKeyLookupUsecase.executeMany( - usesRootKeyWithKeyLookup.items, + const rootKeyEncrypted = await this.encryptPayloads({ + payloads: usesRootKeyWithKeyLookup.items, signingKeyPair, - ) + }) + extendArray(allEncryptedParams, rootKeyEncrypted) } if (usesKeySystemRootKey) { - const keySystemRootKeyEncrypted = await rootKeyEncryptUsecase.executeMany( - usesKeySystemRootKey.items, - usesKeySystemRootKey.key, + const keySystemRootKeyEncrypted = await this.encryptPayloads({ + payloads: usesKeySystemRootKey.items, + key: usesKeySystemRootKey.key, signingKeyPair, - ) + }) extendArray(allEncryptedParams, keySystemRootKeyEncrypted) } if (usesKeySystemRootKeyWithKeyLookup) { - const keySystemRootKeyEncrypted = await rootKeyEncryptWithKeyLookupUsecase.executeMany( - usesKeySystemRootKeyWithKeyLookup.items, + const keySystemRootKeyEncrypted = await this.encryptPayloads({ + payloads: usesKeySystemRootKeyWithKeyLookup.items, signingKeyPair, - ) + }) extendArray(allEncryptedParams, keySystemRootKeyEncrypted) } @@ -423,34 +391,29 @@ export class EncryptionService usesKeySystemRootKeyWithKeyLookup, } = split - const rootKeyDecryptUseCase = new RootKeyDecryptPayloadUseCase(this.operators) - - const rootKeyDecryptWithKeyLookupUsecase = new RootKeyDecryptPayloadWithKeyLookupUseCase( - this.operators, - this.keys, - this.rootKeyManager, - ) - if (usesRootKey) { - const rootKeyDecrypted = await rootKeyDecryptUseCase.executeMany(usesRootKey.items, usesRootKey.key) + const rootKeyDecrypted = await this.decryptPayloads({ + payloads: usesRootKey.items, + key: usesRootKey.key, + }) extendArray(resultParams, rootKeyDecrypted) } if (usesRootKeyWithKeyLookup) { - const rootKeyDecrypted = await rootKeyDecryptWithKeyLookupUsecase.executeMany(usesRootKeyWithKeyLookup.items) + const rootKeyDecrypted = await this.decryptPayloads({ payloads: usesRootKeyWithKeyLookup.items }) extendArray(resultParams, rootKeyDecrypted) } if (usesKeySystemRootKey) { - const keySystemRootKeyDecrypted = await rootKeyDecryptUseCase.executeMany( - usesKeySystemRootKey.items, - usesKeySystemRootKey.key, - ) + const keySystemRootKeyDecrypted = await this.decryptPayloads({ + payloads: usesKeySystemRootKey.items, + key: usesKeySystemRootKey.key, + }) extendArray(resultParams, keySystemRootKeyDecrypted) } if (usesKeySystemRootKeyWithKeyLookup) { - const keySystemRootKeyDecrypted = await rootKeyDecryptWithKeyLookupUsecase.executeMany( - usesKeySystemRootKeyWithKeyLookup.items, - ) + const keySystemRootKeyDecrypted = await this.decryptPayloads({ + payloads: usesKeySystemRootKeyWithKeyLookup.items, + }) extendArray(resultParams, keySystemRootKeyDecrypted) } @@ -1026,4 +989,37 @@ export class EncryptionService void this.mutator.setItemsDirty(unsyncedKeys) } } + + private async encryptPayloads(dto: { + payloads: DecryptedPayloadInterface[] + key?: RootKeyInterface | KeySystemRootKeyInterface + signingKeyPair?: PkcKeyPair + }): Promise { + const encryptedPayloadsOrError = await this.encryptPayloadsUseCase.execute({ + ...dto, + fallbackRootKey: this.rootKeyManager.getRootKey(), + }) + if (encryptedPayloadsOrError.isFailed()) { + throw new Error(encryptedPayloadsOrError.getError()) + } + const encryptedPayloads = encryptedPayloadsOrError.getValue() + + return encryptedPayloads + } + + private async decryptPayloads(dto: { + payloads: EncryptedPayloadInterface[] + key?: RootKeyInterface | KeySystemRootKeyInterface + }): Promise<(DecryptedParameters | ErrorDecryptingParameters)[]> { + const decryptedPayloadsOrError = await this.decryptPayloadsUseCase.execute({ + ...dto, + fallbackRootKey: this.rootKeyManager.getRootKey(), + }) + if (decryptedPayloadsOrError.isFailed()) { + throw new Error(decryptedPayloadsOrError.getError()) + } + const decryptedPayloads = decryptedPayloadsOrError.getValue() + + return decryptedPayloads + } } diff --git a/packages/services/src/Domain/Encryption/RootKey/RootKeyManager.ts b/packages/services/src/Domain/Encryption/RootKey/RootKeyManager.ts index 3720cd027..b4a1b4a7f 100644 --- a/packages/services/src/Domain/Encryption/RootKey/RootKeyManager.ts +++ b/packages/services/src/Domain/Encryption/RootKey/RootKeyManager.ts @@ -16,28 +16,28 @@ import { import { ContentTypesUsingRootKeyEncryption, DecryptedPayload, - DecryptedTransferPayload, EncryptedPayload, EncryptedTransferPayload, - FillItemContentSpecialized, NamespacedRootKeyInKeychain, RootKeyContent, RootKeyInterface, RootKeyParamsInterface, + DecryptedTransferPayload, + FillItemContentSpecialized, } from '@standardnotes/models' import { DeviceInterface } from '../../Device/DeviceInterface' import { InternalEventBusInterface } from '../../Internal/InternalEventBusInterface' import { StorageKey } from '../../Storage/StorageKeys' import { StorageServiceInterface } from '../../Storage/StorageServiceInterface' import { StorageValueModes } from '../../Storage/StorageTypes' -import { RootKeyEncryptPayloadUseCase } from '../UseCase/RootEncryption/EncryptPayload' -import { RootKeyDecryptPayloadUseCase } from '../UseCase/RootEncryption/DecryptPayload' import { AbstractService } from '../../Service/AbstractService' import { ItemManagerInterface } from '../../Item/ItemManagerInterface' import { MutatorClientInterface } from '../../Mutator/MutatorClientInterface' import { RootKeyManagerEvent } from './RootKeyManagerEvent' import { ValidatePasscodeResult } from './ValidatePasscodeResult' import { ValidateAccountPasswordResult } from './ValidateAccountPasswordResult' +import { DecryptPayloads } from '../UseCase/DecryptPayloads/DecryptPayloads' +import { EncryptPayloads } from '../UseCase/EncryptPayloads/EncryptPayloads' export class RootKeyManager extends AbstractService { private rootKey?: RootKeyInterface @@ -51,6 +51,8 @@ export class RootKeyManager extends AbstractService { private mutator: MutatorClientInterface, private operators: OperatorManager, private identifier: ApplicationIdentifier, + private encryptPayloadsUseCase: EncryptPayloads, + private decryptPayloadsUseCase: DecryptPayloads, eventBus: InternalEventBusInterface, ) { super(eventBus) @@ -249,8 +251,16 @@ export class RootKeyManager extends AbstractService { const payload = new DecryptedPayload(value) - const usecase = new RootKeyEncryptPayloadUseCase(this.operators) - const wrappedKey = await usecase.executeOne(payload, wrappingKey) + const wrappedKeysOrError = await this.encryptPayloadsUseCase.execute({ + payloads: [payload], + key: wrappingKey, + fallbackRootKey: this.getRootKey(), + }) + if (wrappedKeysOrError.isFailed()) { + throw Error(wrappedKeysOrError.getError()) + } + const wrappedKey = wrappedKeysOrError.getValue()[0] + const wrappedKeyPayload = new EncryptedPayload({ ...payload.ejected(), ...wrappedKey, @@ -273,8 +283,15 @@ export class RootKeyManager extends AbstractService { const wrappedKey = this.getWrappedRootKey() const payload = new EncryptedPayload(wrappedKey) - const usecase = new RootKeyDecryptPayloadUseCase(this.operators) - const decrypted = await usecase.executeOne(payload, wrappingKey) + const decryptedPayloadsOrError = await this.decryptPayloadsUseCase.execute({ + payloads: [payload], + key: wrappingKey, + fallbackRootKey: this.getRootKey(), + }) + if (decryptedPayloadsOrError.isFailed()) { + throw Error(decryptedPayloadsOrError.getError()) + } + const decrypted = decryptedPayloadsOrError.getValue()[0] if (isErrorDecryptingParameters(decrypted)) { throw Error('Unable to decrypt root key with provided wrapping key.') @@ -433,8 +450,16 @@ export class RootKeyManager extends AbstractService { * by attempting to decrypt account keys. */ const wrappedKeyPayload = new EncryptedPayload(wrappedRootKey) - const usecase = new RootKeyDecryptPayloadUseCase(this.operators) - const decrypted = await usecase.executeOne(wrappedKeyPayload, wrappingKey) + const decryptedPayloadsOrError = await this.decryptPayloadsUseCase.execute({ + payloads: [wrappedKeyPayload], + key: wrappingKey, + fallbackRootKey: this.getRootKey(), + }) + if (decryptedPayloadsOrError.isFailed()) { + throw Error(decryptedPayloadsOrError.getError()) + } + const decrypted = decryptedPayloadsOrError.getValue()[0] + return !isErrorDecryptingParameters(decrypted) } else { throw 'Unhandled case in validateWrappingKey' diff --git a/packages/services/src/Domain/Encryption/UseCase/DecryptPayloads/DecryptPayloads.ts b/packages/services/src/Domain/Encryption/UseCase/DecryptPayloads/DecryptPayloads.ts new file mode 100644 index 000000000..b66a1dde5 --- /dev/null +++ b/packages/services/src/Domain/Encryption/UseCase/DecryptPayloads/DecryptPayloads.ts @@ -0,0 +1,73 @@ +import { + DecryptedParameters, + ErrorDecryptingParameters, + KeySystemKeyManagerInterface, + OperatorManager, + decryptPayload, +} from '@standardnotes/encryption' +import { Result, UseCaseInterface } from '@standardnotes/domain-core' +import { + ContentTypeUsesKeySystemRootKeyEncryption, + EncryptedPayloadInterface, + ItemContent, + KeySystemRootKeyInterface, + RootKeyInterface, +} from '@standardnotes/models' + +import { DecryptPayloadsDTO } from './DecryptPayloadsDTO' + +export class DecryptPayloads implements UseCaseInterface<(DecryptedParameters | ErrorDecryptingParameters)[]> { + constructor(private operatorManager: OperatorManager, private keySystemKeyManager: KeySystemKeyManagerInterface) {} + + async execute( + dto: DecryptPayloadsDTO, + ): Promise | ErrorDecryptingParameters)[]>> { + const decryptedOrErroredParameters = [] + for (const payload of dto.payloads) { + const keyForPayloadOrError = this.getKeyForPayload({ + payload, + existingKey: dto.key, + fallbackRootKey: dto.fallbackRootKey, + }) + if (keyForPayloadOrError.isFailed()) { + const errorDecryptingParamteres: ErrorDecryptingParameters = { + uuid: payload.uuid, + errorDecrypting: true, + waitingForKey: true, + } + decryptedOrErroredParameters.push(errorDecryptingParamteres) + + continue + } + const key = keyForPayloadOrError.getValue() + + decryptedOrErroredParameters.push(await decryptPayload(payload, key, this.operatorManager)) + } + + return Result.ok(decryptedOrErroredParameters) + } + + private getKeyForPayload(dto: { + payload: EncryptedPayloadInterface + existingKey?: RootKeyInterface | KeySystemRootKeyInterface + fallbackRootKey?: RootKeyInterface + }): Result { + let key = dto.existingKey + if (key === undefined) { + if (ContentTypeUsesKeySystemRootKeyEncryption(dto.payload.content_type)) { + if (!dto.payload.key_system_identifier) { + return Result.fail('Key system root key encrypted payload is missing key_system_identifier') + } + key = this.keySystemKeyManager.getPrimaryKeySystemRootKey(dto.payload.key_system_identifier) + } else { + key = dto.fallbackRootKey + } + } + + if (key === undefined) { + return Result.fail('Attempting root key decryption with no root key') + } + + return Result.ok(key) + } +} diff --git a/packages/services/src/Domain/Encryption/UseCase/DecryptPayloads/DecryptPayloadsDTO.ts b/packages/services/src/Domain/Encryption/UseCase/DecryptPayloads/DecryptPayloadsDTO.ts new file mode 100644 index 000000000..06e42a7ef --- /dev/null +++ b/packages/services/src/Domain/Encryption/UseCase/DecryptPayloads/DecryptPayloadsDTO.ts @@ -0,0 +1,7 @@ +import { EncryptedPayloadInterface, KeySystemRootKeyInterface, RootKeyInterface } from '@standardnotes/models' + +export interface DecryptPayloadsDTO { + payloads: EncryptedPayloadInterface[] + key?: RootKeyInterface | KeySystemRootKeyInterface + fallbackRootKey?: RootKeyInterface +} diff --git a/packages/services/src/Domain/Encryption/UseCase/EmitDecryptedErroredPayloads/EmitDecryptedErroredPayloads.ts b/packages/services/src/Domain/Encryption/UseCase/EmitDecryptedErroredPayloads/EmitDecryptedErroredPayloads.ts new file mode 100644 index 000000000..5e764fa61 --- /dev/null +++ b/packages/services/src/Domain/Encryption/UseCase/EmitDecryptedErroredPayloads/EmitDecryptedErroredPayloads.ts @@ -0,0 +1,55 @@ +import { + ContentTypeUsesKeySystemRootKeyEncryption, + ContentTypeUsesRootKeyEncryption, + DecryptedPayload, + EncryptedPayload, + PayloadEmitSource, + SureFindPayload, +} from '@standardnotes/models' +import { isErrorDecryptingParameters } from '@standardnotes/encryption' +import { UseCaseInterface, Result } from '@standardnotes/domain-core' + +import { PayloadManagerInterface } from '../../../Payloads/PayloadManagerInterface' + +import { DecryptPayloads } from '../DecryptPayloads/DecryptPayloads' + +export class EmitDecryptedErroredPayloads implements UseCaseInterface { + constructor(private payloadsManager: PayloadManagerInterface, private decryptPayloadsUseCase: DecryptPayloads) {} + + async execute(): Promise> { + const erroredRootPayloads = this.payloadsManager.invalidPayloads.filter( + (i) => + ContentTypeUsesRootKeyEncryption(i.content_type) || ContentTypeUsesKeySystemRootKeyEncryption(i.content_type), + ) + if (erroredRootPayloads.length === 0) { + return Result.fail('No errored payloads found') + } + + const decryptedPaylodsAndErrorsOrFail = await this.decryptPayloadsUseCase.execute({ + payloads: erroredRootPayloads, + }) + if (decryptedPaylodsAndErrorsOrFail.isFailed()) { + return Result.fail(decryptedPaylodsAndErrorsOrFail.getError()) + } + const decryptedPaylodsAndErrors = decryptedPaylodsAndErrorsOrFail.getValue() + + const decryptedPayloads = decryptedPaylodsAndErrors.map((params) => { + const original = SureFindPayload(erroredRootPayloads, params.uuid) + if (isErrorDecryptingParameters(params)) { + return new EncryptedPayload({ + ...original.ejected(), + ...params, + }) + } else { + return new DecryptedPayload({ + ...original.ejected(), + ...params, + }) + } + }) + + await this.payloadsManager.emitPayloads(decryptedPayloads, PayloadEmitSource.LocalChanged) + + return Result.ok() + } +} diff --git a/packages/services/src/Domain/Encryption/UseCase/EncryptPayloads/EncryptPayloads.ts b/packages/services/src/Domain/Encryption/UseCase/EncryptPayloads/EncryptPayloads.ts new file mode 100644 index 000000000..7e3471243 --- /dev/null +++ b/packages/services/src/Domain/Encryption/UseCase/EncryptPayloads/EncryptPayloads.ts @@ -0,0 +1,68 @@ +import { + EncryptedOutputParameters, + KeySystemKeyManagerInterface, + OperatorManager, + encryptPayload, +} from '@standardnotes/encryption' +import { Result, UseCaseInterface } from '@standardnotes/domain-core' +import { + ContentTypeUsesKeySystemRootKeyEncryption, + DecryptedPayloadInterface, + KeySystemRootKeyInterface, + RootKeyInterface, +} from '@standardnotes/models' + +import { EncryptPayloadsDTO } from './EncryptPayloadsDTO' + +export class EncryptPayloads implements UseCaseInterface { + constructor(private operatorManager: OperatorManager, private keySystemKeyManager: KeySystemKeyManagerInterface) {} + + async execute(dto: EncryptPayloadsDTO): Promise> { + try { + const encryptedPayloads = [] + for (const payload of dto.payloads) { + const keyForPayloadOrError = this.getKeyForPayload({ + payload, + existingKey: dto.key, + fallbackRootKey: dto.fallbackRootKey, + }) + if (keyForPayloadOrError.isFailed()) { + return Result.fail(keyForPayloadOrError.getError()) + } + const key = keyForPayloadOrError.getValue() + + encryptedPayloads.push(await encryptPayload(payload, key, this.operatorManager, dto.signingKeyPair)) + } + + return Result.ok(encryptedPayloads) + } catch (error) { + return Result.fail((error as Error).message) + } + } + + private getKeyForPayload(dto: { + payload: DecryptedPayloadInterface + existingKey?: RootKeyInterface | KeySystemRootKeyInterface + fallbackRootKey?: RootKeyInterface + }): Result { + let key = dto.existingKey + if (key === undefined) { + if (ContentTypeUsesKeySystemRootKeyEncryption(dto.payload.content_type)) { + if (!dto.payload.key_system_identifier) { + return Result.fail( + `Key system-encrypted payload ${dto.payload.content_type}is missing a key_system_identifier`, + ) + } + key = this.keySystemKeyManager.getPrimaryKeySystemRootKey(dto.payload.key_system_identifier) + } else { + key = dto.fallbackRootKey + } + } + + if (key === undefined) { + return Result.fail('Attempting root key encryption with no root key') + } + + return Result.ok(key) + } +} diff --git a/packages/services/src/Domain/Encryption/UseCase/EncryptPayloads/EncryptPayloadsDTO.ts b/packages/services/src/Domain/Encryption/UseCase/EncryptPayloads/EncryptPayloadsDTO.ts new file mode 100644 index 000000000..10f677c95 --- /dev/null +++ b/packages/services/src/Domain/Encryption/UseCase/EncryptPayloads/EncryptPayloadsDTO.ts @@ -0,0 +1,9 @@ +import { DecryptedPayloadInterface, KeySystemRootKeyInterface, RootKeyInterface } from '@standardnotes/models' +import { PkcKeyPair } from '@standardnotes/sncrypto-common' + +export interface EncryptPayloadsDTO { + payloads: DecryptedPayloadInterface[] + key?: RootKeyInterface | KeySystemRootKeyInterface + fallbackRootKey?: RootKeyInterface + signingKeyPair?: PkcKeyPair +} diff --git a/packages/services/src/Domain/Encryption/UseCase/RootEncryption/DecryptErroredPayloads.ts b/packages/services/src/Domain/Encryption/UseCase/RootEncryption/DecryptErroredPayloads.ts deleted file mode 100644 index ebfa9c93e..000000000 --- a/packages/services/src/Domain/Encryption/UseCase/RootEncryption/DecryptErroredPayloads.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { - ContentTypeUsesKeySystemRootKeyEncryption, - ContentTypeUsesRootKeyEncryption, - DecryptedPayload, - EncryptedPayload, - PayloadEmitSource, - SureFindPayload, -} from '@standardnotes/models' -import { PayloadManagerInterface } from './../../../Payloads/PayloadManagerInterface' -import { KeySystemKeyManagerInterface, OperatorManager, isErrorDecryptingParameters } from '@standardnotes/encryption' -import { RootKeyDecryptPayloadWithKeyLookupUseCase } from './DecryptPayloadWithKeyLookup' -import { RootKeyManager } from '../../RootKey/RootKeyManager' - -export class DecryptErroredRootPayloadsUseCase { - constructor( - private payloads: PayloadManagerInterface, - private operatorManager: OperatorManager, - private keySystemKeyManager: KeySystemKeyManagerInterface, - private rootKeyManager: RootKeyManager, - ) {} - - async execute(): Promise { - const erroredRootPayloads = this.payloads.invalidPayloads.filter( - (i) => - ContentTypeUsesRootKeyEncryption(i.content_type) || ContentTypeUsesKeySystemRootKeyEncryption(i.content_type), - ) - if (erroredRootPayloads.length === 0) { - return - } - - const usecase = new RootKeyDecryptPayloadWithKeyLookupUseCase( - this.operatorManager, - this.keySystemKeyManager, - this.rootKeyManager, - ) - const resultParams = await usecase.executeMany(erroredRootPayloads) - - const decryptedPayloads = resultParams.map((params) => { - const original = SureFindPayload(erroredRootPayloads, params.uuid) - if (isErrorDecryptingParameters(params)) { - return new EncryptedPayload({ - ...original.ejected(), - ...params, - }) - } else { - return new DecryptedPayload({ - ...original.ejected(), - ...params, - }) - } - }) - - await this.payloads.emitPayloads(decryptedPayloads, PayloadEmitSource.LocalChanged) - } -} diff --git a/packages/services/src/Domain/Encryption/UseCase/RootEncryption/DecryptPayload.ts b/packages/services/src/Domain/Encryption/UseCase/RootEncryption/DecryptPayload.ts deleted file mode 100644 index 18d84bac4..000000000 --- a/packages/services/src/Domain/Encryption/UseCase/RootEncryption/DecryptPayload.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { - DecryptedParameters, - ErrorDecryptingParameters, - OperatorManager, - decryptPayload, -} from '@standardnotes/encryption' -import { - EncryptedPayloadInterface, - ItemContent, - KeySystemRootKeyInterface, - RootKeyInterface, -} from '@standardnotes/models' - -export class RootKeyDecryptPayloadUseCase { - constructor(private operatorManager: OperatorManager) {} - - async executeOne( - payload: EncryptedPayloadInterface, - key: RootKeyInterface | KeySystemRootKeyInterface, - ): Promise | ErrorDecryptingParameters> { - return decryptPayload(payload, key, this.operatorManager) - } - - async executeMany( - payloads: EncryptedPayloadInterface[], - key: RootKeyInterface | KeySystemRootKeyInterface, - ): Promise<(DecryptedParameters | ErrorDecryptingParameters)[]> { - return Promise.all(payloads.map((payload) => this.executeOne(payload, key))) - } -} diff --git a/packages/services/src/Domain/Encryption/UseCase/RootEncryption/DecryptPayloadWithKeyLookup.ts b/packages/services/src/Domain/Encryption/UseCase/RootEncryption/DecryptPayloadWithKeyLookup.ts deleted file mode 100644 index 1611756cd..000000000 --- a/packages/services/src/Domain/Encryption/UseCase/RootEncryption/DecryptPayloadWithKeyLookup.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { - DecryptedParameters, - ErrorDecryptingParameters, - KeySystemKeyManagerInterface, - OperatorManager, -} from '@standardnotes/encryption' -import { - ContentTypeUsesKeySystemRootKeyEncryption, - EncryptedPayloadInterface, - ItemContent, - KeySystemRootKeyInterface, - RootKeyInterface, -} from '@standardnotes/models' - -import { RootKeyDecryptPayloadUseCase } from './DecryptPayload' -import { RootKeyManager } from '../../RootKey/RootKeyManager' - -export class RootKeyDecryptPayloadWithKeyLookupUseCase { - constructor( - private operatorManager: OperatorManager, - private keySystemKeyManager: KeySystemKeyManagerInterface, - private rootKeyManager: RootKeyManager, - ) {} - - async executeOne( - payload: EncryptedPayloadInterface, - ): Promise | ErrorDecryptingParameters> { - let key: RootKeyInterface | KeySystemRootKeyInterface | undefined - if (ContentTypeUsesKeySystemRootKeyEncryption(payload.content_type)) { - if (!payload.key_system_identifier) { - throw Error('Key system root key encrypted payload is missing key_system_identifier') - } - key = this.keySystemKeyManager.getPrimaryKeySystemRootKey(payload.key_system_identifier) - } else { - key = this.rootKeyManager.getRootKey() - } - - if (key == undefined) { - return { - uuid: payload.uuid, - errorDecrypting: true, - waitingForKey: true, - } - } - - const usecase = new RootKeyDecryptPayloadUseCase(this.operatorManager) - - return usecase.executeOne(payload, key) - } - - async executeMany( - payloads: EncryptedPayloadInterface[], - ): Promise<(DecryptedParameters | ErrorDecryptingParameters)[]> { - return Promise.all(payloads.map((payload) => this.executeOne(payload))) - } -} diff --git a/packages/services/src/Domain/Encryption/UseCase/RootEncryption/EncryptPayload.ts b/packages/services/src/Domain/Encryption/UseCase/RootEncryption/EncryptPayload.ts deleted file mode 100644 index 09a3453c9..000000000 --- a/packages/services/src/Domain/Encryption/UseCase/RootEncryption/EncryptPayload.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { EncryptedOutputParameters, OperatorManager, encryptPayload } from '@standardnotes/encryption' -import { DecryptedPayloadInterface, KeySystemRootKeyInterface, RootKeyInterface } from '@standardnotes/models' -import { PkcKeyPair } from '@standardnotes/sncrypto-common' - -export class RootKeyEncryptPayloadUseCase { - constructor(private operatorManager: OperatorManager) {} - - async executeOne( - payload: DecryptedPayloadInterface, - key: RootKeyInterface | KeySystemRootKeyInterface, - signingKeyPair?: PkcKeyPair, - ): Promise { - return encryptPayload(payload, key, this.operatorManager, signingKeyPair) - } - - async executeMany( - payloads: DecryptedPayloadInterface[], - key: RootKeyInterface | KeySystemRootKeyInterface, - signingKeyPair?: PkcKeyPair, - ): Promise { - return Promise.all(payloads.map((payload) => this.executeOne(payload, key, signingKeyPair))) - } -} diff --git a/packages/services/src/Domain/Encryption/UseCase/RootEncryption/EncryptPayloadWithKeyLookup.ts b/packages/services/src/Domain/Encryption/UseCase/RootEncryption/EncryptPayloadWithKeyLookup.ts deleted file mode 100644 index 1b693610e..000000000 --- a/packages/services/src/Domain/Encryption/UseCase/RootEncryption/EncryptPayloadWithKeyLookup.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { EncryptedOutputParameters, KeySystemKeyManagerInterface, OperatorManager } from '@standardnotes/encryption' -import { - ContentTypeUsesKeySystemRootKeyEncryption, - DecryptedPayloadInterface, - KeySystemRootKeyInterface, - RootKeyInterface, -} from '@standardnotes/models' -import { PkcKeyPair } from '@standardnotes/sncrypto-common' - -import { RootKeyEncryptPayloadUseCase } from './EncryptPayload' -import { RootKeyManager } from '../../RootKey/RootKeyManager' - -export class RootKeyEncryptPayloadWithKeyLookupUseCase { - constructor( - private operatorManager: OperatorManager, - private keySystemKeyManager: KeySystemKeyManagerInterface, - private rootKeyManager: RootKeyManager, - ) {} - - async executeOne( - payload: DecryptedPayloadInterface, - signingKeyPair?: PkcKeyPair, - ): Promise { - let key: RootKeyInterface | KeySystemRootKeyInterface | undefined - if (ContentTypeUsesKeySystemRootKeyEncryption(payload.content_type)) { - if (!payload.key_system_identifier) { - throw Error(`Key system-encrypted payload ${payload.content_type}is missing a key_system_identifier`) - } - key = this.keySystemKeyManager.getPrimaryKeySystemRootKey(payload.key_system_identifier) - } else { - key = this.rootKeyManager.getRootKey() - } - - if (key == undefined) { - throw Error('Attempting root key encryption with no root key') - } - - const usecase = new RootKeyEncryptPayloadUseCase(this.operatorManager) - return usecase.executeOne(payload, key, signingKeyPair) - } - - async executeMany( - payloads: DecryptedPayloadInterface[], - signingKeyPair?: PkcKeyPair, - ): Promise { - return Promise.all(payloads.map((payload) => this.executeOne(payload, signingKeyPair))) - } -} diff --git a/packages/services/src/Domain/SharedVaults/SharedVaultService.ts b/packages/services/src/Domain/SharedVaults/SharedVaultService.ts index 7bca6bfb0..ac7b57675 100644 --- a/packages/services/src/Domain/SharedVaults/SharedVaultService.ts +++ b/packages/services/src/Domain/SharedVaults/SharedVaultService.ts @@ -64,6 +64,7 @@ import { SendSharedVaultMetadataChangedMessageToAll } from './UseCase/SendShared import { ConvertToSharedVaultUseCase } from './UseCase/ConvertToSharedVault' import { GetVaultUseCase } from '../Vaults/UseCase/GetVault' import { ContentType } from '@standardnotes/domain-core' +import { EmitDecryptedErroredPayloads } from '../Encryption/UseCase/EmitDecryptedErroredPayloads/EmitDecryptedErroredPayloads' export class SharedVaultService extends AbstractService @@ -87,6 +88,7 @@ export class SharedVaultService private files: FilesClientInterface, private vaults: VaultServiceInterface, private storage: StorageServiceInterface, + private emitDecryptedErroredPayloadsUseCase: EmitDecryptedErroredPayloads, eventBus: InternalEventBusInterface, ) { super(eventBus) @@ -399,15 +401,14 @@ export class SharedVaultService void this.sync.sync() - await this.decryptErroredItemsAfterInviteAccept() + const emitedOrFailed = await this.emitDecryptedErroredPayloadsUseCase.execute() + if (emitedOrFailed.isFailed()) { + throw new Error(emitedOrFailed.getError()) + } await this.sync.syncSharedVaultsFromScratch([pendingInvite.invite.shared_vault_uuid]) } - private async decryptErroredItemsAfterInviteAccept(): Promise { - await this.encryption.decryptErroredPayloads() - } - public async getInvitableContactsForSharedVault( sharedVault: SharedVaultListingInterface, ): Promise { diff --git a/packages/services/src/Domain/User/UserService.ts b/packages/services/src/Domain/User/UserService.ts index 85a9bec72..5f2bdf819 100644 --- a/packages/services/src/Domain/User/UserService.ts +++ b/packages/services/src/Domain/User/UserService.ts @@ -36,6 +36,7 @@ import { AccountEventData } from './AccountEventData' import { AccountEvent } from './AccountEvent' import { SignedInOrRegisteredEventPayload } from './SignedInOrRegisteredEventPayload' import { CredentialsChangeFunctionResponse } from './CredentialsChangeFunctionResponse' +import { EmitDecryptedErroredPayloads } from '../Encryption/UseCase/EmitDecryptedErroredPayloads/EmitDecryptedErroredPayloads' export class UserService extends AbstractService @@ -57,6 +58,7 @@ export class UserService private challengeService: ChallengeServiceInterface, private protectionService: ProtectionsClientInterface, private userApiService: UserApiServiceInterface, + private emitDecryptedErroredPayloadsUseCase: EmitDecryptedErroredPayloads, protected override internalEventBus: InternalEventBusInterface, ) { super(internalEventBus) @@ -87,14 +89,14 @@ export class UserService }) .then(() => { if (!payload.awaitSync) { - void this.encryptionService.decryptErroredPayloads() + void this.emitDecryptedErroredPayloadsUseCase.execute() } }) if (payload.awaitSync) { await syncPromise - await this.encryptionService.decryptErroredPayloads() + await this.emitDecryptedErroredPayloadsUseCase.execute() } } } diff --git a/packages/services/src/Domain/Vaults/VaultService.ts b/packages/services/src/Domain/Vaults/VaultService.ts index b20dedf76..ed971e0b9 100644 --- a/packages/services/src/Domain/Vaults/VaultService.ts +++ b/packages/services/src/Domain/Vaults/VaultService.ts @@ -29,6 +29,7 @@ import { ChangeVaultKeyOptionsUseCase } from './UseCase/ChangeVaultKeyOptions' import { MutatorClientInterface } from '../Mutator/MutatorClientInterface' import { AlertService } from '../Alert/AlertService' import { ContentType } from '@standardnotes/domain-core' +import { EmitDecryptedErroredPayloads } from '../Encryption/UseCase/EmitDecryptedErroredPayloads/EmitDecryptedErroredPayloads' export class VaultService extends AbstractService @@ -43,6 +44,7 @@ export class VaultService private encryption: EncryptionProviderInterface, private files: FilesClientInterface, private alerts: AlertService, + private emitDecryptedErroredPayloadsUseCase: EmitDecryptedErroredPayloads, eventBus: InternalEventBusInterface, ) { super(eventBus) @@ -271,7 +273,10 @@ export class VaultService this.encryption.keys.intakeNonPersistentKeySystemRootKey(derivedRootKey, vault.keyStorageMode) - await this.encryption.decryptErroredPayloads() + const emitedOrFailed = await this.emitDecryptedErroredPayloadsUseCase.execute() + if (emitedOrFailed.isFailed()) { + throw emitedOrFailed.getError() + } if (this.computeVaultLockState(vault) === 'locked') { this.encryption.keys.undoIntakeNonPersistentKeySystemRootKey(vault.systemIdentifier) diff --git a/packages/services/src/Domain/index.ts b/packages/services/src/Domain/index.ts index c27a12ddb..872be1932 100644 --- a/packages/services/src/Domain/index.ts +++ b/packages/services/src/Domain/index.ts @@ -15,6 +15,7 @@ export * from './Application/DeinitSource' export * from './AsymmetricMessage/AsymmetricMessageService' export * from './AsymmetricMessage/AsymmetricMessageServiceInterface' +export * from './AsymmetricMessage/UseCase/HandleTrustedSharedVaultRootKeyChangedMessage' export * from './Auth/AuthClientInterface' export * from './Auth/AuthManager' @@ -68,6 +69,12 @@ export * from './Encryption/EncryptionService' export * from './Encryption/EncryptionServiceEvent' export * from './Encryption/Functions' export * from './Encryption/ItemsEncryption' +export * from './Encryption/RootKey/RootKeyManager' +export * from './Encryption/UseCase/DecryptPayloads/DecryptPayloads' +export * from './Encryption/UseCase/DecryptPayloads/DecryptPayloadsDTO' +export * from './Encryption/UseCase/EmitDecryptedErroredPayloads/EmitDecryptedErroredPayloads' +export * from './Encryption/UseCase/EncryptPayloads/EncryptPayloads' +export * from './Encryption/UseCase/EncryptPayloads/EncryptPayloadsDTO' export * from './Event/ApplicationEvent' export * from './Event/ApplicationEventCallback' diff --git a/packages/snjs/lib/Application/Application.ts b/packages/snjs/lib/Application/Application.ts index ddc38b5a5..2374f35b3 100644 --- a/packages/snjs/lib/Application/Application.ts +++ b/packages/snjs/lib/Application/Application.ts @@ -68,6 +68,11 @@ import { RevisionClientInterface, RevisionManager, ApiServiceEvent, + DecryptPayloads, + EncryptPayloads, + RootKeyManager, + HandleTrustedSharedVaultRootKeyChangedMessage, + EmitDecryptedErroredPayloads, } from '@standardnotes/services' import { BackupServiceInterface, @@ -75,7 +80,7 @@ import { FileBackupsDevice, FilesClientInterface, } from '@standardnotes/files' -import { ComputePrivateUsername } from '@standardnotes/encryption' +import { ComputePrivateUsername, OperatorManager } from '@standardnotes/encryption' import { useBoolean } from '@standardnotes/utils' import { BackupFile, @@ -189,6 +194,7 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli private declare authManager: AuthClientInterface private declare revisionManager: RevisionClientInterface private homeServerService?: ExternalServices.HomeServerService + private declare operatorManager: OperatorManager private declare _signInWithRecoveryCodes: SignInWithRecoveryCodes private declare _getRecoveryCodes: GetRecoveryCodes @@ -200,6 +206,9 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli private declare _listRevisions: ListRevisions private declare _getRevision: GetRevision private declare _deleteRevision: DeleteRevision + private declare _encryptPayloads: EncryptPayloads + private declare _decryptPayloads: DecryptPayloads + private declare _emitDecryptedErroredPayloads: EmitDecryptedErroredPayloads public internalEventBus!: ExternalServices.InternalEventBusInterface @@ -1308,6 +1317,7 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli ;(this.httpService as unknown) = undefined ;(this.payloadManager as unknown) = undefined ;(this.encryptionService as unknown) = undefined + ;(this.operatorManager as unknown) = undefined ;(this.diskStorageService as unknown) = undefined ;(this.inMemoryStore as unknown) = undefined ;(this.apiService as unknown) = undefined @@ -1356,6 +1366,9 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli ;(this._listRevisions as unknown) = undefined ;(this._getRevision as unknown) = undefined ;(this._deleteRevision as unknown) = undefined + ;(this._encryptPayloads as unknown) = undefined + ;(this._decryptPayloads as unknown) = undefined + ;(this._emitDecryptedErroredPayloads as unknown) = undefined ;(this.vaultService as unknown) = undefined ;(this.contactService as unknown) = undefined ;(this.sharedVaultService as unknown) = undefined @@ -1389,13 +1402,20 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli } private createAsymmetricMessageService() { + const handleTrustedSharedVaultRootKeyChangedMessageUseCase = new HandleTrustedSharedVaultRootKeyChangedMessage( + this.mutator, + this.itemManager, + this.syncService, + this._emitDecryptedErroredPayloads, + ) + this.asymmetricMessageService = new ExternalServices.AsymmetricMessageService( this.httpService, this.encryptionService, this.contacts, this.itemManager, this.mutator, - this.syncService, + handleTrustedSharedVaultRootKeyChangedMessageUseCase, this.internalEventBus, ) this.services.push(this.asymmetricMessageService) @@ -1429,6 +1449,7 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli this.files, this.vaults, this.storage, + this._emitDecryptedErroredPayloads, this.internalEventBus, ) this.services.push(this.sharedVaultService) @@ -1442,6 +1463,7 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli this.encryptionService, this.files, this.alertService, + this._emitDecryptedErroredPayloads, this.internalEventBus, ) @@ -1573,6 +1595,7 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli this.challengeService, this.protectionService, this.userApiService, + this._emitDecryptedErroredPayloads, this.internalEventBus, ) this.serviceObservers.push( @@ -1727,6 +1750,26 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli } private createProtocolService() { + this.operatorManager = new OperatorManager(this.options.crypto) + + this._decryptPayloads = new DecryptPayloads(this.operatorManager, this.keySystemKeyManager) + + this._encryptPayloads = new EncryptPayloads(this.operatorManager, this.keySystemKeyManager) + + this._emitDecryptedErroredPayloads = new EmitDecryptedErroredPayloads(this.payloadManager, this._decryptPayloads) + + const rootKeyManager = new RootKeyManager( + this.deviceInterface, + this.diskStorageService, + this.itemManager, + this.mutator, + this.operatorManager, + this.identifier, + this._encryptPayloads, + this._decryptPayloads, + this.internalEventBus, + ) + this.encryptionService = new EncryptionService( this.itemManager, this.mutator, @@ -1734,8 +1777,11 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli this.deviceInterface, this.diskStorageService, this.keySystemKeyManager, + rootKeyManager, this.identifier, - this.options.crypto, + this._encryptPayloads, + this._decryptPayloads, + this.operatorManager, this.internalEventBus, ) this.serviceObservers.push( @@ -1788,6 +1834,7 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli this.sessionStorageMapper, this.legacySessionStorageMapper, this.identifier, + this.options.crypto, this.internalEventBus, ) this.serviceObservers.push( diff --git a/packages/snjs/lib/Services/Session/SessionManager.ts b/packages/snjs/lib/Services/Session/SessionManager.ts index ac397124d..069accd5d 100644 --- a/packages/snjs/lib/Services/Session/SessionManager.ts +++ b/packages/snjs/lib/Services/Session/SessionManager.ts @@ -65,6 +65,7 @@ import { UserApiServiceInterface, UserRegistrationResponseBody, } from '@standardnotes/api' +import { PureCryptoInterface } from '@standardnotes/sncrypto-common' export const MINIMUM_PASSWORD_LENGTH = 8 export const MissingAccountParams = 'missing-params' @@ -98,6 +99,7 @@ export class SNSessionManager private sessionStorageMapper: MapperInterface>, private legacySessionStorageMapper: MapperInterface>, private workspaceIdentifier: string, + private crypto: PureCryptoInterface, protected override internalEventBus: InternalEventBusInterface, ) { super(internalEventBus) @@ -694,7 +696,7 @@ export class SNSessionManager } private decodeDemoShareToken(token: Base64String): ShareToken { - const jsonString = this.encryptionService.crypto.base64Decode(token) + const jsonString = this.crypto.base64Decode(token) return JSON.parse(jsonString) }