diff --git a/packages/legacy/core/App/components/misc/CredentialCard.tsx b/packages/legacy/core/App/components/misc/CredentialCard.tsx index 51ceed4234..467b4e870c 100644 --- a/packages/legacy/core/App/components/misc/CredentialCard.tsx +++ b/packages/legacy/core/App/components/misc/CredentialCard.tsx @@ -15,6 +15,7 @@ interface CredentialCardProps { credDefId?: string schemaId?: string proofCredDefId?: string + proofSchemaId?: string credName?: string onPress?: GenericFn style?: ViewStyle @@ -31,6 +32,7 @@ const CredentialCard: React.FC = ({ credDefId, schemaId, proofCredDefId, + proofSchemaId, proof, displayItems, credName, @@ -56,6 +58,7 @@ const CredentialCard: React.FC = ({ credDefId={credDefId} schemaId={schemaId} proofCredDefId={proofCredDefId} + proofSchemaId={proofSchemaId} credential={credential} handleAltCredChange={handleAltCredChange} hasAltCredentials={hasAltCredentials} diff --git a/packages/legacy/core/App/components/misc/CredentialCard11.tsx b/packages/legacy/core/App/components/misc/CredentialCard11.tsx index 3d141b110f..43b88031e3 100644 --- a/packages/legacy/core/App/components/misc/CredentialCard11.tsx +++ b/packages/legacy/core/App/components/misc/CredentialCard11.tsx @@ -34,6 +34,7 @@ interface CredentialCard11Props { credDefId?: string schemaId?: string proofCredDefId?: string + proofSchemaId?: string proof?: boolean hasAltCredentials?: boolean handleAltCredChange?: () => void @@ -80,6 +81,7 @@ const CredentialCard11: React.FC = ({ credDefId, schemaId, proofCredDefId, + proofSchemaId, proof, hasAltCredentials, handleAltCredChange, @@ -291,14 +293,25 @@ const CredentialCard11: React.FC = ({ }, [credential?.revocationNotification]) useEffect(() => { + if (!error) { + return + } + getCredentialHelpDictionary?.some((entry) => { if (proofCredDefId && entry.credDefIds.includes(proofCredDefId)) { setHelpAction(() => () => { entry.action(navigation) }) + return true + } + if (proofSchemaId && entry.schemaIds.includes(proofSchemaId)) { + setHelpAction(() => () => { + entry.action(navigation) + }) + return true } }) - }, [proofCredDefId]) + }, [proofCredDefId, proofSchemaId]) const CredentialCardLogo: React.FC = () => { return ( diff --git a/packages/legacy/core/App/screens/ProofRequest.tsx b/packages/legacy/core/App/screens/ProofRequest.tsx index 1d706957e3..29f648121f 100644 --- a/packages/legacy/core/App/screens/ProofRequest.tsx +++ b/packages/legacy/core/App/screens/ProofRequest.tsx @@ -544,6 +544,7 @@ const ProofRequest: React.FC = ({ navigation, route }) => { credDefId={item.credDefId} schemaId={item.schemaId} proofCredDefId={item.proofCredDefId} + proofSchemaId={item.proofSchemaId} displayItems={[ ...(item.attributes ?? []), ...evaluatePredicates(getCredentialsFields(), item.credId)(item), diff --git a/packages/legacy/core/App/types/get-credential-help.ts b/packages/legacy/core/App/types/get-credential-help.ts index 2e87ceb4d5..6ee3b317ab 100644 --- a/packages/legacy/core/App/types/get-credential-help.ts +++ b/packages/legacy/core/App/types/get-credential-help.ts @@ -8,5 +8,6 @@ export type GetCredentialHelpAction = ( export interface GetCredentialHelpEntry { credDefIds: string[] + schemaIds: string[] action: GetCredentialHelpAction } diff --git a/packages/legacy/core/App/types/proof-items.ts b/packages/legacy/core/App/types/proof-items.ts index 79ed412216..e163d9ba25 100644 --- a/packages/legacy/core/App/types/proof-items.ts +++ b/packages/legacy/core/App/types/proof-items.ts @@ -8,6 +8,7 @@ export interface ProofCredentialAttributes { credDefId?: string proofCredDefId?: string schemaId?: string + proofSchemaId?: string credName: string attributes?: Attribute[] } @@ -19,6 +20,7 @@ export interface ProofCredentialPredicates { credDefId?: string proofCredDefId?: string schemaId?: string + proofSchemaId?: string credName: string predicates?: Predicate[] } diff --git a/packages/legacy/core/App/utils/helpers.ts b/packages/legacy/core/App/utils/helpers.ts index 127b04f502..bfe72c3774 100644 --- a/packages/legacy/core/App/utils/helpers.ts +++ b/packages/legacy/core/App/utils/helpers.ts @@ -320,10 +320,23 @@ const credNameFromRestriction = (queries?: AnonCredsProofRequestRestriction[]): } } -const credDefIdFromRestrictions = (queries?: AnonCredsProofRequestRestriction[]): string => { +export const credDefIdFromRestrictions = (queries?: AnonCredsProofRequestRestriction[]): string => { return queries?.filter((rstr) => rstr.cred_def_id)[0]?.cred_def_id ?? '' } +export const schemaIdFromRestrictions = (queries?: AnonCredsProofRequestRestriction[]): string => { + const rstrWithSchemaId = queries?.filter( + (rstr) => rstr.schema_id || (rstr.issuer_did && rstr.schema_name && rstr.schema_version) + )[0] + + // the '2' here is the enum of the transaction type which, for schemas, is always 2 + const schemaId = rstrWithSchemaId + ? rstrWithSchemaId.schema_id || + `${rstrWithSchemaId.issuer_did}:2:${rstrWithSchemaId.schema_name}:${rstrWithSchemaId.schema_version}` + : '' + return schemaId +} + export const isDataUrl = (value: string | number | null) => { return typeof value === 'string' && value.startsWith('data:image/') } @@ -409,6 +422,7 @@ const addMissingDisplayAttributes = (attrReq: AnonCredsRequestedAttribute) => { const { name, names, restrictions } = attrReq const credName = credNameFromRestriction(restrictions) const proofCredDefId = credDefIdFromRestrictions(restrictions) + const proofSchemaId = schemaIdFromRestrictions(restrictions) //there is no credId in this context so use credName as a placeholder const processedAttributes: ProofCredentialAttributes = { @@ -419,6 +433,7 @@ const addMissingDisplayAttributes = (attrReq: AnonCredsRequestedAttribute) => { credDefId: undefined, credName: credName, proofCredDefId, + proofSchemaId, attributes: [] as Attribute[], } @@ -461,6 +476,7 @@ export const processProofAttributes = ( const { name, names, non_revoked, restrictions } = requestedProofAttributes[key] const proofCredDefId = credDefIdFromRestrictions(restrictions) + const proofSchemaId = schemaIdFromRestrictions(restrictions) if (credentialList.length <= 0) { const missingAttributes = addMissingDisplayAttributes(requestedProofAttributes[key]) @@ -500,6 +516,7 @@ export const processProofAttributes = ( schemaId: credential?.credentialInfo?.schemaId, credDefId: credential?.credentialInfo?.credentialDefinitionId, proofCredDefId, + proofSchemaId, credName, attributes: [], } @@ -550,6 +567,7 @@ const addMissingDisplayPredicates = (predReq: AnonCredsRequestedPredicate) => { const credName = credNameFromRestriction(restrictions) const proofCredDefId = credDefIdFromRestrictions(restrictions) + const proofSchemaId = schemaIdFromRestrictions(restrictions) //there is no credId in this context so use credName as a placeholder const processedPredicates: ProofCredentialPredicates = { @@ -559,6 +577,7 @@ const addMissingDisplayPredicates = (predReq: AnonCredsRequestedPredicate) => { schemaId: undefined, credDefId: undefined, proofCredDefId, + proofSchemaId, credName: credName, predicates: [] as Predicate[], } @@ -599,6 +618,7 @@ export const processProofPredicates = ( const credentialList = [...(retrievedCredentialPredicates[key] ?? [])].sort(credentialSortFn) const { name, p_type: pType, p_value: pValue, non_revoked, restrictions } = requestedProofPredicates[key] const proofCredDefId = credDefIdFromRestrictions(restrictions) + const proofSchemaId = schemaIdFromRestrictions(restrictions) if (credentialList.length <= 0) { const missingPredicates = addMissingDisplayPredicates(requestedProofPredicates[key]) @@ -640,6 +660,7 @@ export const processProofPredicates = ( schemaId, credDefId: credentialDefinitionId, proofCredDefId, + proofSchemaId, credName: credName, predicates: [], } diff --git a/packages/legacy/core/__tests__/components/CredentialCard11.test.tsx b/packages/legacy/core/__tests__/components/CredentialCard11.test.tsx index 3eb216f22a..5d2293782b 100644 --- a/packages/legacy/core/__tests__/components/CredentialCard11.test.tsx +++ b/packages/legacy/core/__tests__/components/CredentialCard11.test.tsx @@ -52,7 +52,6 @@ describe('CredentialCard11 component', () => { credential={credentialRecord} credDefId={'cred_def_id'} proof - proofCredDefId={'proof_cred_def'} error={false} handleAltCredChange={handleAltCredChange} hasAltCredentials @@ -68,14 +67,14 @@ describe('CredentialCard11 component', () => { expect(handleAltCredChange).toBeCalled() }) - test('Missing credential with help action', async () => { + test('Missing credential with help action (cred def ID)', async () => { const helpAction = jest.fn() const { findByTestId } = render( @@ -89,5 +88,27 @@ describe('CredentialCard11 component', () => { fireEvent(getThisCredentialButton, 'press') expect(helpAction).toBeCalled() }) + + test('Missing credential with help action (schema ID)', async () => { + const helpAction = jest.fn() + + const { findByTestId } = render( + + + + ) + + const getThisCredentialButton = await findByTestId(testIdWithKey('GetThisCredential')) + + expect(getThisCredentialButton).toBeTruthy() + + fireEvent(getThisCredentialButton, 'press') + expect(helpAction).toBeCalled() + }) }) }) diff --git a/packages/legacy/core/__tests__/utils/helpers.test.ts b/packages/legacy/core/__tests__/utils/helpers.test.ts index 9cf0b99194..07b6dbcbaa 100644 --- a/packages/legacy/core/__tests__/utils/helpers.test.ts +++ b/packages/legacy/core/__tests__/utils/helpers.test.ts @@ -11,6 +11,8 @@ import { getConnectionName, removeExistingInvitationIfRequired, connectFromInvitation, + credDefIdFromRestrictions, + schemaIdFromRestrictions, } from '../../App/utils/helpers' const proofCredentialPath = path.join(__dirname, '../fixtures/proof-credential.json') @@ -197,3 +199,63 @@ describe('getConnectionName', () => { expect(result).toBe('') }) }) + +describe('credDefIdFromRestrictions', () => { + test('With no cred_def_id in any restrictions', async () => { + const expected = '' + const restrictions = [{}, {}] + + const result = credDefIdFromRestrictions(restrictions) + expect(result).toBe(expected) + }) + + test('With cred_def_id in restriction', async () => { + const expected = 'cred_def_id' + const restrictions = [{ cred_def_id: expected }] + + const result = credDefIdFromRestrictions(restrictions) + expect(result).toBe(expected) + }) + + test('With cred_def_id in later restriction', async () => { + const expected = 'cred_def_id' + const restrictions = [{}, { cred_def_id: expected }] + + const result = credDefIdFromRestrictions(restrictions) + expect(result).toBe(expected) + }) +}) + +describe('schemaIdFromRestrictions', () => { + test('With no schema_id or schema ID subproperties in any restrictions', async () => { + const expected = '' + const restrictions = [{}, {}] + + const result = schemaIdFromRestrictions(restrictions) + expect(result).toBe(expected) + }) + + test('With schema_id in restriction', async () => { + const expected = 'schema_id' + const restrictions = [{}, { schema_id: expected }] + + const result = schemaIdFromRestrictions(restrictions) + expect(result).toBe(expected) + }) + + test('With all subproperties of schema ID in restriction', async () => { + const expected = 'abc123:2:Student Card:1.0' + const restrictions = [{ schema_name: 'Student Card', schema_version: '1.0', issuer_did: 'abc123' }] + + const result = schemaIdFromRestrictions(restrictions) + expect(result).toBe(expected) + }) + + test('With only some subproperties of schema ID in restriction', async () => { + const expected = '' + const restrictions = [{ schema_name: 'Student Card', issuer_did: 'abc123' }] + + const result = schemaIdFromRestrictions(restrictions) + expect(result).toBe(expected) + }) +})