Skip to content

Commit

Permalink
feat: filter retrieved credential by revocation state (#641)
Browse files Browse the repository at this point in the history
Signed-off-by: Timo Glastra <timo@animo.id>
  • Loading branch information
TimoGlastra committed Feb 16, 2022
1 parent c43cfaa commit 5912c0c
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 53 deletions.
Expand Up @@ -167,7 +167,7 @@ export class IndyRevocationService {

const revoked: boolean = revocationRegistryDelta.value.revoked?.includes(parseInt(credentialRevocationId)) || false
this.logger.trace(
`Credental with Credential Revocation Id '${credentialRevocationId}' is ${
`Credential with Credential Revocation Id '${credentialRevocationId}' is ${
revoked ? '' : 'not '
}revoked with revocation interval with to '${requestRevocationInterval.to}' & from '${
requestRevocationInterval.from
Expand Down
12 changes: 12 additions & 0 deletions packages/core/src/modules/proofs/ProofsModule.ts
Expand Up @@ -356,6 +356,7 @@ export class ProofsModule {

return this.proofService.getRequestedCredentialsForProofRequest(indyProofRequest, {
presentationProposal: presentationPreview,
filterByNonRevocationRequirements: config?.filterByNonRevocationRequirements ?? true,
})
}

Expand Down Expand Up @@ -476,6 +477,17 @@ export interface GetRequestedCredentialsConfig {
* Whether to filter the retrieved credentials using the presentation preview.
* This configuration will only have effect if a presentation proposal message is available
* containing a presentation preview.
*
* @default false
*/
filterByPresentationPreview?: boolean

/**
* Whether to filter the retrieved credentials using the non-revocation request in the proof request.
* This configuration will only have effect if the proof request requires proof on non-revocation of any kind.
* Default to true
*
* @default true
*/
filterByNonRevocationRequirements?: boolean
}
116 changes: 64 additions & 52 deletions packages/core/src/modules/proofs/services/ProofService.ts
Expand Up @@ -766,6 +766,7 @@ export class ProofService {
proofRequest: ProofRequest,
config: {
presentationProposal?: PresentationPreview
filterByNonRevocationRequirements?: boolean
} = {}
): Promise<RetrievedCredentials> {
const retrievedCredentials = new RetrievedCredentials({})
Expand Down Expand Up @@ -801,32 +802,11 @@ export class ProofService {

retrievedCredentials.requestedAttributes[referent] = await Promise.all(
credentialMatch.map(async (credential: Credential) => {
const requestNonRevoked = requestedAttribute.nonRevoked ?? proofRequest.nonRevoked
const credentialRevocationId = credential.credentialInfo.credentialRevocationId
const revocationRegistryId = credential.credentialInfo.revocationRegistryId
let revoked: boolean | undefined
let deltaTimestamp: number | undefined

// If revocation interval is present and the credential is revocable then fetch the revocation status of credentials for display
if (requestNonRevoked && credentialRevocationId && revocationRegistryId) {
this.logger.trace(
`Presentation is requesting proof of non revocation for referent '${referent}', getting revocation status for credential`,
{
requestNonRevoked,
credentialRevocationId,
revocationRegistryId,
}
)

// Note presentation from-to's vs ledger from-to's: https://github.com/hyperledger/indy-hipe/blob/master/text/0011-cred-revocation/README.md#indy-node-revocation-registry-intervals
const status = await this.indyRevocationService.getRevocationStatus(
credentialRevocationId,
revocationRegistryId,
requestNonRevoked
)
revoked = status.revoked
deltaTimestamp = status.deltaTimestamp
}
const { revoked, deltaTimestamp } = await this.getRevocationStatusForRequestedItem({
proofRequest,
requestedItem: requestedAttribute,
credential,
})

return new RequestedAttribute({
credentialId: credential.credentialInfo.referent,
Expand All @@ -837,39 +817,26 @@ export class ProofService {
})
})
)

// We only attach revoked state if non-revocation is requested. So if revoked is true it means
// the credential is not applicable to the proof request
if (config.filterByNonRevocationRequirements) {
retrievedCredentials.requestedAttributes[referent] = retrievedCredentials.requestedAttributes[referent].filter(
(r) => !r.revoked
)
}
}

for (const [referent, requestedPredicate] of proofRequest.requestedPredicates.entries()) {
const credentials = await this.getCredentialsForProofRequest(proofRequest, referent)

retrievedCredentials.requestedPredicates[referent] = await Promise.all(
credentials.map(async (credential) => {
const requestNonRevoked = requestedPredicate.nonRevoked ?? proofRequest.nonRevoked
const credentialRevocationId = credential.credentialInfo.credentialRevocationId
const revocationRegistryId = credential.credentialInfo.revocationRegistryId
let revoked: boolean | undefined
let deltaTimestamp: number | undefined

// If revocation interval is present and the credential is revocable then fetch the revocation status of credentials for display
if (requestNonRevoked && credentialRevocationId && revocationRegistryId) {
this.logger.trace(
`Presentation is requesting proof of non revocation for referent '${referent}', getting revocation status for credential`,
{
requestNonRevoked,
credentialRevocationId,
revocationRegistryId,
}
)

// Note presentation from-to's vs ledger from-to's: https://github.com/hyperledger/indy-hipe/blob/master/text/0011-cred-revocation/README.md#indy-node-revocation-registry-intervals
const status = await this.indyRevocationService.getRevocationStatus(
credentialRevocationId,
revocationRegistryId,
requestNonRevoked
)
revoked = status.revoked
deltaTimestamp = status.deltaTimestamp
}
const { revoked, deltaTimestamp } = await this.getRevocationStatusForRequestedItem({
proofRequest,
requestedItem: requestedPredicate,
credential,
})

return new RequestedPredicate({
credentialId: credential.credentialInfo.referent,
Expand All @@ -879,6 +846,14 @@ export class ProofService {
})
})
)

// We only attach revoked state if non-revocation is requested. So if revoked is true it means
// the credential is not applicable to the proof request
if (config.filterByNonRevocationRequirements) {
retrievedCredentials.requestedPredicates[referent] = retrievedCredentials.requestedPredicates[referent].filter(
(r) => !r.revoked
)
}
}

return retrievedCredentials
Expand Down Expand Up @@ -1067,6 +1042,43 @@ export class ProofService {
return JsonTransformer.fromJSON(credentialsJson, Credential) as unknown as Credential[]
}

private async getRevocationStatusForRequestedItem({
proofRequest,
requestedItem,
credential,
}: {
proofRequest: ProofRequest
requestedItem: ProofAttributeInfo | ProofPredicateInfo
credential: Credential
}) {
const requestNonRevoked = requestedItem.nonRevoked ?? proofRequest.nonRevoked
const credentialRevocationId = credential.credentialInfo.credentialRevocationId
const revocationRegistryId = credential.credentialInfo.revocationRegistryId

// If revocation interval is present and the credential is revocable then fetch the revocation status of credentials for display
if (requestNonRevoked && credentialRevocationId && revocationRegistryId) {
this.logger.trace(
`Presentation is requesting proof of non revocation, getting revocation status for credential`,
{
requestNonRevoked,
credentialRevocationId,
revocationRegistryId,
}
)

// Note presentation from-to's vs ledger from-to's: https://github.com/hyperledger/indy-hipe/blob/master/text/0011-cred-revocation/README.md#indy-node-revocation-registry-intervals
const status = await this.indyRevocationService.getRevocationStatus(
credentialRevocationId,
revocationRegistryId,
requestNonRevoked
)

return status
}

return { revoked: undefined, deltaTimestamp: undefined }
}

/**
* Update the record to a new state and emit an state changed event. Also updates the record
* in storage.
Expand Down

0 comments on commit 5912c0c

Please sign in to comment.