diff --git a/packages/anoncreds/src/formats/AnonCredsCredentialFormatService.ts b/packages/anoncreds/src/formats/AnonCredsCredentialFormatService.ts index efebabc26e..0d308f87b2 100644 --- a/packages/anoncreds/src/formats/AnonCredsCredentialFormatService.ts +++ b/packages/anoncreds/src/formats/AnonCredsCredentialFormatService.ts @@ -341,7 +341,7 @@ export class AnonCredsCredentialFormatService implements CredentialFormatService revocationStatusList = revocationStatusListResult.revocationStatusList } - const { credential } = await anonCredsIssuerService.createCredential(agentContext, { + const { credential, credentialRevocationId } = await anonCredsIssuerService.createCredential(agentContext, { credentialOffer, credentialRequest, credentialValues: convertAttributesToCredentialValues(credentialAttributes), @@ -350,6 +350,18 @@ export class AnonCredsCredentialFormatService implements CredentialFormatService revocationStatusList, }) + // If the credential is revocable, store the revocation identifiers in the credential record + if (credential.rev_reg_id) { + credentialRecord.metadata.add(AnonCredsCredentialMetadataKey, { + revocationRegistryId: revocationRegistryDefinitionId ?? undefined, + credentialRevocationId: credentialRevocationId ?? undefined, + }) + credentialRecord.setTags({ + anonCredsRevocationRegistryId: revocationRegistryDefinitionId, + anonCredsCredentialRevocationId: credentialRevocationId, + }) + } + const format = new CredentialFormatSpec({ attachmentId, format: ANONCREDS_CREDENTIAL, diff --git a/packages/anoncreds/src/formats/LegacyIndyCredentialFormatService.ts b/packages/anoncreds/src/formats/LegacyIndyCredentialFormatService.ts index 5a2d7b9592..07ead68328 100644 --- a/packages/anoncreds/src/formats/LegacyIndyCredentialFormatService.ts +++ b/packages/anoncreds/src/formats/LegacyIndyCredentialFormatService.ts @@ -300,23 +300,12 @@ export class LegacyIndyCredentialFormatService implements CredentialFormatServic const credentialRequest = requestAttachment.getDataAsJson() if (!credentialRequest) throw new CredoError('Missing indy credential request in createCredential') - const { credential, credentialRevocationId } = await anonCredsIssuerService.createCredential(agentContext, { + const { credential } = await anonCredsIssuerService.createCredential(agentContext, { credentialOffer, credentialRequest, credentialValues: convertAttributesToCredentialValues(credentialAttributes), }) - if (credential.rev_reg_id) { - credentialRecord.metadata.add(AnonCredsCredentialMetadataKey, { - credentialRevocationId: credentialRevocationId, - revocationRegistryId: credential.rev_reg_id, - }) - credentialRecord.setTags({ - anonCredsRevocationRegistryId: credential.rev_reg_id, - anonCredsCredentialRevocationId: credentialRevocationId, - }) - } - const format = new CredentialFormatSpec({ attachmentId, format: INDY_CRED, @@ -399,6 +388,7 @@ export class LegacyIndyCredentialFormatService implements CredentialFormatServic }) credentialRecord.setTags({ anonCredsRevocationRegistryId: credential.revocationRegistryId, + anonCredsUnqualifiedRevocationRegistryId: anonCredsCredential.rev_reg_id, anonCredsCredentialRevocationId: credential.credentialRevocationId, }) } diff --git a/packages/anoncreds/src/updates/0.4-0.5/anonCredsCredentialRecord.ts b/packages/anoncreds/src/updates/0.4-0.5/anonCredsCredentialRecord.ts index c55972500d..6c2791ca40 100644 --- a/packages/anoncreds/src/updates/0.4-0.5/anonCredsCredentialRecord.ts +++ b/packages/anoncreds/src/updates/0.4-0.5/anonCredsCredentialRecord.ts @@ -16,6 +16,7 @@ import { fetchCredentialDefinition } from '../../utils/anonCredsObjects' import { getIndyNamespaceFromIndyDid, getQualifiedDidIndyDid, + getUnQualifiedDidIndyDid, isIndyDid, isUnqualifiedCredentialDefinitionId, isUnqualifiedIndyDid, @@ -154,6 +155,16 @@ async function migrateLegacyToW3cCredential(agentContext: AgentContext, legacyRe credentialRecordType: 'w3c', credentialRecordId: w3cCredentialRecord.id, } + + // If using unqualified dids, store both qualified/unqualified revRegId forms + // to allow retrieving it from revocation notification service + if (legacyTags.revocationRegistryId && indyNamespace) { + relatedCredentialExchangeRecord.setTags({ + anonCredsRevocationRegistryId: getQualifiedDidIndyDid(legacyTags.revocationRegistryId, indyNamespace), + anonCredsUnqualifiedRevocationRegistryId: getUnQualifiedDidIndyDid(legacyTags.revocationRegistryId), + }) + } + await credentialExchangeRepository.update(agentContext, relatedCredentialExchangeRecord) } } diff --git a/packages/anoncreds/src/utils/indyIdentifiers.ts b/packages/anoncreds/src/utils/indyIdentifiers.ts index 6b957bfc5d..c31d26b03e 100644 --- a/packages/anoncreds/src/utils/indyIdentifiers.ts +++ b/packages/anoncreds/src/utils/indyIdentifiers.ts @@ -221,6 +221,8 @@ export function getIndyNamespaceFromIndyDid(identifier: string): string { } export function getUnQualifiedDidIndyDid(identifier: string): string { + if (isUnqualifiedIndyDid(identifier)) return identifier + if (isDidIndySchemaId(identifier)) { const { schemaName, schemaVersion, namespaceIdentifier } = parseIndySchemaId(identifier) return getUnqualifiedSchemaId(namespaceIdentifier, schemaName, schemaVersion) diff --git a/packages/anoncreds/src/utils/w3cAnonCredsUtils.ts b/packages/anoncreds/src/utils/w3cAnonCredsUtils.ts index fe9bfa0c58..550a97c3f3 100644 --- a/packages/anoncreds/src/utils/w3cAnonCredsUtils.ts +++ b/packages/anoncreds/src/utils/w3cAnonCredsUtils.ts @@ -20,6 +20,7 @@ import { isUnqualifiedRevocationRegistryId, isIndyDid, getUnQualifiedDidIndyDid, + isUnqualifiedIndyDid, } from './indyIdentifiers' import { W3cAnonCredsCredentialMetadataKey } from './metadata' @@ -199,7 +200,7 @@ export function getW3cRecordAnonCredsTags(options: { anonCredsMethodName: methodName, anonCredsRevocationRegistryId: revocationRegistryId, anonCredsCredentialRevocationId: credentialRevocationId, - ...(isIndyDid(issuerId) && { + ...((isIndyDid(issuerId) || isUnqualifiedIndyDid(issuerId)) && { anonCredsUnqualifiedIssuerId: getUnQualifiedDidIndyDid(issuerId), anonCredsUnqualifiedCredentialDefinitionId: getUnQualifiedDidIndyDid(credentialDefinitionId), anonCredsUnqualifiedSchemaId: getUnQualifiedDidIndyDid(schemaId), diff --git a/packages/core/src/modules/credentials/protocol/revocation-notification/services/RevocationNotificationService.ts b/packages/core/src/modules/credentials/protocol/revocation-notification/services/RevocationNotificationService.ts index 97b2afec14..ff0a1dd4b0 100644 --- a/packages/core/src/modules/credentials/protocol/revocation-notification/services/RevocationNotificationService.ts +++ b/packages/core/src/modules/credentials/protocol/revocation-notification/services/RevocationNotificationService.ts @@ -51,7 +51,21 @@ export class RevocationNotificationService { comment?: string ) { // TODO: can we extract support for this revocation notification handler to the anoncreds module? - const query = { anonCredsRevocationRegistryId, anonCredsCredentialRevocationId, connectionId: connection.id } + // Search for the revocation registry in both qualified and unqualified forms + const query = { + $or: [ + { + anonCredsRevocationRegistryId, + anonCredsCredentialRevocationId, + connectionId: connection.id, + }, + { + anonCredsUnqualifiedRevocationRegistryId: anonCredsRevocationRegistryId, + anonCredsCredentialRevocationId, + connectionId: connection.id, + }, + ], + } this.logger.trace(`Getting record by query for revocation notification:`, query) const credentialRecord = await this.credentialRepository.getSingleByQuery(agentContext, query) diff --git a/packages/core/src/modules/credentials/protocol/revocation-notification/services/__tests__/RevocationNotificationService.test.ts b/packages/core/src/modules/credentials/protocol/revocation-notification/services/__tests__/RevocationNotificationService.test.ts index abd50e160b..d8c545a0fc 100644 --- a/packages/core/src/modules/credentials/protocol/revocation-notification/services/__tests__/RevocationNotificationService.test.ts +++ b/packages/core/src/modules/credentials/protocol/revocation-notification/services/__tests__/RevocationNotificationService.test.ts @@ -78,7 +78,7 @@ describe('RevocationNotificationService', () => { } satisfies AnonCredsCredentialMetadata // Set required tags - credentialRecord.setTag('anonCredsRevocationRegistryId', metadata.revocationRegistryId) + credentialRecord.setTag('anonCredsUnqualifiedRevocationRegistryId', metadata.revocationRegistryId) credentialRecord.setTag('anonCredsCredentialRevocationId', metadata.credentialRevocationId) mockFunction(credentialRepository.getSingleByQuery).mockResolvedValueOnce(credentialRecord)