From c5899ef731297928e629393709d44edb78ee4be6 Mon Sep 17 00:00:00 2001 From: AdriGeorge Date: Mon, 18 May 2026 09:24:20 +0300 Subject: [PATCH 1/4] chore: double decryption --- .../Indexer/processors/BaseProcessor.ts | 7 +- .../processors/MetadataEventProcessor.ts | 73 +++++++++++++++++-- src/components/core/handler/ddoHandler.ts | 2 +- 3 files changed, 73 insertions(+), 9 deletions(-) diff --git a/src/components/Indexer/processors/BaseProcessor.ts b/src/components/Indexer/processors/BaseProcessor.ts index 95fa4439a..5c6aaf4d1 100644 --- a/src/components/Indexer/processors/BaseProcessor.ts +++ b/src/components/Indexer/processors/BaseProcessor.ts @@ -317,6 +317,9 @@ export abstract class BaseEventProcessor { chainId, decrypterAddress: ethAddress, dataNftAddress: contractAddress, + encryptedDocument: txId ? undefined : metadata, + flags: parseInt(flag), + documentHash: metadataHash || undefined, signature, nonce } @@ -383,7 +386,7 @@ export abstract class BaseEventProcessor { ddo = JSON.parse(response.data) responseHash = create256Hash(ddo) } - if (responseHash !== metadataHash) { + if (metadataHash && responseHash !== metadataHash) { const msg = `Hash check failed: response=${ddo}, decrypted ddo hash=${responseHash}\n metadata hash=${metadataHash}` INDEXER_LOGGER.log(LOG_LEVELS_STR.LEVEL_ERROR, msg) throw new Error(msg) @@ -429,6 +432,7 @@ export abstract class BaseEventProcessor { decrypterAddress: ethAddress, chainId, encryptedDocument: metadata, + flags: parseInt(flag), documentHash: metadataHash, dataNftAddress: contractAddress, signature, @@ -491,6 +495,7 @@ export abstract class BaseEventProcessor { decrypterAddress: ethAddress, chainId, encryptedDocument: metadata, + flags: parseInt(flag), documentHash: metadataHash, dataNftAddress: contractAddress, signature, diff --git a/src/components/Indexer/processors/MetadataEventProcessor.ts b/src/components/Indexer/processors/MetadataEventProcessor.ts index 82b6162f1..e08c695dd 100644 --- a/src/components/Indexer/processors/MetadataEventProcessor.ts +++ b/src/components/Indexer/processors/MetadataEventProcessor.ts @@ -9,7 +9,7 @@ import { deleteIndexedMetadataIfExists } from '../../../utils/asset.js' import { checkCredentialOnAccessList } from '../../../utils/credentials.js' -import { INDEXER_LOGGER } from '../../../utils/logging/common.js' +import { CORE_LOGGER, INDEXER_LOGGER } from '../../../utils/logging/common.js' import { LOG_LEVELS_STR } from '../../../utils/logging/Logger.js' import { asyncCallWithTimeout, streamToString } from '../../../utils/util.js' import { PolicyServer } from '../../policyServer/index.js' @@ -23,6 +23,16 @@ import { getConfiguration } from '../../../utils/config.js' import { isRemoteDDO } from '../../core/utils/validateDdoHandler.js' export class MetadataEventProcessor extends BaseEventProcessor { + private isDDO(data: any): data is Record { + return ( + data && + typeof data === 'object' && + !Array.isArray(data) && + typeof data.id === 'string' && + typeof data.version === 'string' + ) + } + async processEvent( event: ethers.Log, chainId: number, @@ -123,6 +133,9 @@ export class MetadataEventProcessor extends BaseEventProcessor { metadata ) let ddo = await this.processDDO(decryptDDO) + CORE_LOGGER.logMessage( + `Processed DDO for event ${event.transactionHash}: ${JSON.stringify(ddo)}` + ) if ( !isRemoteDDO(decryptDDO) && parseInt(flag) !== 2 && @@ -131,17 +144,63 @@ export class MetadataEventProcessor extends BaseEventProcessor { return } if (ddo.encryptedData) { + let { encryptedData } = ddo + if ((parseInt(flag) & 2) !== 0) { + try { + const decryptedIpfsPayload = await this.decryptDDO( + decodedEventData.args[2], + flag, + owner, + event.address, + chainId, + '', + '', + ddo.encryptedData + ) + CORE_LOGGER.logMessage( + `Decrypted IPFS payload for event ${event.transactionHash}: ${JSON.stringify(decryptedIpfsPayload)}` + ) + encryptedData = decryptedIpfsPayload.encryptedData || encryptedData + } catch (error) { + INDEXER_LOGGER.log( + LOG_LEVELS_STR.LEVEL_ERROR, + `Unable to decrypt encrypted IPFS DDO payload, trying plaintext payload fallback: ${ + error instanceof Error ? error.message : String(error) + }` + ) + } + } + const proof = await this.decryptDDOIPFS( decodedEventData.args[2], owner, - ddo.encryptedData + encryptedData ) - const data = this.getDataFromProof(proof) - const ddoInstance = DDOManager.getDDOClass(data.ddoObj) - ddo = ddoInstance.updateFields({ - proof: { signature: data.signature, header: data.header } - }) + CORE_LOGGER.logMessage( + `Decrypted proof payload for event ${event.transactionHash}: ${JSON.stringify(proof)}` + ) + const data = typeof proof === 'string' ? this.getDataFromProof(proof) : null + + const ddoObj = data?.ddoObj || (this.isDDO(proof) ? proof : null) + CORE_LOGGER.logMessage( + `Processed ddoOBJ for event ${event.transactionHash}: ${JSON.stringify(ddoObj)}` + ) + if (!ddoObj) { + throw new Error( + 'IPFS encryptedData payload is neither a DDO nor a supported DDO proof.' + ) + } + const ddoInstance = DDOManager.getDDOClass(ddoObj) + ddo = + data?.signature && data?.header + ? ddoInstance.updateFields({ + proof: { signature: data.signature, header: data.header } + }) + : ddoInstance.getDDOData() } + CORE_LOGGER.logMessage( + `Processed DDO final for event ${event.transactionHash}: ${JSON.stringify(ddo)}` + ) const clonedDdo = structuredClone(ddo) const updatedDdo = deleteIndexedMetadataIfExists(clonedDdo) const ddoInstance = DDOManager.getDDOClass(updatedDdo) diff --git a/src/components/core/handler/ddoHandler.ts b/src/components/core/handler/ddoHandler.ts index 13f281219..b33e5fedc 100644 --- a/src/components/core/handler/ddoHandler.ts +++ b/src/components/core/handler/ddoHandler.ts @@ -357,7 +357,7 @@ export class DecryptDdoHandler extends CommandHandler { } else { // checksum matches const decryptedDocumentHash = create256Hash(decryptedDocument.toString()) - if (decryptedDocumentHash !== documentHash) { + if (documentHash && decryptedDocumentHash !== documentHash) { return { stream: null, status: { From feb6e68a7dff8f1225de87ab6db89527762fff32 Mon Sep 17 00:00:00 2001 From: AdriGeorge Date: Mon, 18 May 2026 10:20:44 +0300 Subject: [PATCH 2/4] fix: improve DDO hash validation logic in BaseEventProcessor and MetadataEventProcessor --- .../Indexer/processors/BaseProcessor.ts | 9 +++++++-- .../Indexer/processors/MetadataEventProcessor.ts | 16 +++++++++------- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/src/components/Indexer/processors/BaseProcessor.ts b/src/components/Indexer/processors/BaseProcessor.ts index 5c6aaf4d1..939260be0 100644 --- a/src/components/Indexer/processors/BaseProcessor.ts +++ b/src/components/Indexer/processors/BaseProcessor.ts @@ -210,9 +210,14 @@ export abstract class BaseEventProcessor { } protected checkDdoHash(decryptedDocument: any, documentHashFromContract: any): boolean { - const utf8Bytes = toUtf8Bytes(JSON.stringify(decryptedDocument)) + const documentString = JSON.stringify(decryptedDocument) + const utf8Bytes = toUtf8Bytes(documentString) const expectedMetadata = hexlify(utf8Bytes) - if (create256Hash(expectedMetadata.toString()) !== documentHashFromContract) { + const validHashes = [ + create256Hash(expectedMetadata.toString()), + create256Hash(documentString) + ] + if (!validHashes.includes(documentHashFromContract)) { INDEXER_LOGGER.error(`DDO checksum does not match.`) return false } diff --git a/src/components/Indexer/processors/MetadataEventProcessor.ts b/src/components/Indexer/processors/MetadataEventProcessor.ts index e08c695dd..4e9439cc0 100644 --- a/src/components/Indexer/processors/MetadataEventProcessor.ts +++ b/src/components/Indexer/processors/MetadataEventProcessor.ts @@ -132,15 +132,13 @@ export class MetadataEventProcessor extends BaseEventProcessor { metadataHash, metadata ) + const isRemoteMetadata = isRemoteDDO(decryptDDO) + const isEncryptedMetadata = (parseInt(flag) & 2) !== 0 let ddo = await this.processDDO(decryptDDO) CORE_LOGGER.logMessage( `Processed DDO for event ${event.transactionHash}: ${JSON.stringify(ddo)}` ) - if ( - !isRemoteDDO(decryptDDO) && - parseInt(flag) !== 2 && - !this.checkDdoHash(ddo, metadataHash) - ) { + if (!isEncryptedMetadata && !this.checkDdoHash(ddo, metadataHash)) { return } if (ddo.encryptedData) { @@ -218,8 +216,12 @@ export class MetadataEventProcessor extends BaseEventProcessor { ) return } - // for unencrypted DDOs - if ((parseInt(flag) & 2) === 0 && !this.checkDdoHash(updatedDdo, metadataHash)) { + // for unencrypted inline DDOs + if ( + !isRemoteMetadata && + !isEncryptedMetadata && + !this.checkDdoHash(updatedDdo, metadataHash) + ) { INDEXER_LOGGER.error('Unencrypted DDO hash does not match metadata hash.') await ddoState.update( this.networkId, From 356f749af86de82c102d8b26e13b520fa9b96437 Mon Sep 17 00:00:00 2001 From: AdriGeorge Date: Mon, 18 May 2026 10:24:54 +0300 Subject: [PATCH 3/4] fix: remove logs --- .../processors/MetadataEventProcessor.ts | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/src/components/Indexer/processors/MetadataEventProcessor.ts b/src/components/Indexer/processors/MetadataEventProcessor.ts index 4e9439cc0..f618c85c7 100644 --- a/src/components/Indexer/processors/MetadataEventProcessor.ts +++ b/src/components/Indexer/processors/MetadataEventProcessor.ts @@ -9,7 +9,7 @@ import { deleteIndexedMetadataIfExists } from '../../../utils/asset.js' import { checkCredentialOnAccessList } from '../../../utils/credentials.js' -import { CORE_LOGGER, INDEXER_LOGGER } from '../../../utils/logging/common.js' +import { INDEXER_LOGGER } from '../../../utils/logging/common.js' import { LOG_LEVELS_STR } from '../../../utils/logging/Logger.js' import { asyncCallWithTimeout, streamToString } from '../../../utils/util.js' import { PolicyServer } from '../../policyServer/index.js' @@ -135,9 +135,6 @@ export class MetadataEventProcessor extends BaseEventProcessor { const isRemoteMetadata = isRemoteDDO(decryptDDO) const isEncryptedMetadata = (parseInt(flag) & 2) !== 0 let ddo = await this.processDDO(decryptDDO) - CORE_LOGGER.logMessage( - `Processed DDO for event ${event.transactionHash}: ${JSON.stringify(ddo)}` - ) if (!isEncryptedMetadata && !this.checkDdoHash(ddo, metadataHash)) { return } @@ -155,9 +152,6 @@ export class MetadataEventProcessor extends BaseEventProcessor { '', ddo.encryptedData ) - CORE_LOGGER.logMessage( - `Decrypted IPFS payload for event ${event.transactionHash}: ${JSON.stringify(decryptedIpfsPayload)}` - ) encryptedData = decryptedIpfsPayload.encryptedData || encryptedData } catch (error) { INDEXER_LOGGER.log( @@ -174,15 +168,9 @@ export class MetadataEventProcessor extends BaseEventProcessor { owner, encryptedData ) - CORE_LOGGER.logMessage( - `Decrypted proof payload for event ${event.transactionHash}: ${JSON.stringify(proof)}` - ) const data = typeof proof === 'string' ? this.getDataFromProof(proof) : null const ddoObj = data?.ddoObj || (this.isDDO(proof) ? proof : null) - CORE_LOGGER.logMessage( - `Processed ddoOBJ for event ${event.transactionHash}: ${JSON.stringify(ddoObj)}` - ) if (!ddoObj) { throw new Error( 'IPFS encryptedData payload is neither a DDO nor a supported DDO proof.' @@ -196,9 +184,6 @@ export class MetadataEventProcessor extends BaseEventProcessor { }) : ddoInstance.getDDOData() } - CORE_LOGGER.logMessage( - `Processed DDO final for event ${event.transactionHash}: ${JSON.stringify(ddo)}` - ) const clonedDdo = structuredClone(ddo) const updatedDdo = deleteIndexedMetadataIfExists(clonedDdo) const ddoInstance = DDOManager.getDDOClass(updatedDdo) From 0c2f3a4e006598477dd9bea274544bcc567c09bd Mon Sep 17 00:00:00 2001 From: AdriGeorge Date: Mon, 18 May 2026 10:31:20 +0300 Subject: [PATCH 4/4] chore: 3.1.12 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 500db652a..e3e39a9f6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "ocean-node", - "version": "3.1.11", + "version": "3.1.12", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "ocean-node", - "version": "3.1.11", + "version": "3.1.12", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { diff --git a/package.json b/package.json index bca6ee73c..fd00bd054 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ocean-node", - "version": "3.1.11", + "version": "3.1.12", "description": "Ocean Node is used to run all core services in the Ocean stack", "author": "Ocean Protocol Foundation", "license": "Apache-2.0",