Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: AnonCreds proof requests with unqualified dids #1891

15 changes: 11 additions & 4 deletions packages/anoncreds/src/anoncreds-rs/AnonCredsRsHolderService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ import {
} from '../utils/indyIdentifiers'
import { assertLinkSecretsMatch, getLinkSecret } from '../utils/linkSecret'
import { W3cAnonCredsCredentialMetadataKey } from '../utils/metadata'
import { proofRequestUsesUnqualifiedIdentifiers } from '../utils/proofRequest'
import { getAnoncredsCredentialInfoFromRecord, getW3cRecordAnonCredsTags } from '../utils/w3cAnonCredsUtils'

import { getRevocationMetadata } from './utils'
Expand Down Expand Up @@ -142,8 +143,10 @@ export class AnonCredsRsHolderService implements AnonCredsHolderService {
}
}

const { linkSecretId, revocationRegistryId, credentialRevocationId } =
getAnoncredsCredentialInfoFromRecord(credentialRecord)
const { linkSecretId, revocationRegistryId, credentialRevocationId } = getAnoncredsCredentialInfoFromRecord(
credentialRecord,
proofRequestUsesUnqualifiedIdentifiers(proofRequest)
)

// TODO: Check if credential has a revocation registry id (check response from anoncreds-rs API, as it is
// sending back a mandatory string in Credential.revocationRegistryId)
Expand Down Expand Up @@ -495,7 +498,9 @@ export class AnonCredsRsHolderService implements AnonCredsHolderService {
): Promise<AnonCredsCredentialInfo> {
const w3cCredentialRepository = agentContext.dependencyManager.resolve(W3cCredentialRepository)
const w3cCredentialRecord = await w3cCredentialRepository.findById(agentContext, options.id)
if (w3cCredentialRecord) return getAnoncredsCredentialInfoFromRecord(w3cCredentialRecord)
if (w3cCredentialRecord) {
return getAnoncredsCredentialInfoFromRecord(w3cCredentialRecord, options.useUnqualifiedIdentifiersIfPresent)
}

const anonCredsCredentialRepository = agentContext.dependencyManager.resolve(AnonCredsCredentialRepository)
const anonCredsCredentialRecord = await anonCredsCredentialRepository.getByCredentialId(agentContext, options.id)
Expand Down Expand Up @@ -653,6 +658,8 @@ export class AnonCredsRsHolderService implements AnonCredsHolderService {

const $and = []

const useUnqualifiedIdentifiers = proofRequestUsesUnqualifiedIdentifiers(proofRequest)

// Make sure the attribute(s) that are requested are present using the marker tag
const attributes = requestedAttribute.names ?? [requestedAttribute.name]
const attributeQuery: SimpleQuery<W3cCredentialRecord> = {}
Expand Down Expand Up @@ -689,7 +696,7 @@ export class AnonCredsRsHolderService implements AnonCredsHolderService {

const credentialWithMetadata = credentials.map((credentialRecord) => {
return {
credentialInfo: getAnoncredsCredentialInfoFromRecord(credentialRecord),
credentialInfo: getAnoncredsCredentialInfoFromRecord(credentialRecord, useUnqualifiedIdentifiers),
interval: proofRequest.non_revoked,
}
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export interface CreateProofOptions {
schemas: AnonCredsSchemas
credentialDefinitions: AnonCredsCredentialDefinitions
revocationRegistries: AnonCredsRevocationRegistries
useUnqualifiedIdentifiers?: boolean
}

export interface StoreCredentialOptions {
Expand All @@ -48,6 +49,7 @@ export interface StoreCredentialOptions {

export interface GetCredentialOptions {
id: string
useUnqualifiedIdentifiersIfPresent?: boolean
}

export interface GetCredentialsOptions {
Expand Down
24 changes: 24 additions & 0 deletions packages/anoncreds/src/utils/proofRequest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import type { AnonCredsProofRequest } from '../models/exchange'

import {
isUnqualifiedCredentialDefinitionId,
isUnqualifiedSchemaId,
isUnqualifiedIndyDid,
isUnqualifiedRevocationRegistryId,
} from './indyIdentifiers'

export function proofRequestUsesUnqualifiedIdentifiers(proofRequest: AnonCredsProofRequest) {
// We assume that if any identifier is unqualified, all of them are unqualified as well
return Object.values(proofRequest.requested_attributes).some((attribute) =>
attribute.restrictions?.some(
(restriction) =>
(restriction.cred_def_id && isUnqualifiedCredentialDefinitionId(restriction.cred_def_id)) ||
(restriction.schema_id && isUnqualifiedSchemaId(restriction.schema_id)) ||
(restriction.issuer_did && isUnqualifiedIndyDid(restriction.issuer_did)) ||
(restriction.issuer_id && isUnqualifiedIndyDid(restriction.issuer_id)) ||
(restriction.schema_issuer_did && isUnqualifiedIndyDid(restriction.schema_issuer_did)) ||
(restriction.schema_issuer_id && isUnqualifiedIndyDid(restriction.schema_issuer_id)) ||
(restriction.rev_reg_id && isUnqualifiedRevocationRegistryId(restriction.rev_reg_id))
)
)
}
31 changes: 25 additions & 6 deletions packages/anoncreds/src/utils/w3cAnonCredsUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,10 @@ export type AnonCredsCredentialTags = {
anonCredsUnqualifiedRevocationRegistryId?: string
}

function anonCredsCredentialInfoFromW3cRecord(w3cCredentialRecord: W3cCredentialRecord): AnonCredsCredentialInfo {
function anonCredsCredentialInfoFromW3cRecord(
w3cCredentialRecord: W3cCredentialRecord,
useUnqualifiedIdentifiers?: boolean
): AnonCredsCredentialInfo {
if (Array.isArray(w3cCredentialRecord.credential.credentialSubject)) {
throw new CredoError('Credential subject must be an object, not an array.')
}
Expand All @@ -61,13 +64,28 @@ function anonCredsCredentialInfoFromW3cRecord(w3cCredentialRecord: W3cCredential
)
if (!anonCredsCredentialMetadata) throw new CredoError('AnonCreds metadata not found on credential record.')

const credentialDefinitionId =
useUnqualifiedIdentifiers && anonCredsTags.anonCredsUnqualifiedCredentialDefinitionId
? anonCredsTags.anonCredsUnqualifiedCredentialDefinitionId
: anonCredsTags.anonCredsCredentialDefinitionId

const schemaId =
useUnqualifiedIdentifiers && anonCredsTags.anonCredsUnqualifiedSchemaId
? anonCredsTags.anonCredsUnqualifiedSchemaId
: anonCredsTags.anonCredsSchemaId

const revocationRegistryId =
useUnqualifiedIdentifiers && anonCredsTags.anonCredsUnqualifiedRevocationRegistryId
? anonCredsTags.anonCredsUnqualifiedRevocationRegistryId
: anonCredsTags.anonCredsRevocationRegistryId ?? null

return {
attributes: (w3cCredentialRecord.credential.credentialSubject.claims as AnonCredsClaimRecord) ?? {},
credentialId: w3cCredentialRecord.id,
credentialDefinitionId: anonCredsTags.anonCredsCredentialDefinitionId,
schemaId: anonCredsTags.anonCredsSchemaId,
credentialDefinitionId,
schemaId,
revocationRegistryId,
credentialRevocationId: anonCredsCredentialMetadata.credentialRevocationId ?? null,
revocationRegistryId: anonCredsTags.anonCredsRevocationRegistryId ?? null,
methodName: anonCredsCredentialMetadata.methodName,
linkSecretId: anonCredsCredentialMetadata.linkSecretId,
createdAt: w3cCredentialRecord.createdAt,
Expand Down Expand Up @@ -98,10 +116,11 @@ function anonCredsCredentialInfoFromAnonCredsRecord(
}

export function getAnoncredsCredentialInfoFromRecord(
credentialRecord: W3cCredentialRecord | AnonCredsCredentialRecord
credentialRecord: W3cCredentialRecord | AnonCredsCredentialRecord,
useUnqualifiedIdentifiersIfPresent?: boolean
): AnonCredsCredentialInfo {
if (credentialRecord instanceof W3cCredentialRecord) {
return anonCredsCredentialInfoFromW3cRecord(credentialRecord)
return anonCredsCredentialInfoFromW3cRecord(credentialRecord, useUnqualifiedIdentifiersIfPresent)
} else {
return anonCredsCredentialInfoFromAnonCredsRecord(credentialRecord)
}
Expand Down
Loading
Loading