diff --git a/.env.demo b/.env.demo index 033e26aa..a2ebfa60 100644 --- a/.env.demo +++ b/.env.demo @@ -30,6 +30,10 @@ OTEL_LOGS_OTLP_ENDPOINT='http://localhost:4318/v1/logs' OTEL_HEADERS_KEY='88caXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' OTEL_LOGGER_NAME='credo-controller-logger' +ENABLE_CUSTOM_DOCUMENT_LOADER=false +DEPRECATED_DOMAIN=https://schema.credebl.id +CURRENT_DOMAIN=https://schema.new-credebl.id + BCOVRIN_TEST_GENESIS='{"reqSignature":{},"txn":{"data":{"data":{"alias":"Node1","blskey":"4N8aUNHSgjQVgkpm8nhNEfDf6txHznoYREg9kirmJrkivgL4oSEimFF6nsQ6M41QvhM2Z33nves5vfSn9n1UwNFJBYtWVnHYMATn76vLuL3zU88KyeAYcHfsih3He6UHcXDxcaecHVz6jhCYz1P2UZn2bDVruL5wXpehgBfBaLKm3Ba","blskey_pop":"RahHYiCvoNCtPTrVtP7nMC5eTYrsUA8WjXbdhNc8debh1agE9bGiJxWBXYNFbnJXoXhWFMvyqhqhRoq737YQemH5ik9oL7R4NTTCz2LEZhkgLJzB3QRQqJyBNyv7acbdHrAT8nQ9UkLbaVL9NBpnWXBTw4LEMePaSHEw66RzPNdAX1","client_ip":"138.197.138.255","client_port":9702,"node_ip":"138.197.138.255","node_port":9701,"services":["VALIDATOR"]},"dest":"Gw6pDLhcBcoQesN72qfotTgFa7cbuqZpkX3Xo6pLhPhv"},"metadata":{"from":"Th7MpTaRZVRYnPiabds81Y"},"type":"0"},"txnMetadata":{"seqNo":1,"txnId":"fea82e10e894419fe2bea7d96296a6d46f50f93f9eeda954ec461b2ed2950b62"},"ver":"1"} {"reqSignature":{},"txn":{"data":{"data":{"alias":"Node2","blskey":"37rAPpXVoxzKhz7d9gkUe52XuXryuLXoM6P6LbWDB7LSbG62Lsb33sfG7zqS8TK1MXwuCHj1FKNzVpsnafmqLG1vXN88rt38mNFs9TENzm4QHdBzsvCuoBnPH7rpYYDo9DZNJePaDvRvqJKByCabubJz3XXKbEeshzpz4Ma5QYpJqjk","blskey_pop":"Qr658mWZ2YC8JXGXwMDQTzuZCWF7NK9EwxphGmcBvCh6ybUuLxbG65nsX4JvD4SPNtkJ2w9ug1yLTj6fgmuDg41TgECXjLCij3RMsV8CwewBVgVN67wsA45DFWvqvLtu4rjNnE9JbdFTc1Z4WCPA3Xan44K1HoHAq9EVeaRYs8zoF5","client_ip":"138.197.138.255","client_port":9704,"node_ip":"138.197.138.255","node_port":9703,"services":["VALIDATOR"]},"dest":"8ECVSk179mjsjKRLWiQtssMLgp6EPhWXtaYyStWPSGAb"},"metadata":{"from":"EbP4aYNeTHL6q385GuVpRV"},"type":"0"},"txnMetadata":{"seqNo":2,"txnId":"1ac8aece2a18ced660fef8694b61aac3af08ba875ce3026a160acbc3a3af35fc"},"ver":"1"} {"reqSignature":{},"txn":{"data":{"data":{"alias":"Node3","blskey":"3WFpdbg7C5cnLYZwFZevJqhubkFALBfCBBok15GdrKMUhUjGsk3jV6QKj6MZgEubF7oqCafxNdkm7eswgA4sdKTRc82tLGzZBd6vNqU8dupzup6uYUf32KTHTPQbuUM8Yk4QFXjEf2Usu2TJcNkdgpyeUSX42u5LqdDDpNSWUK5deC5","blskey_pop":"QwDeb2CkNSx6r8QC8vGQK3GRv7Yndn84TGNijX8YXHPiagXajyfTjoR87rXUu4G4QLk2cF8NNyqWiYMus1623dELWwx57rLCFqGh7N4ZRbGDRP4fnVcaKg1BcUxQ866Ven4gw8y4N56S5HzxXNBZtLYmhGHvDtk6PFkFwCvxYrNYjh","client_ip":"138.197.138.255","client_port":9706,"node_ip":"138.197.138.255","node_port":9705,"services":["VALIDATOR"]},"dest":"DKVxG2fXXTU8yT5N7hGEbXB3dfdAnYv1JczDUHpmDxya"},"metadata":{"from":"4cU41vWW82ArfxJxHkzXPG"},"type":"0"},"txnMetadata":{"seqNo":3,"txnId":"7e9f355dffa78ed24668f0e0e369fd8c224076571c51e2ea8be5f26479edebe4"},"ver":"1"} diff --git a/.env.sample b/.env.sample index 46b3a602..9c6ae29c 100644 --- a/.env.sample +++ b/.env.sample @@ -27,6 +27,11 @@ maxRateLimit= # Specify Did contract address DID_CONTRACT_ADDRESS= +# Boolean: If we want to enable custom document loader +ENABLE_CUSTOM_DOCUMENT_LOADER=false +# If custom document loader is enabled, add the deprecated domain-url and the current/latest domain url +DEPRECATED_DOMAIN= +CURRENT_DOMAIN= # Specify Bcovrin test genesis BCOVRIN_TEST_GENESIS=`{"reqSignature":{},"txn":{"data":{"data":{"alias":"Node1","blskey":"4N8aUNHSgjQVgkpm8nhNEfDf6txHznoYREg9kirmJrkivgL4oSEimFF6nsQ6M41QvhM2Z33nves5vfSn9n1UwNFJBYtWVnHYMATn76vLuL3zU88KyeAYcHfsih3He6UHcXDxcaecHVz6jhCYz1P2UZn2bDVruL5wXpehgBfBaLKm3Ba","blskey_pop":"RahHYiCvoNCtPTrVtP7nMC5eTYrsUA8WjXbdhNc8debh1agE9bGiJxWBXYNFbnJXoXhWFMvyqhqhRoq737YQemH5ik9oL7R4NTTCz2LEZhkgLJzB3QRQqJyBNyv7acbdHrAT8nQ9UkLbaVL9NBpnWXBTw4LEMePaSHEw66RzPNdAX1","client_ip":"138.197.138.255","client_port":9702,"node_ip":"138.197.138.255","node_port":9701,"services":["VALIDATOR"]},"dest":"Gw6pDLhcBcoQesN72qfotTgFa7cbuqZpkX3Xo6pLhPhv"},"metadata":{"from":"Th7MpTaRZVRYnPiabds81Y"},"type":"0"},"txnMetadata":{"seqNo":1,"txnId":"fea82e10e894419fe2bea7d96296a6d46f50f93f9eeda954ec461b2ed2950b62"},"ver":"1"} {"reqSignature":{},"txn":{"data":{"data":{"alias":"Node2","blskey":"37rAPpXVoxzKhz7d9gkUe52XuXryuLXoM6P6LbWDB7LSbG62Lsb33sfG7zqS8TK1MXwuCHj1FKNzVpsnafmqLG1vXN88rt38mNFs9TENzm4QHdBzsvCuoBnPH7rpYYDo9DZNJePaDvRvqJKByCabubJz3XXKbEeshzpz4Ma5QYpJqjk","blskey_pop":"Qr658mWZ2YC8JXGXwMDQTzuZCWF7NK9EwxphGmcBvCh6ybUuLxbG65nsX4JvD4SPNtkJ2w9ug1yLTj6fgmuDg41TgECXjLCij3RMsV8CwewBVgVN67wsA45DFWvqvLtu4rjNnE9JbdFTc1Z4WCPA3Xan44K1HoHAq9EVeaRYs8zoF5","client_ip":"138.197.138.255","client_port":9704,"node_ip":"138.197.138.255","node_port":9703,"services":["VALIDATOR"]},"dest":"8ECVSk179mjsjKRLWiQtssMLgp6EPhWXtaYyStWPSGAb"},"metadata":{"from":"EbP4aYNeTHL6q385GuVpRV"},"type":"0"},"txnMetadata":{"seqNo":2,"txnId":"1ac8aece2a18ced660fef8694b61aac3af08ba875ce3026a160acbc3a3af35fc"},"ver":"1"} diff --git a/src/cliAgent.ts b/src/cliAgent.ts index 61c671e7..d0a177bc 100644 --- a/src/cliAgent.ts +++ b/src/cliAgent.ts @@ -52,6 +52,8 @@ import { readFile } from 'fs/promises' import { IndicioAcceptanceMechanism, IndicioTransactionAuthorAgreement, Network, NetworkName } from './enums' import { setupServer } from './server' +import { isCustomDocumentLoaderEnabled } from './utils/config' +import { CustomDocumentLoader } from './utils/customDocumentLoader' import { generateSecretKey } from './utils/helpers' import { TsLogger } from './utils/logger' @@ -183,7 +185,11 @@ const getModules = ( }), ], }), - w3cCredentials: new W3cCredentialsModule(), + w3cCredentials: isCustomDocumentLoaderEnabled() + ? new W3cCredentialsModule() + : new W3cCredentialsModule({ + documentLoader: CustomDocumentLoader, + }), cache: new CacheModule({ cache: new InMemoryLruCache({ limit: Number(process.env.INMEMORY_LRU_CACHE_LIMIT) || Infinity }), }), diff --git a/src/utils/config.ts b/src/utils/config.ts new file mode 100644 index 00000000..0e336bff --- /dev/null +++ b/src/utils/config.ts @@ -0,0 +1,22 @@ +/* eslint-disable no-console */ +export const isCustomDocumentLoaderEnabled = (): boolean => { + const flag = process.env.ENABLE_CUSTOM_DOCUMENT_LOADER ?? 'false' + const isCustomDocumentLoaderEnabled = flag.toLowerCase() === 'true' + + if (isCustomDocumentLoaderEnabled) { + if (!process.env.DEPRECATED_DOMAIN || !process.env.CURRENT_DOMAIN) { + console.debug('Invalid configuration set for enabling custom document loader') + console.info( + "If you are unsure about what the error is about. Try setting the 'ENABLE_CUSTOM_DOCUMENT_LOADER' flag in the env variable to false", + ) + throw new Error( + `Custom document loader for the agent is enabled but the deprecated domain and updated domain is not set`, + ) + } + console.warn( + `Custom document loader for the agent is enabled. Resolution of all URLs from the deprecated domain(${process.env.DEPRECATED_DOMAIN}) will actually be resolved from the current, updated domain(${process.env.CURRENT_DOMAIN})`, + ) + } + + return isCustomDocumentLoaderEnabled +} diff --git a/src/utils/customDocumentLoader.ts b/src/utils/customDocumentLoader.ts new file mode 100644 index 00000000..c31a15f9 --- /dev/null +++ b/src/utils/customDocumentLoader.ts @@ -0,0 +1,47 @@ +import type { AgentContext, DocumentLoader } from '@credo-ts/core' +import type { DocumentLoaderResult } from '@credo-ts/core/build/modules/vc/data-integrity/jsonldUtil' + +import { CredoError } from '@credo-ts/core' +import { defaultDocumentLoader } from '@credo-ts/core/build/modules/vc/data-integrity/libraries/documentLoader' + +/** + * Check if URL belongs to CREDEBL schema domain + */ +function isW3CDeprecatedUrl(url: string, agentContext: AgentContext): boolean { + agentContext.config.logger.debug( + `Checking if w3c url(${url}) contains deprecated domain for agent: ${agentContext.config.label}`, + ) + return url.startsWith(process.env.DEPRECATED_DOMAIN!) +} + +/** + * For JSON-LD schemas replace deprecated domain to migrated/updated domain + */ +function replaceUrl(url: string, agent: AgentContext): string { + agent.config.logger.debug(`Replacing deprecated domain with updated domain`) + return url.replace(process.env.DEPRECATED_DOMAIN!, process.env.CURRENT_DOMAIN!) +} + +/** + * Custom loader that extends Credo's default loader + */ +export const CustomDocumentLoader = (agentContext: AgentContext): DocumentLoader => { + const defaultLoader = defaultDocumentLoader(agentContext) + + return async function (url: string): Promise { + try { + // Intercept credebl schemas + if (isW3CDeprecatedUrl(url, agentContext)) { + agentContext.config.logger.debug( + `Found w3c url(${url}) containing deprecated domain for agent: ${agentContext.config.label}`, + ) + url = replaceUrl(url, agentContext) + } + + agentContext.config.logger.debug(`Passing url(${url}) to default loader`) + return await defaultLoader(url) + } catch (error) { + throw new CredoError(`Failed to load document for ${url}`, { cause: error as Error }) + } + } +}