Skip to content

Commit

Permalink
feat(proofs): sort credentials based on revocation (#1225)
Browse files Browse the repository at this point in the history
Signed-off-by: Timo Glastra <[email protected]>
  • Loading branch information
TimoGlastra authored Jan 20, 2023
1 parent 25b2bcf commit 0f6d231
Show file tree
Hide file tree
Showing 3 changed files with 115 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ import {
import { ProofRequest } from './models/ProofRequest'
import { RequestedCredentials } from './models/RequestedCredentials'
import { RetrievedCredentials } from './models/RetrievedCredentials'
import { sortRequestedCredentials } from './util/sortRequestedCredentials'

@scoped(Lifecycle.ContainerScoped)
export class IndyProofFormatService extends ProofFormatService {
Expand Down Expand Up @@ -424,22 +425,24 @@ export class IndyProofFormatService extends ProofFormatService {
})
}

retrievedCredentials.requestedAttributes[referent] = await Promise.all(
credentialMatch.map(async (credential: IndyCredential) => {
const { revoked, deltaTimestamp } = await this.getRevocationStatusForRequestedItem(agentContext, {
proofRequest,
requestedItem: requestedAttribute,
credential,
retrievedCredentials.requestedAttributes[referent] = sortRequestedCredentials(
await Promise.all(
credentialMatch.map(async (credential: IndyCredential) => {
const { revoked, deltaTimestamp } = await this.getRevocationStatusForRequestedItem(agentContext, {
proofRequest,
requestedItem: requestedAttribute,
credential,
})

return new RequestedAttribute({
credentialId: credential.credentialInfo.referent,
revealed: true,
credentialInfo: credential.credentialInfo,
timestamp: deltaTimestamp,
revoked,
})
})

return new RequestedAttribute({
credentialId: credential.credentialInfo.referent,
revealed: true,
credentialInfo: credential.credentialInfo,
timestamp: deltaTimestamp,
revoked,
})
})
)
)

// We only attach revoked state if non-revocation is requested. So if revoked is true it means
Expand All @@ -454,21 +457,23 @@ export class IndyProofFormatService extends ProofFormatService {
for (const [referent, requestedPredicate] of proofRequest.requestedPredicates.entries()) {
const credentials = await this.getCredentialsForProofRequest(agentContext, proofRequest, referent)

retrievedCredentials.requestedPredicates[referent] = await Promise.all(
credentials.map(async (credential) => {
const { revoked, deltaTimestamp } = await this.getRevocationStatusForRequestedItem(agentContext, {
proofRequest,
requestedItem: requestedPredicate,
credential,
retrievedCredentials.requestedPredicates[referent] = sortRequestedCredentials(
await Promise.all(
credentials.map(async (credential) => {
const { revoked, deltaTimestamp } = await this.getRevocationStatusForRequestedItem(agentContext, {
proofRequest,
requestedItem: requestedPredicate,
credential,
})

return new RequestedPredicate({
credentialId: credential.credentialInfo.referent,
credentialInfo: credential.credentialInfo,
timestamp: deltaTimestamp,
revoked,
})
})

return new RequestedPredicate({
credentialId: credential.credentialInfo.referent,
credentialInfo: credential.credentialInfo,
timestamp: deltaTimestamp,
revoked,
})
})
)
)

// We only attach revoked state if non-revocation is requested. So if revoked is true it means
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { RequestedAttribute } from '../../models'
import { sortRequestedCredentials } from '../sortRequestedCredentials'

const credentials = [
new RequestedAttribute({
credentialId: '1',
revealed: true,
revoked: true,
}),
new RequestedAttribute({
credentialId: '2',
revealed: true,
revoked: undefined,
}),
new RequestedAttribute({
credentialId: '3',
revealed: true,
revoked: false,
}),
new RequestedAttribute({
credentialId: '4',
revealed: true,
revoked: false,
}),
new RequestedAttribute({
credentialId: '5',
revealed: true,
revoked: true,
}),
new RequestedAttribute({
credentialId: '6',
revealed: true,
revoked: undefined,
}),
]

describe('sortRequestedCredentials', () => {
test('sorts the credentials', () => {
expect(sortRequestedCredentials(credentials)).toEqual([
credentials[1],
credentials[5],
credentials[2],
credentials[3],
credentials[0],
credentials[4],
])
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import type { RequestedAttribute, RequestedPredicate } from '../models'

/**
* Sort requested attributes and predicates by `revoked` status. The order is:
* - first credentials with `revoked` set to undefined, this means no revocation status is needed for the credentials
* - then credentials with `revoked` set to false, this means the credentials are not revoked
* - then credentials with `revoked` set to true, this means the credentials are revoked
*/
export function sortRequestedCredentials<Requested extends Array<RequestedAttribute> | Array<RequestedPredicate>>(
credentials: Requested
) {
const staySame = 0
const credentialGoUp = -1
const credentialGoDown = 1

// Clone as sort is in place
const credentialsClone = [...credentials]

return credentialsClone.sort((credential, compareTo) => {
// Nothing needs to happen if values are the same
if (credential.revoked === compareTo.revoked) return staySame

// Undefined always is at the top
if (credential.revoked === undefined) return credentialGoUp
if (compareTo.revoked === undefined) return credentialGoDown

// Then revoked
if (credential.revoked === false) return credentialGoUp

// It means that compareTo is false and credential is true
return credentialGoDown
})
}

0 comments on commit 0f6d231

Please sign in to comment.