From fe46e8fd58d51d969117128075f814fa5bf94772 Mon Sep 17 00:00:00 2001 From: Tom Lanser Date: Thu, 4 Jul 2024 18:30:06 +0200 Subject: [PATCH 1/3] feat: Merge anoncreds proof request credentials Signed-off-by: Tom Lanser --- .../hooks/useDidCommPresentationActions.ts | 46 +++++++++++++++---- 1 file changed, 38 insertions(+), 8 deletions(-) diff --git a/packages/agent/src/hooks/useDidCommPresentationActions.ts b/packages/agent/src/hooks/useDidCommPresentationActions.ts index 1331ffaf..c0e80418 100644 --- a/packages/agent/src/hooks/useDidCommPresentationActions.ts +++ b/packages/agent/src/hooks/useDidCommPresentationActions.ts @@ -16,6 +16,8 @@ import { filter, first, timeout } from 'rxjs/operators' import { useAgent } from '../agent' import { getDidCommCredentialExchangeDisplayMetadata } from '../didcomm/metadata' +type ProofedCredentialEntry = FormattedSubmission['entries'][number] + export function useDidCommPresentationActions(proofExchangeId: string) { const { agent } = useAgent() @@ -40,10 +42,22 @@ export function useDidCommPresentationActions(proofExchangeId: string) { throw new CredoError('Invalid proof request.') } - const submission: FormattedSubmission = { - areAllSatisfied: false, - entries: [], - name: proofRequest?.name ?? 'Unknown', + const entries = new Map() + const mergeOrSetEntry = (key: string, newEntry: ProofedCredentialEntry) => { + const entry = entries.get(key) + if (entry) { + entries.set(key, { + name: entry.name || newEntry.name, + backgroundColor: entry.backgroundColor || newEntry.backgroundColor, + description: entry.description || newEntry.description, + credentialName: entry.credentialName || newEntry.credentialName, + issuerName: entry.issuerName || newEntry.issuerName, + isSatisfied: entry.isSatisfied && newEntry.isSatisfied, // Check if both are true otherwise it's not satisfied + requestedAttributes: [...(entry.requestedAttributes ?? []), ...(newEntry.requestedAttributes ?? [])], + }) + } else { + entries.set(key, newEntry) + } } await Promise.all( @@ -54,8 +68,12 @@ export function useDidCommPresentationActions(proofExchangeId: string) { const firstMatch = attributeArray[0] + const credentialKey = groupName.includes('__CREDENTIAL__') + ? groupName.split('__CREDENTIAL__')[0] + : firstMatch?.credentialId ?? groupName + if (!firstMatch) { - submission.entries.push({ + mergeOrSetEntry(credentialKey, { credentialName: 'Credential', // TODO: we can extract this from the schema name, but we would have to fetch it isSatisfied: false, name: groupName, // TODO @@ -70,7 +88,7 @@ export function useDidCommPresentationActions(proofExchangeId: string) { ? getDidCommCredentialExchangeDisplayMetadata(credentialExchange) : undefined - submission.entries.push({ + mergeOrSetEntry(credentialKey, { name: groupName, // TODO: humanize string? Or should we let this out? credentialName: credentialDisplayMetadata?.credentialName ?? 'Credential', isSatisfied: true, @@ -94,8 +112,12 @@ export function useDidCommPresentationActions(proofExchangeId: string) { // This should probably be fixed in AFJ. const firstMatch = predicateArray[0] + const credentialKey = groupName.includes('__CREDENTIAL__') + ? groupName.split('__CREDENTIAL__')[0] + : firstMatch?.credentialId ?? groupName + if (!firstMatch) { - submission.entries.push({ + mergeOrSetEntry(credentialKey, { credentialName: 'Credential', // TODO: we can extract this from the schema name, but we would have to fetch it isSatisfied: false, name: groupName, // TODO @@ -110,7 +132,7 @@ export function useDidCommPresentationActions(proofExchangeId: string) { ? getDidCommCredentialExchangeDisplayMetadata(credentialExchange) : undefined - submission.entries.push({ + mergeOrSetEntry(credentialKey, { name: groupName, // TODO: humanize string? Or should we let this out? credentialName: credentialDisplayMetadata?.credentialName ?? 'Credential', isSatisfied: true, @@ -121,6 +143,14 @@ export function useDidCommPresentationActions(proofExchangeId: string) { }) ) + const entriesArray = Array.from(entries.values()) + + const submission: FormattedSubmission = { + areAllSatisfied: entriesArray.every((entry) => entry.isSatisfied), + entries: entriesArray, + name: proofRequest?.name ?? 'Unknown', + } + submission.areAllSatisfied = submission.entries.every((entry) => entry.isSatisfied) return submission From f718d555a9d957638e2874baa61c64252f22056c Mon Sep 17 00:00:00 2001 From: Tom Lanser Date: Thu, 11 Jul 2024 11:14:43 +0200 Subject: [PATCH 2/3] chore: Merge based on credentialId instead of custom logic Signed-off-by: Tom Lanser --- .../agent/src/hooks/useDidCommPresentationActions.ts | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/packages/agent/src/hooks/useDidCommPresentationActions.ts b/packages/agent/src/hooks/useDidCommPresentationActions.ts index c0e80418..a8bcac6f 100644 --- a/packages/agent/src/hooks/useDidCommPresentationActions.ts +++ b/packages/agent/src/hooks/useDidCommPresentationActions.ts @@ -68,9 +68,8 @@ export function useDidCommPresentationActions(proofExchangeId: string) { const firstMatch = attributeArray[0] - const credentialKey = groupName.includes('__CREDENTIAL__') - ? groupName.split('__CREDENTIAL__')[0] - : firstMatch?.credentialId ?? groupName + // When the credentialId isn't available, we use the groupName as the key but it will result in multiple entries in the view. But I think it's not an easy task to merge them + const credentialKey = firstMatch?.credentialId ?? groupName if (!firstMatch) { mergeOrSetEntry(credentialKey, { @@ -112,9 +111,8 @@ export function useDidCommPresentationActions(proofExchangeId: string) { // This should probably be fixed in AFJ. const firstMatch = predicateArray[0] - const credentialKey = groupName.includes('__CREDENTIAL__') - ? groupName.split('__CREDENTIAL__')[0] - : firstMatch?.credentialId ?? groupName + // When the credentialId isn't available, we use the groupName as the key but it will result in multiple entries in the view. But I think it's not an easy task to merge them + const credentialKey = firstMatch?.credentialId ?? groupName if (!firstMatch) { mergeOrSetEntry(credentialKey, { From 1fdb4866796715d3b8650dc4903572524bc193b3 Mon Sep 17 00:00:00 2001 From: Tom Lanser Date: Thu, 11 Jul 2024 15:32:45 +0200 Subject: [PATCH 3/3] chore: Brought back the custom logic Signed-off-by: Tom Lanser --- .../agent/src/hooks/useDidCommPresentationActions.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/agent/src/hooks/useDidCommPresentationActions.ts b/packages/agent/src/hooks/useDidCommPresentationActions.ts index a8bcac6f..a8898e29 100644 --- a/packages/agent/src/hooks/useDidCommPresentationActions.ts +++ b/packages/agent/src/hooks/useDidCommPresentationActions.ts @@ -68,8 +68,10 @@ export function useDidCommPresentationActions(proofExchangeId: string) { const firstMatch = attributeArray[0] - // When the credentialId isn't available, we use the groupName as the key but it will result in multiple entries in the view. But I think it's not an easy task to merge them - const credentialKey = firstMatch?.credentialId ?? groupName + // When the credentialId isn't available and there is no __CREDENTIAL__ in the groupName, we use the groupName as the key but it will result in multiple entries in the view. But I think it's not an easy task to merge them + const credentialKey = + firstMatch?.credentialId ?? + (groupName.includes('__CREDENTIAL__') ? groupName.split('__CREDENTIAL__')[0] : groupName) if (!firstMatch) { mergeOrSetEntry(credentialKey, { @@ -111,8 +113,10 @@ export function useDidCommPresentationActions(proofExchangeId: string) { // This should probably be fixed in AFJ. const firstMatch = predicateArray[0] - // When the credentialId isn't available, we use the groupName as the key but it will result in multiple entries in the view. But I think it's not an easy task to merge them - const credentialKey = firstMatch?.credentialId ?? groupName + // When the credentialId isn't available and there is no __CREDENTIAL__ in the groupName, we use the groupName as the key but it will result in multiple entries in the view. But I think it's not an easy task to merge them + const credentialKey = + firstMatch?.credentialId ?? + (groupName.includes('__CREDENTIAL__') ? groupName.split('__CREDENTIAL__')[0] : groupName) if (!firstMatch) { mergeOrSetEntry(credentialKey, {