diff --git a/package-lock.json b/package-lock.json index 2c8f683e82..fb98f8251c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11009,6 +11009,12 @@ "node": ">= 0.8" } }, + "node_modules/comlink": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/comlink/-/comlink-4.4.2.tgz", + "integrity": "sha512-OxGdvBmJuNKSCMO4NTl1L47VRp6xn2wG4F/2hYzB6tiCb709otOxtEYCSvK80PtjODfXXZu8ds+Nw5kVCjqd2g==", + "license": "Apache-2.0" + }, "node_modules/commander": { "version": "14.0.2", "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.2.tgz", @@ -27192,6 +27198,12 @@ "dev": true, "license": "MIT" }, + "node_modules/web-worker": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/web-worker/-/web-worker-1.5.0.tgz", + "integrity": "sha512-RiMReJrTAiA+mBjGONMnjVDP2u3p9R1vkcGz6gDIrOMT3oGuYwX2WRMYI9ipkphSuE5XKEhydbhNEJh4NY9mlw==", + "license": "Apache-2.0" + }, "node_modules/webidl-conversions": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", @@ -28924,6 +28936,7 @@ "@streamr/proto-rpc": "103.3.0", "@streamr/trackerless-network": "103.3.0", "@streamr/utils": "103.3.0", + "comlink": "^4.4.2", "env-paths": "^2.2.1", "ethers": "^6.13.0", "eventemitter3": "^5.0.0", @@ -28942,6 +28955,7 @@ "ts-toolbelt": "^9.6.0", "tsyringe": "^4.10.0", "uuid": "^11.1.0", + "web-worker": "^1.5.0", "zod": "^4.1.13" }, "devDependencies": { diff --git a/packages/browser-test-runner/src/createKarmaConfig.ts b/packages/browser-test-runner/src/createKarmaConfig.ts index b38a4ea05c..3f826cc4a1 100644 --- a/packages/browser-test-runner/src/createKarmaConfig.ts +++ b/packages/browser-test-runner/src/createKarmaConfig.ts @@ -4,8 +4,16 @@ import type { Configuration, ExternalItem } from 'webpack' const DEBUG_MODE = process.env.BROWSER_TEST_DEBUG_MODE ?? false +export interface KarmaConfigOptions { + // File patterns to serve but not include in the test bundle (e.g. worker files) + servedFiles?: string[] +} + export const createKarmaConfig = ( - testPaths: string[], webpackConfig: () => Configuration, localDirectory?: string + testPaths: string[], + webpackConfig: () => Configuration, + localDirectory?: string, + options: KarmaConfigOptions = {} ): (config: any) => any => { const setupFiles = [fileURLToPath(new URL('./karma-setup.js', import.meta.url))] @@ -57,7 +65,13 @@ export const createKarmaConfig = ( reporters: ['spec'], files: [ ...setupFiles, - ...testPaths + ...testPaths, + ...(options.servedFiles ?? []).map((pattern) => ({ + pattern, + included: false, + served: true, + watched: false + })) ], preprocessors, customLaunchers: { diff --git a/packages/browser-test-runner/src/exports.ts b/packages/browser-test-runner/src/exports.ts index da76c5cee4..e04593074b 100644 --- a/packages/browser-test-runner/src/exports.ts +++ b/packages/browser-test-runner/src/exports.ts @@ -1,2 +1,3 @@ export { createKarmaConfig } from './createKarmaConfig' +export type { KarmaConfigOptions } from './createKarmaConfig' export { createWebpackConfig } from './createWebpackConfig' diff --git a/packages/cli-tools/src/command.ts b/packages/cli-tools/src/command.ts index 30f49ad10f..3f34ec5ad7 100644 --- a/packages/cli-tools/src/command.ts +++ b/packages/cli-tools/src/command.ts @@ -53,6 +53,8 @@ export const createClientCommand = ( await client.destroy() } } + // Exit cleanly after command completes - worker threads may keep event loop alive + process.exit(0) } catch (e: any) { console.error(e) process.exit(1) diff --git a/packages/cli-tools/src/resend.ts b/packages/cli-tools/src/resend.ts index c05cd62d62..09bab29cd0 100644 --- a/packages/cli-tools/src/resend.ts +++ b/packages/cli-tools/src/resend.ts @@ -19,16 +19,19 @@ export const resend = async ( subscribe: boolean ): Promise => { try { - const handler = (message: any) => { - console.info(JSON.stringify(message)) - } if (subscribe) { + const handler = (message: any) => { + console.info(JSON.stringify(message)) + } await client.subscribe({ stream: streamId, resend: resendOpts }, handler) } else { - await client.resend(streamId, resendOpts, handler) + const messageStream = await client.resend(streamId, resendOpts) + for await (const message of messageStream) { + console.info(JSON.stringify(message.content)) + } } } catch (err) { console.error(err.message ?? err) diff --git a/packages/sdk/createKarmaConfig.ts b/packages/sdk/createKarmaConfig.ts index 8c0769f11e..a1adab036e 100644 --- a/packages/sdk/createKarmaConfig.ts +++ b/packages/sdk/createKarmaConfig.ts @@ -15,6 +15,7 @@ export function createKarmaConfig(testPaths: string[]): ReturnType/src/_jest/createSignatureValidationWorker.ts", "^@/(.*)$": "/src/_nodejs/$1", }, transform: { diff --git a/packages/sdk/package.json b/packages/sdk/package.json index e4d4cd4222..9391a42aff 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -31,6 +31,7 @@ "dist/exports-browser.*", "dist/exports-umd.*", "dist/encryption/migrations", + "dist/workers", "!*.tsbuildinfo", "LICENSE", "README.md", @@ -94,6 +95,7 @@ "@streamr/proto-rpc": "103.3.0", "@streamr/trackerless-network": "103.3.0", "@streamr/utils": "103.3.0", + "comlink": "^4.4.2", "env-paths": "^2.2.1", "ethers": "^6.13.0", "eventemitter3": "^5.0.0", @@ -112,6 +114,7 @@ "ts-toolbelt": "^9.6.0", "tsyringe": "^4.10.0", "uuid": "^11.1.0", + "web-worker": "^1.5.0", "zod": "^4.1.13" }, "optionalDependencies": { diff --git a/packages/sdk/rollup.config.mts b/packages/sdk/rollup.config.mts index 183eb3fca3..db9527580a 100644 --- a/packages/sdk/rollup.config.mts +++ b/packages/sdk/rollup.config.mts @@ -29,6 +29,8 @@ const browserAliases: Alias[] = [ ] export default defineConfig([ + workerNodejs(), + workerBrowser(), nodejs(), nodejsTypes(), browser(), @@ -204,3 +206,58 @@ function umdMinified(): RollupOptions { onwarn, } } + +/** + * Worker bundle for Node.js - ESM format for use with web-worker {type: 'module'} + */ +function workerNodejs(): RollupOptions { + return { + input: './dist/nodejs/src/signature/SignatureValidationWorker.js', + context: 'globalThis', + output: { + format: 'es', + file: './dist/workers/SignatureValidationWorker.node.mjs', + sourcemap: true, + }, + plugins: [ + json(), + alias({ + entries: nodejsAliases, + }), + nodeResolve({ + preferBuiltins: true, + }), + cjs(), + ], + external: [/node_modules/, /@streamr\//], + onwarn, + } +} + +/** + * Worker bundle for browser - ESM format for use with web-worker {type: 'module'} + */ +function workerBrowser(): RollupOptions { + return { + input: './dist/browser/src/signature/SignatureValidationWorker.js', + context: 'self', + output: { + format: 'es', + file: './dist/workers/SignatureValidationWorker.browser.mjs', + sourcemap: true, + }, + plugins: [ + json(), + alias({ + entries: browserAliases, + }), + nodeResolve({ + browser: true, + preferBuiltins: false, + }), + cjs(), + ], + external: [], + onwarn, + } +} diff --git a/packages/sdk/src/_browser/createSignatureValidationWorker.ts b/packages/sdk/src/_browser/createSignatureValidationWorker.ts new file mode 100644 index 0000000000..73388eefb3 --- /dev/null +++ b/packages/sdk/src/_browser/createSignatureValidationWorker.ts @@ -0,0 +1,11 @@ +/** + * Browser-specific signature validation worker factory. + */ +import Worker from 'web-worker' + +export function createSignatureValidationWorker(): InstanceType { + return new Worker( + new URL('./workers/SignatureValidationWorker.browser.mjs', import.meta.url), + { type: 'module' } + ) +} diff --git a/packages/sdk/src/_jest/createSignatureValidationWorker.ts b/packages/sdk/src/_jest/createSignatureValidationWorker.ts new file mode 100644 index 0000000000..73eedd434f --- /dev/null +++ b/packages/sdk/src/_jest/createSignatureValidationWorker.ts @@ -0,0 +1,11 @@ +/** + * Jest-specific signature validation worker factory. + */ +import Worker from 'web-worker' + +export function createSignatureValidationWorker(): InstanceType { + return new Worker( + new URL('../../dist/workers/SignatureValidationWorker.node.mjs', import.meta.url), + { type: 'module' } + ) +} diff --git a/packages/sdk/src/_karma/createSignatureValidationWorker.ts b/packages/sdk/src/_karma/createSignatureValidationWorker.ts new file mode 100644 index 0000000000..e2e4090127 --- /dev/null +++ b/packages/sdk/src/_karma/createSignatureValidationWorker.ts @@ -0,0 +1,11 @@ +/** + * Browser-specific signature validation worker factory. + */ +import Worker from 'web-worker' + +export function createSignatureValidationWorker(): InstanceType { + return new Worker( + new URL('../../dist/workers/SignatureValidationWorker.browser.mjs', import.meta.url), + { type: 'module' } + ) +} diff --git a/packages/sdk/src/_nodejs/createSignatureValidationWorker.ts b/packages/sdk/src/_nodejs/createSignatureValidationWorker.ts new file mode 100644 index 0000000000..ad891da4f6 --- /dev/null +++ b/packages/sdk/src/_nodejs/createSignatureValidationWorker.ts @@ -0,0 +1,11 @@ +/** + * Node.js-specific signature validation worker factory. + */ +import Worker from 'web-worker' + +export function createSignatureValidationWorker(): InstanceType { + return new Worker( + new URL('./workers/SignatureValidationWorker.node.mjs', import.meta.url), + { type: 'module' } + ) +} diff --git a/packages/sdk/src/signature/SignatureValidation.ts b/packages/sdk/src/signature/SignatureValidation.ts new file mode 100644 index 0000000000..760334e0b5 --- /dev/null +++ b/packages/sdk/src/signature/SignatureValidation.ts @@ -0,0 +1,31 @@ +/** + * Unified signature validation using Web Worker. + * This offloads CPU-intensive cryptographic operations to a separate thread. + * Works in both browser and Node.js environments via platform-specific config. + */ +import { wrap, releaseProxy, type Remote } from 'comlink' +import { createSignatureValidationWorker } from '@/createSignatureValidationWorker' +import { SignatureValidationResult, toSignatureValidationData } from './signatureValidationUtils' +import type { SignatureValidationWorkerApi } from './SignatureValidationWorker' +import { StreamMessage } from '../protocol/StreamMessage' + +export class SignatureValidation { + private worker: ReturnType + private workerApi: Remote + + constructor() { + this.worker = createSignatureValidationWorker() + this.workerApi = wrap(this.worker) + } + + async validateSignature(message: StreamMessage): Promise { + // Convert class instance to plain serializable data before sending to worker + const data = toSignatureValidationData(message) + return this.workerApi.validateSignature(data) + } + + destroy(): void { + this.workerApi[releaseProxy]() + this.worker.terminate() + } +} diff --git a/packages/sdk/src/signature/SignatureValidationWorker.ts b/packages/sdk/src/signature/SignatureValidationWorker.ts new file mode 100644 index 0000000000..f55ac77e7b --- /dev/null +++ b/packages/sdk/src/signature/SignatureValidationWorker.ts @@ -0,0 +1,18 @@ +import { expose } from 'comlink' +import { + validateSignatureData, + SignatureValidationResult, + SignatureValidationData, +} from './signatureValidationUtils' + +const workerApi = { + validateSignature: async ( + data: SignatureValidationData + ): Promise => { + return validateSignatureData(data) + }, +} + +export type SignatureValidationWorkerApi = typeof workerApi + +expose(workerApi) diff --git a/packages/sdk/src/signature/SignatureValidator.ts b/packages/sdk/src/signature/SignatureValidator.ts index 0c7ba17605..87328bfe0c 100644 --- a/packages/sdk/src/signature/SignatureValidator.ts +++ b/packages/sdk/src/signature/SignatureValidator.ts @@ -1,26 +1,28 @@ -import { toEthereumAddress, toUserIdRaw, SigningUtil } from '@streamr/utils' +import { toEthereumAddress } from '@streamr/utils' import { Lifecycle, scoped } from 'tsyringe' import { ERC1271ContractFacade } from '../contracts/ERC1271ContractFacade' +import { DestroySignal } from '../DestroySignal' import { StreamMessage } from '../protocol/StreamMessage' import { StreamrClientError } from '../StreamrClientError' -import { createLegacySignaturePayload } from './createLegacySignaturePayload' import { createSignaturePayload } from './createSignaturePayload' +import { SignatureValidation } from './SignatureValidation' import { SignatureType } from '@streamr/trackerless-network' -import { IDENTITY_MAPPING } from '../identity/IdentityMapping' - -// Lookup structure SignatureType -> SigningUtil -const signingUtilBySignatureType: Record = Object.fromEntries( - IDENTITY_MAPPING.map((idMapping) => [idMapping.signatureType, SigningUtil.getInstance(idMapping.keyType)]) -) - -const evmSigner = SigningUtil.getInstance('ECDSA_SECP256K1_EVM') @scoped(Lifecycle.ContainerScoped) export class SignatureValidator { private readonly erc1271ContractFacade: ERC1271ContractFacade + private signatureValidation: SignatureValidation | undefined - constructor(erc1271ContractFacade: ERC1271ContractFacade) { + constructor( + erc1271ContractFacade: ERC1271ContractFacade, + destroySignal: DestroySignal + ) { this.erc1271ContractFacade = erc1271ContractFacade + destroySignal.onDestroy.listen(() => this.destroy()) + } + + private getSignatureValidation(): SignatureValidation { + return this.signatureValidation ??= new SignatureValidation() } /** @@ -41,36 +43,33 @@ export class SignatureValidator { } private async validate(streamMessage: StreamMessage): Promise { - const signingUtil = signingUtilBySignatureType[streamMessage.signatureType] - - // Common case - if (signingUtil) { - return signingUtil.verifySignature( - toUserIdRaw(streamMessage.getPublisherId()), - createSignaturePayload(streamMessage), - streamMessage.signature - ) - } - - // Special handling: different payload computation, same SigningUtil - if (streamMessage.signatureType === SignatureType.ECDSA_SECP256K1_LEGACY) { - return evmSigner.verifySignature( - // publisherId is hex encoded Ethereum address string - toUserIdRaw(streamMessage.getPublisherId()), - createLegacySignaturePayload(streamMessage), - streamMessage.signature - ) - } - - // Special handling: check signature with ERC-1271 contract facade if (streamMessage.signatureType === SignatureType.ERC_1271) { return this.erc1271ContractFacade.isValidSignature( - toEthereumAddress(streamMessage.getPublisherId()), + toEthereumAddress(streamMessage.messageId.publisherId), createSignaturePayload(streamMessage), streamMessage.signature ) } + const result = await this.getSignatureValidation().validateSignature(streamMessage) + switch (result.type) { + case 'valid': + return true + case 'invalid': + return false + case 'error': + throw new Error(result.message) + default: + throw new Error(`Unknown signature validation result type '${result}'`) + } + } - throw new Error(`Cannot validate message signature, unsupported signatureType: "${streamMessage.signatureType}"`) + /** + * Cleanup worker resources when the validator is no longer needed. + */ + destroy(): void { + if (this.signatureValidation) { + this.signatureValidation.destroy() + this.signatureValidation = undefined + } } } diff --git a/packages/sdk/src/signature/createLegacySignaturePayload.ts b/packages/sdk/src/signature/createLegacySignaturePayload.ts index 3aadd0828e..42c785c2fe 100644 --- a/packages/sdk/src/signature/createLegacySignaturePayload.ts +++ b/packages/sdk/src/signature/createLegacySignaturePayload.ts @@ -1,7 +1,6 @@ import { binaryToHex, binaryToUtf8 } from '@streamr/utils' import { EncryptedGroupKey, EncryptionType } from '@streamr/trackerless-network' -import { MessageID } from '../protocol/MessageID' -import { MessageRef } from '../protocol/MessageRef' +import { MessageIdLike, MessageRefLike } from './createSignaturePayload' const serializeGroupKey = ({ id, data }: EncryptedGroupKey): string => { return JSON.stringify([id, binaryToHex(data)]) @@ -11,10 +10,10 @@ const serializeGroupKey = ({ id, data }: EncryptedGroupKey): string => { * Only to be used for LEGACY_SECP256K1 signature type. */ export const createLegacySignaturePayload = (opts: { - messageId: MessageID + messageId: MessageIdLike content: Uint8Array encryptionType: EncryptionType - prevMsgRef?: MessageRef + prevMsgRef?: MessageRefLike newGroupKey?: EncryptedGroupKey }): Uint8Array => { const prev = ((opts.prevMsgRef !== undefined) ? `${opts.prevMsgRef.timestamp}${opts.prevMsgRef.sequenceNumber}` : '') diff --git a/packages/sdk/src/signature/createSignaturePayload.ts b/packages/sdk/src/signature/createSignaturePayload.ts index 9cfadf7d32..0162139680 100644 --- a/packages/sdk/src/signature/createSignaturePayload.ts +++ b/packages/sdk/src/signature/createSignaturePayload.ts @@ -3,16 +3,34 @@ import { GroupKeyRequest as NewGroupKeyRequest, GroupKeyResponse as NewGroupKeyResponse } from '@streamr/trackerless-network' -import { utf8ToBinary } from '@streamr/utils' -import { MessageID } from '../protocol/MessageID' -import { MessageRef } from '../protocol/MessageRef' +import { StreamID, UserID, utf8ToBinary } from '@streamr/utils' import { StreamMessageType } from '../protocol/StreamMessage' +/** + * Plain data for message ID - accepts class instances or plain objects with the same properties. + */ +export interface MessageIdLike { + streamId: StreamID + streamPartition: number + timestamp: number + sequenceNumber: number + publisherId: UserID + msgChainId: string +} + +/** + * Plain data for message reference - accepts class instances or plain objects with the same properties. + */ +export interface MessageRefLike { + timestamp: number + sequenceNumber: number +} + export const createSignaturePayload = (opts: { - messageId: MessageID + messageId: MessageIdLike content: Uint8Array messageType: StreamMessageType - prevMsgRef?: MessageRef + prevMsgRef?: MessageRefLike newGroupKey?: EncryptedGroupKey }): Uint8Array | never => { const header = Buffer.concat([ diff --git a/packages/sdk/src/signature/signatureValidationUtils.ts b/packages/sdk/src/signature/signatureValidationUtils.ts new file mode 100644 index 0000000000..6f1cd3d348 --- /dev/null +++ b/packages/sdk/src/signature/signatureValidationUtils.ts @@ -0,0 +1,112 @@ +/** + * Core signature validation logic - shared between worker and main thread implementations. + * This file contains pure cryptographic validation functions without any network dependencies. + */ +import { SigningUtil, toUserIdRaw } from '@streamr/utils' +import { EncryptedGroupKey, EncryptionType, SignatureType } from '@streamr/trackerless-network' +import { IDENTITY_MAPPING } from '../identity/IdentityMapping' +import { createSignaturePayload, MessageIdLike, MessageRefLike } from './createSignaturePayload' +import { createLegacySignaturePayload } from './createLegacySignaturePayload' +import { StreamMessage, StreamMessageType } from '../protocol/StreamMessage' + +// Lookup structure SignatureType -> SigningUtil +const signingUtilBySignatureType: Record = Object.fromEntries( + IDENTITY_MAPPING.map((idMapping) => [idMapping.signatureType, SigningUtil.getInstance(idMapping.keyType)]) +) + +const evmSigner = SigningUtil.getInstance('ECDSA_SECP256K1_EVM') + +/** + * Result of signature validation + */ +export type SignatureValidationResult = + | { type: 'valid' } + | { type: 'invalid' } + | { type: 'error', message: string } + +/** + * Plain data type for signature validation that can be serialized to a worker. + * This contains only primitive values and simple objects (no class instances). + */ +export interface SignatureValidationData { + messageId: MessageIdLike + prevMsgRef?: MessageRefLike + messageType: StreamMessageType + content: Uint8Array + signature: Uint8Array + signatureType: SignatureType + encryptionType: EncryptionType + newGroupKey?: EncryptedGroupKey +} + +/** + * Extract plain serializable data from a StreamMessage for worker communication. + */ +export function toSignatureValidationData(message: StreamMessage): SignatureValidationData { + return { + messageId: { + streamId: message.messageId.streamId, + streamPartition: message.messageId.streamPartition, + timestamp: message.messageId.timestamp, + sequenceNumber: message.messageId.sequenceNumber, + publisherId: message.messageId.publisherId, + msgChainId: message.messageId.msgChainId, + }, + prevMsgRef: message.prevMsgRef ? { + timestamp: message.prevMsgRef.timestamp, + sequenceNumber: message.prevMsgRef.sequenceNumber, + } : undefined, + messageType: message.messageType, + content: message.content, + signature: message.signature, + signatureType: message.signatureType, + encryptionType: message.encryptionType, + newGroupKey: message.newGroupKey, + } +} + +/** + * Validate signature using extracted data. + * This is the core validation logic that can be run in a worker. + */ +export async function validateSignatureData(data: SignatureValidationData): Promise { + try { + const signingUtil = signingUtilBySignatureType[data.signatureType] + // Common case: standard signature types + if (signingUtil) { + const payload = createSignaturePayload({ + messageId: data.messageId, + content: data.content, + messageType: data.messageType, + prevMsgRef: data.prevMsgRef, + newGroupKey: data.newGroupKey, + }) + const isValid = await signingUtil.verifySignature( + toUserIdRaw(data.messageId.publisherId), + payload, + data.signature + ) + return isValid ? { type: 'valid' } : { type: 'invalid' } + } + // Special handling: legacy signature type + if (data.signatureType === SignatureType.ECDSA_SECP256K1_LEGACY) { + const payload = createLegacySignaturePayload({ + messageId: data.messageId, + content: data.content, + encryptionType: data.encryptionType, + prevMsgRef: data.prevMsgRef, + newGroupKey: data.newGroupKey, + }) + const isValid = await evmSigner.verifySignature( + toUserIdRaw(data.messageId.publisherId), + payload, + data.signature + ) + return isValid ? { type: 'valid' } : { type: 'invalid' } + } + return { type: 'error', message: `Unsupported signatureType: "${data.signatureType}"` } + } catch (err) { + return { type: 'error', message: String(err) } + } +} + diff --git a/packages/sdk/test/integration/update-encryption-key.test.ts b/packages/sdk/test/integration/update-encryption-key.test.ts index 23d65e55a0..16554a6ea3 100644 --- a/packages/sdk/test/integration/update-encryption-key.test.ts +++ b/packages/sdk/test/integration/update-encryption-key.test.ts @@ -24,7 +24,7 @@ describe('update encryption key', () => { publisher = environment.createClient() subscriber = environment.createClient({ encryption: { - keyRequestTimeout: 200 + keyRequestTimeout: 1000 } }) const stream = await publisher.createStream('/path') diff --git a/packages/sdk/test/unit/MessageFactory.test.ts b/packages/sdk/test/unit/MessageFactory.test.ts index 3b2f0b93b9..03d09f31d3 100644 --- a/packages/sdk/test/unit/MessageFactory.test.ts +++ b/packages/sdk/test/unit/MessageFactory.test.ts @@ -16,6 +16,7 @@ import { StreamMessage, StreamMessageType } from './../../src/protocol/StreamMes import { EthereumKeyPairIdentity } from '../../src/identity/EthereumKeyPairIdentity' import { EncryptionType, SignatureType, ContentType } from '@streamr/trackerless-network' import type { StrictStreamrClientConfig } from '../../src/ConfigTypes' +import { DestroySignal } from '../../src/DestroySignal' const CONTENT = { foo: 'bar' } const TIMESTAMP = Date.parse('2001-02-03T04:05:06Z') @@ -58,7 +59,7 @@ describe('MessageFactory', () => { isStreamPublisher: true }), groupKeyQueue: await createGroupKeyQueue(identity, GROUP_KEY), - signatureValidator: new SignatureValidator(opts?.erc1271ContractFacade ?? mock()), + signatureValidator: new SignatureValidator(opts?.erc1271ContractFacade ?? mock(), new DestroySignal()), messageSigner: new MessageSigner(identity), config: { validation: { diff --git a/packages/sdk/test/unit/SignatureValidator.test.ts b/packages/sdk/test/unit/SignatureValidator.test.ts index d08cd1da29..5a995dba35 100644 --- a/packages/sdk/test/unit/SignatureValidator.test.ts +++ b/packages/sdk/test/unit/SignatureValidator.test.ts @@ -9,6 +9,7 @@ import { StreamrClientError } from './../../src/StreamrClientError' import { MessageID } from './../../src/protocol/MessageID' import { StreamMessage, StreamMessageType } from './../../src/protocol/StreamMessage' import { ContentType, EncryptionType, SignatureType } from '@streamr/trackerless-network' +import { DestroySignal } from '../../src/DestroySignal' describe('SignatureValidator', () => { let erc1271ContractFacade: MockProxy @@ -16,7 +17,7 @@ describe('SignatureValidator', () => { beforeEach(() => { erc1271ContractFacade = mock() - signatureValidator = new SignatureValidator(erc1271ContractFacade) + signatureValidator = new SignatureValidator(erc1271ContractFacade, new DestroySignal()) }) describe('SECP256K1', () => { diff --git a/packages/sdk/test/unit/messagePipeline.test.ts b/packages/sdk/test/unit/messagePipeline.test.ts index 84370e858f..c267813b6f 100644 --- a/packages/sdk/test/unit/messagePipeline.test.ts +++ b/packages/sdk/test/unit/messagePipeline.test.ts @@ -86,7 +86,7 @@ describe('messagePipeline', () => { getStorageNodes: undefined as any, resends: undefined as any, streamRegistry: streamRegistry as any, - signatureValidator: new SignatureValidator(mock()), + signatureValidator: new SignatureValidator(mock(), destroySignal), groupKeyManager: new GroupKeyManager( mock(), groupKeyStore, diff --git a/packages/sdk/test/unit/validateStreamMessage.test.ts b/packages/sdk/test/unit/validateStreamMessage.test.ts index 314583c4bf..4f76a68044 100644 --- a/packages/sdk/test/unit/validateStreamMessage.test.ts +++ b/packages/sdk/test/unit/validateStreamMessage.test.ts @@ -10,6 +10,7 @@ import { validateStreamMessage } from '../../src/utils/validateStreamMessage' import { createMockMessage } from '../test-utils/utils' import { StreamMessage } from './../../src/protocol/StreamMessage' import type { StrictStreamrClientConfig } from '../../src/ConfigTypes' +import { DestroySignal } from '../../src/DestroySignal' const PARTITION_COUNT = 3 @@ -45,7 +46,7 @@ describe('Validator', () => { await validateStreamMessage( msg, streamRegistry as any, - new SignatureValidator(mock()), + new SignatureValidator(mock(), new DestroySignal()), { validation: { permissions: true, diff --git a/packages/sdk/test/unit/validateStreamMessage2.test.ts b/packages/sdk/test/unit/validateStreamMessage2.test.ts index e120307cd3..9010e93cba 100644 --- a/packages/sdk/test/unit/validateStreamMessage2.test.ts +++ b/packages/sdk/test/unit/validateStreamMessage2.test.ts @@ -12,6 +12,7 @@ import { MessageID } from './../../src/protocol/MessageID' import { MessageRef } from './../../src/protocol/MessageRef' import { StreamMessage, StreamMessageType } from './../../src/protocol/StreamMessage' import type { StrictStreamrClientConfig } from '../../src/ConfigTypes' +import { DestroySignal } from '../../src/DestroySignal' const groupKeyRequestToStreamMessage = async ( groupKeyRequest: GroupKeyRequest, @@ -69,7 +70,7 @@ describe('Validator2', () => { isStreamPublisher: (streamId: string, userId: UserID) => isPublisher(userId, streamId), isStreamSubscriber: (streamId: string, userId: UserID) => isSubscriber(userId, streamId) } as any, - new SignatureValidator(mock()), + new SignatureValidator(mock(), new DestroySignal()), { validation: { permissions: true,