From 8ea2b9117ea160c273a7d6f634e3b4272748d96f Mon Sep 17 00:00:00 2001 From: Teo Gebhard Date: Thu, 21 Nov 2024 14:07:04 +0200 Subject: [PATCH 1/3] StreamrClientError cause parameter, update lib to "es2022" --- packages/sdk/src/StreamrClientError.ts | 5 +++-- packages/sdk/tsconfig.jest.json | 2 +- packages/sdk/tsconfig.node.json | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/sdk/src/StreamrClientError.ts b/packages/sdk/src/StreamrClientError.ts index d4efbf9215..862a34e52c 100644 --- a/packages/sdk/src/StreamrClientError.ts +++ b/packages/sdk/src/StreamrClientError.ts @@ -15,8 +15,9 @@ export class StreamrClientError extends Error { public readonly code: StreamrClientErrorCode - constructor(message: string, code: StreamrClientErrorCode) { - super(message) + // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types + constructor(message: string, code: StreamrClientErrorCode, cause?: any) { + super(message, cause !== undefined ? { cause } : undefined) this.code = code this.name = this.constructor.name } diff --git a/packages/sdk/tsconfig.jest.json b/packages/sdk/tsconfig.jest.json index 9f049c0960..a6cdd30069 100644 --- a/packages/sdk/tsconfig.jest.json +++ b/packages/sdk/tsconfig.jest.json @@ -2,7 +2,7 @@ "extends": "../../tsconfig.jest.json", "compilerOptions": { "noEmit": true, - "lib": ["es2021", "dom"], + "lib": ["es2022", "dom"], "experimentalDecorators": true, "emitDecoratorMetadata": true, "resolveJsonModule": true, diff --git a/packages/sdk/tsconfig.node.json b/packages/sdk/tsconfig.node.json index 2294ce2e0b..77bac31afe 100644 --- a/packages/sdk/tsconfig.node.json +++ b/packages/sdk/tsconfig.node.json @@ -3,7 +3,7 @@ "compilerOptions": { "outDir": "dist", "declarationDir": "dist/types", - "lib": ["es2021", "dom"], + "lib": ["es2022", "dom"], "experimentalDecorators": true, "emitDecoratorMetadata": true, "resolveJsonModule": true, From 76c798204b79144bbbbe501a892344ced24236c1 Mon Sep 17 00:00:00 2001 From: Teo Gebhard Date: Thu, 21 Nov 2024 14:07:50 +0200 Subject: [PATCH 2/3] replace DecryptError with StreamrClientError --- packages/sdk/src/StreamrClientError.ts | 7 +++++++ packages/sdk/src/encryption/EncryptionUtil.ts | 13 +++++-------- packages/sdk/src/encryption/decrypt.ts | 5 ++--- .../integration/resend-with-existing-key.test.ts | 5 +++-- .../sdk/test/integration/revoke-permissions.test.ts | 2 +- .../test/integration/update-encryption-key.test.ts | 5 +++-- packages/sdk/test/unit/Decrypt.test.ts | 6 +++++- packages/sdk/test/unit/EncryptionUtil.test.ts | 6 +++++- packages/sdk/test/unit/messagePipeline.test.ts | 8 +++++--- 9 files changed, 36 insertions(+), 21 deletions(-) diff --git a/packages/sdk/src/StreamrClientError.ts b/packages/sdk/src/StreamrClientError.ts index 862a34e52c..3f71c80f55 100644 --- a/packages/sdk/src/StreamrClientError.ts +++ b/packages/sdk/src/StreamrClientError.ts @@ -1,3 +1,5 @@ +import { MessageID } from './protocol/MessageID' + export type StreamrClientErrorCode = 'STREAM_NOT_FOUND' | 'NODE_NOT_FOUND' | @@ -8,6 +10,7 @@ export type StreamrClientErrorCode = 'PIPELINE_ERROR' | 'UNSUPPORTED_OPERATION' | 'INVALID_STREAM_METADATA' | + 'DECRYPT_ERROR' | 'STORAGE_NODE_ERROR' | 'UNKNOWN_ERROR' @@ -22,3 +25,7 @@ export class StreamrClientError extends Error { this.name = this.constructor.name } } + +export const formMessageIdDescription = (messageId: MessageID): string => { + return JSON.stringify(messageId) +} diff --git a/packages/sdk/src/encryption/EncryptionUtil.ts b/packages/sdk/src/encryption/EncryptionUtil.ts index 0028c486fe..6d1569e2c4 100644 --- a/packages/sdk/src/encryption/EncryptionUtil.ts +++ b/packages/sdk/src/encryption/EncryptionUtil.ts @@ -1,12 +1,10 @@ import crypto, { CipherKey } from 'crypto' import { StreamMessage, StreamMessageAESEncrypted } from '../protocol/StreamMessage' -import { StreamMessageError } from '../protocol/StreamMessageError' import { GroupKey } from './GroupKey' +import { formMessageIdDescription, StreamrClientError } from '../StreamrClientError' -export class DecryptError extends StreamMessageError { - constructor(streamMessage: StreamMessage, message = '') { - super(`Decrypt error: ${message}`, streamMessage) - } +export const createDecryptError = (message: string, streamMessage: StreamMessage, cause?: Error): StreamrClientError => { + return new StreamrClientError(`${message} (messageId=${formMessageIdDescription(streamMessage.messageId)})`, 'DECRYPT_ERROR', cause) } export const INITIALIZATION_VECTOR_LENGTH = 16 @@ -54,7 +52,7 @@ export class EncryptionUtil { try { content = this.decryptWithAES(streamMessage.content, groupKey.data) } catch (err) { - throw new DecryptError(streamMessage, err.stack) + throw createDecryptError('AES decryption failed', streamMessage, err) } let newGroupKey: GroupKey | undefined = undefined @@ -62,8 +60,7 @@ export class EncryptionUtil { try { newGroupKey = groupKey.decryptNextGroupKey(streamMessage.newGroupKey) } catch (err) { - // eslint-disable-next-line @typescript-eslint/restrict-template-expressions - throw new DecryptError(streamMessage, `Could not decrypt new group key: ${err.stack}`) + throw createDecryptError('Could not decrypt new encryption key', streamMessage, err) } } diff --git a/packages/sdk/src/encryption/decrypt.ts b/packages/sdk/src/encryption/decrypt.ts index 4fe447dd18..6ee56cfa18 100644 --- a/packages/sdk/src/encryption/decrypt.ts +++ b/packages/sdk/src/encryption/decrypt.ts @@ -1,5 +1,5 @@ import { DestroySignal } from '../DestroySignal' -import { DecryptError, EncryptionUtil } from '../encryption/EncryptionUtil' +import { createDecryptError, EncryptionUtil } from '../encryption/EncryptionUtil' import { GroupKey } from '../encryption/GroupKey' import { GroupKeyManager } from '../encryption/GroupKeyManager' import { EncryptionType, StreamMessage, StreamMessageAESEncrypted } from '../protocol/StreamMessage' @@ -26,8 +26,7 @@ export const decrypt = async ( if (destroySignal.isDestroyed()) { return streamMessage } - // eslint-disable-next-line @typescript-eslint/restrict-template-expressions - throw new DecryptError(streamMessage, `Could not get GroupKey ${streamMessage.groupKeyId}: ${e.message}`) + throw createDecryptError(`Could not get encryption key ${streamMessage.groupKeyId}`, streamMessage, e) } if (destroySignal.isDestroyed()) { return streamMessage diff --git a/packages/sdk/test/integration/resend-with-existing-key.test.ts b/packages/sdk/test/integration/resend-with-existing-key.test.ts index e773378e27..dfb3b0dcb2 100644 --- a/packages/sdk/test/integration/resend-with-existing-key.test.ts +++ b/packages/sdk/test/integration/resend-with-existing-key.test.ts @@ -4,12 +4,12 @@ import { fastWallet } from '@streamr/test-utils' import { collect, toEthereumAddress, toStreamID, toUserId } from '@streamr/utils' import { Stream } from '../../src/Stream' import { StreamrClient } from '../../src/StreamrClient' -import { DecryptError } from '../../src/encryption/EncryptionUtil' import { GroupKey } from '../../src/encryption/GroupKey' import { StreamPermission } from '../../src/permission' import { FakeEnvironment } from '../test-utils/fake/FakeEnvironment' import { FakeStorageNode } from '../test-utils/fake/FakeStorageNode' import { createMockMessage, createRelativeTestStreamId, getLocalGroupKeyStore } from '../test-utils/utils' +import { StreamrClientError } from '../../src/StreamrClientError' /* * A subscriber has some GroupKeys in the local store and reads historical data @@ -68,7 +68,8 @@ describe('resend with existing key', () => { await collect(messageStream) expect(onError).toBeCalled() const error = onError.mock.calls[0][0] - expect(error).toBeInstanceOf(DecryptError) + expect(error).toBeInstanceOf(StreamrClientError) + expect(error.code).toBe('DECRYPT_ERROR') } beforeEach(async () => { diff --git a/packages/sdk/test/integration/revoke-permissions.test.ts b/packages/sdk/test/integration/revoke-permissions.test.ts index a751774d60..ceeb32a26c 100644 --- a/packages/sdk/test/integration/revoke-permissions.test.ts +++ b/packages/sdk/test/integration/revoke-permissions.test.ts @@ -159,7 +159,7 @@ describe('revoke permissions', () => { break } } - }).rejects.toThrow(/not a subscriber|Could not get GroupKey/) + }).rejects.toThrow(/not a subscriber|Could not get encryption key/) } finally { clearTimeout(t) // run in finally to ensure publish promise finishes before diff --git a/packages/sdk/test/integration/update-encryption-key.test.ts b/packages/sdk/test/integration/update-encryption-key.test.ts index c7e3c89609..e1be54495a 100644 --- a/packages/sdk/test/integration/update-encryption-key.test.ts +++ b/packages/sdk/test/integration/update-encryption-key.test.ts @@ -2,12 +2,12 @@ import 'reflect-metadata' import { StreamPartID, StreamPartIDUtils, until } from '@streamr/utils' import { Message } from '../../src/Message' -import { DecryptError } from '../../src/encryption/EncryptionUtil' import { GroupKey } from '../../src/encryption/GroupKey' import { StreamPermission } from '../../src/permission' import { nextValue } from '../../src/utils/iterators' import { StreamrClient } from './../../src/StreamrClient' import { FakeEnvironment } from './../test-utils/fake/FakeEnvironment' +import { StreamrClientError } from '../../src/StreamrClientError' /* * Subscriber has subscribed to a stream, and the publisher updates the encryption key for that stream. @@ -161,7 +161,8 @@ describe('update encryption key', () => { mockId: 2 }) await until(() => onError.mock.calls.length > 0, 10 * 1000) - expect(onError.mock.calls[0][0]).toBeInstanceOf(DecryptError) + expect(onError.mock.calls[0][0]).toBeInstanceOf(StreamrClientError) + expect(onError.mock.calls[0][0].code).toBe('DECRYPT_ERROR') }, 10 * 1000) }) }) diff --git a/packages/sdk/test/unit/Decrypt.test.ts b/packages/sdk/test/unit/Decrypt.test.ts index b516041d4e..21001b9ed1 100644 --- a/packages/sdk/test/unit/Decrypt.test.ts +++ b/packages/sdk/test/unit/Decrypt.test.ts @@ -10,6 +10,7 @@ import { GroupKeyManager } from '../../src/encryption/GroupKeyManager' import { decrypt } from '../../src/encryption/decrypt' import { createGroupKeyManager, createMockMessage } from '../test-utils/utils' import { EncryptionType, StreamMessage, StreamMessageAESEncrypted } from './../../src/protocol/StreamMessage' +import { formMessageIdDescription } from '../../src/StreamrClientError' describe('Decrypt', () => { @@ -54,6 +55,9 @@ describe('Decrypt', () => { msg as StreamMessageAESEncrypted, groupKeyManager, destroySignal) - }).rejects.toThrow(`Decrypt error: Could not get GroupKey ${groupKey.id}`) + }).rejects.toThrowStreamrError({ + code: 'DECRYPT_ERROR', + message: `Could not get encryption key ${groupKey.id} (messageId=${formMessageIdDescription(msg.messageId)})` + }) }) }) diff --git a/packages/sdk/test/unit/EncryptionUtil.test.ts b/packages/sdk/test/unit/EncryptionUtil.test.ts index c1b3838bb6..4c50209575 100644 --- a/packages/sdk/test/unit/EncryptionUtil.test.ts +++ b/packages/sdk/test/unit/EncryptionUtil.test.ts @@ -5,6 +5,7 @@ import { GroupKey } from '../../src/encryption/GroupKey' import { createMockMessage } from '../test-utils/utils' import { EncryptedGroupKey } from './../../src/protocol/EncryptedGroupKey' import { StreamMessage, StreamMessageAESEncrypted } from './../../src/protocol/StreamMessage' +import { formMessageIdDescription } from '../../src/StreamrClientError' const STREAM_ID = toStreamID('streamId') @@ -61,6 +62,9 @@ describe('EncryptionUtil', () => { ...msg, newGroupKey: new EncryptedGroupKey('mockId', hexToBinary('0x1234')) }) as StreamMessageAESEncrypted - expect(() => EncryptionUtil.decryptStreamMessage(msg2, key)).toThrow('Could not decrypt new group key') + expect(() => EncryptionUtil.decryptStreamMessage(msg2, key)).toThrowStreamrError({ + code: 'DECRYPT_ERROR', + message: `Could not decrypt new encryption key (messageId=${formMessageIdDescription(msg2.messageId)})` + }) }) }) diff --git a/packages/sdk/test/unit/messagePipeline.test.ts b/packages/sdk/test/unit/messagePipeline.test.ts index f3cd1bcbea..6aa5b24d3a 100644 --- a/packages/sdk/test/unit/messagePipeline.test.ts +++ b/packages/sdk/test/unit/messagePipeline.test.ts @@ -9,7 +9,7 @@ import { StrictStreamrClientConfig } from '../../src/Config' import { DestroySignal } from '../../src/DestroySignal' import { ERC1271ContractFacade } from '../../src/contracts/ERC1271ContractFacade' import { StreamRegistry } from '../../src/contracts/StreamRegistry' -import { DecryptError, EncryptionUtil } from '../../src/encryption/EncryptionUtil' +import { EncryptionUtil } from '../../src/encryption/EncryptionUtil' import { GroupKey } from '../../src/encryption/GroupKey' import { GroupKeyManager } from '../../src/encryption/GroupKeyManager' import { LitProtocolFacade } from '../../src/encryption/LitProtocolFacade' @@ -22,6 +22,7 @@ import { PushPipeline } from '../../src/utils/PushPipeline' import { mockLoggerFactory } from '../test-utils/utils' import { MessageID } from './../../src/protocol/MessageID' import { ContentType, EncryptionType, SignatureType, StreamMessage, StreamMessageType } from './../../src/protocol/StreamMessage' +import { StreamrClientError } from '../../src/StreamrClientError' const CONTENT = { foo: 'bar' @@ -168,8 +169,9 @@ describe('messagePipeline', () => { const output = await collect(pipeline) expect(onError).toBeCalledTimes(1) const error = onError.mock.calls[0][0] - expect(error).toBeInstanceOf(DecryptError) - expect(error.message).toMatch(/timed out/) + expect(error).toBeInstanceOf(StreamrClientError) + expect(error.code).toBe('DECRYPT_ERROR') + expect(error.message).toMatch(/Could not get encryption key/) expect(output).toEqual([]) expect(streamRegistry.invalidatePermissionCaches).toBeCalledTimes(1) expect(streamRegistry.invalidatePermissionCaches).toBeCalledWith(StreamPartIDUtils.getStreamID(streamPartId)) From 298b8230a27e38dffdeee1c1de7268a44caa6788 Mon Sep 17 00:00:00 2001 From: Teo Gebhard Date: Mon, 25 Nov 2024 15:09:17 +0200 Subject: [PATCH 3/3] remove cause parameter --- packages/sdk/src/StreamrClientError.ts | 5 ++--- packages/sdk/src/encryption/EncryptionUtil.ts | 12 ++++++------ packages/sdk/src/encryption/decrypt.ts | 4 ++-- packages/sdk/tsconfig.jest.json | 2 +- packages/sdk/tsconfig.node.json | 2 +- 5 files changed, 12 insertions(+), 13 deletions(-) diff --git a/packages/sdk/src/StreamrClientError.ts b/packages/sdk/src/StreamrClientError.ts index 3f71c80f55..2f02226b55 100644 --- a/packages/sdk/src/StreamrClientError.ts +++ b/packages/sdk/src/StreamrClientError.ts @@ -18,9 +18,8 @@ export class StreamrClientError extends Error { public readonly code: StreamrClientErrorCode - // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types - constructor(message: string, code: StreamrClientErrorCode, cause?: any) { - super(message, cause !== undefined ? { cause } : undefined) + constructor(message: string, code: StreamrClientErrorCode) { + super(message) this.code = code this.name = this.constructor.name } diff --git a/packages/sdk/src/encryption/EncryptionUtil.ts b/packages/sdk/src/encryption/EncryptionUtil.ts index 6d1569e2c4..ae71b0f976 100644 --- a/packages/sdk/src/encryption/EncryptionUtil.ts +++ b/packages/sdk/src/encryption/EncryptionUtil.ts @@ -3,8 +3,8 @@ import { StreamMessage, StreamMessageAESEncrypted } from '../protocol/StreamMess import { GroupKey } from './GroupKey' import { formMessageIdDescription, StreamrClientError } from '../StreamrClientError' -export const createDecryptError = (message: string, streamMessage: StreamMessage, cause?: Error): StreamrClientError => { - return new StreamrClientError(`${message} (messageId=${formMessageIdDescription(streamMessage.messageId)})`, 'DECRYPT_ERROR', cause) +export const createDecryptError = (message: string, streamMessage: StreamMessage): StreamrClientError => { + return new StreamrClientError(`${message} (messageId=${formMessageIdDescription(streamMessage.messageId)})`, 'DECRYPT_ERROR') } export const INITIALIZATION_VECTOR_LENGTH = 16 @@ -51,16 +51,16 @@ export class EncryptionUtil { let content: Uint8Array try { content = this.decryptWithAES(streamMessage.content, groupKey.data) - } catch (err) { - throw createDecryptError('AES decryption failed', streamMessage, err) + } catch { + throw createDecryptError('AES decryption failed', streamMessage) } let newGroupKey: GroupKey | undefined = undefined if (streamMessage.newGroupKey) { try { newGroupKey = groupKey.decryptNextGroupKey(streamMessage.newGroupKey) - } catch (err) { - throw createDecryptError('Could not decrypt new encryption key', streamMessage, err) + } catch { + throw createDecryptError('Could not decrypt new encryption key', streamMessage) } } diff --git a/packages/sdk/src/encryption/decrypt.ts b/packages/sdk/src/encryption/decrypt.ts index 6ee56cfa18..2221c5364b 100644 --- a/packages/sdk/src/encryption/decrypt.ts +++ b/packages/sdk/src/encryption/decrypt.ts @@ -22,11 +22,11 @@ export const decrypt = async ( streamMessage.groupKeyId, streamMessage.getPublisherId() ) - } catch (e: any) { + } catch { if (destroySignal.isDestroyed()) { return streamMessage } - throw createDecryptError(`Could not get encryption key ${streamMessage.groupKeyId}`, streamMessage, e) + throw createDecryptError(`Could not get encryption key ${streamMessage.groupKeyId}`, streamMessage) } if (destroySignal.isDestroyed()) { return streamMessage diff --git a/packages/sdk/tsconfig.jest.json b/packages/sdk/tsconfig.jest.json index a6cdd30069..9f049c0960 100644 --- a/packages/sdk/tsconfig.jest.json +++ b/packages/sdk/tsconfig.jest.json @@ -2,7 +2,7 @@ "extends": "../../tsconfig.jest.json", "compilerOptions": { "noEmit": true, - "lib": ["es2022", "dom"], + "lib": ["es2021", "dom"], "experimentalDecorators": true, "emitDecoratorMetadata": true, "resolveJsonModule": true, diff --git a/packages/sdk/tsconfig.node.json b/packages/sdk/tsconfig.node.json index 77bac31afe..2294ce2e0b 100644 --- a/packages/sdk/tsconfig.node.json +++ b/packages/sdk/tsconfig.node.json @@ -3,7 +3,7 @@ "compilerOptions": { "outDir": "dist", "declarationDir": "dist/types", - "lib": ["es2022", "dom"], + "lib": ["es2021", "dom"], "experimentalDecorators": true, "emitDecoratorMetadata": true, "resolveJsonModule": true,