Skip to content

Commit

Permalink
feat: presentation exchange (#201)
Browse files Browse the repository at this point in the history
* feat: presentation exchange wip

Signed-off-by: Sai Ranjit Tummalapalli <[email protected]>

* fix: wallet naming navigation

Signed-off-by: Sai Ranjit Tummalapalli <[email protected]>

* feat: w3c verification

Signed-off-by: Sai Ranjit Tummalapalli <[email protected]>

* refactor: get connection label from credential

Signed-off-by: Sai Ranjit Tummalapalli <[email protected]>

---------

Signed-off-by: Sai Ranjit Tummalapalli <[email protected]>
  • Loading branch information
sairanjit authored Jun 24, 2024
1 parent f728ca6 commit 8768578
Show file tree
Hide file tree
Showing 19 changed files with 893 additions and 45 deletions.
34 changes: 30 additions & 4 deletions app/components/listItems/NotificationListItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import {
declineProofRequest as declineProof,
getProofRequestAgentMessage,
} from '@adeya/ssi'
// eslint-disable-next-line import/no-extraneous-dependencies
import { V2RequestPresentationMessage } from '@credo-ts/core'
import { useNavigation } from '@react-navigation/core'
import { StackNavigationProp } from '@react-navigation/stack'
import React, { useState, useEffect } from 'react'
Expand Down Expand Up @@ -67,6 +69,7 @@ const NotificationListItem: React.FC<NotificationListItemProps> = ({ notificatio
const { ColorPallet, TextTheme } = useTheme()
const { agent } = useAppAgent()
const [declineModalVisible, setDeclineModalVisible] = useState(false)
const [notificationDetails, setNotificationDetails] = useState<V2RequestPresentationMessage | null>(null)
const [details, setDetails] = useState<DisplayDetails>({
type: InfoBoxType.Info,
title: undefined,
Expand Down Expand Up @@ -215,13 +218,25 @@ const NotificationListItem: React.FC<NotificationListItemProps> = ({ notificatio
case NotificationType.ProofRequest: {
const proofId = (notification as ProofExchangeRecord).id
getProofRequestAgentMessage(agent, proofId).then(message => {
setNotificationDetails(message)
if (message instanceof V1RequestPresentationMessage && message.indyProofRequest) {
resolve({
type: InfoBoxType.Info,
title: t('ProofRequest.NewProofRequest'),
body: message.indyProofRequest.name,
buttonTitle: undefined,
})
} else if (
message instanceof V2RequestPresentationMessage &&
message?.formats?.length > 0 &&
message?.formats[0].format.includes('dif/presentation-exchange')
) {
resolve({
type: InfoBoxType.Info,
title: t('ProofRequest.NewProofRequest'),
body: message?.requestAttachments[0]?.data?.json?.presentation_definition?.name ?? 'Proof Request',
buttonTitle: undefined,
})
} else {
//TODO:(jl) Should we have a default message or stick with an empty string?
resolve({
Expand Down Expand Up @@ -277,10 +292,21 @@ const NotificationListItem: React.FC<NotificationListItemProps> = ({ notificatio
}
} else {
onPress = () => {
navigation.getParent()?.navigate(Stacks.NotificationStack, {
screen: Screens.ProofRequest,
params: { proofId: (notification as ProofExchangeRecord).id },
})
// Added this check to navigate to different screen if proof request is of presentation exchange format
if (
notificationDetails?.formats?.length > 0 &&
notificationDetails?.formats[0].format.includes('dif/presentation-exchange')
) {
navigation.getParent()?.navigate(Stacks.NotificationStack, {
screen: Screens.ProofRequestW3C,
params: { proofId: (notification as ProofExchangeRecord).id },
})
} else {
navigation.getParent()?.navigate(Stacks.NotificationStack, {
screen: Screens.ProofRequest,
params: { proofId: (notification as ProofExchangeRecord).id },
})
}
}
}
onClose = toggleDeclineModalVisible
Expand Down
5 changes: 3 additions & 2 deletions app/components/misc/CredentialCard10.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { CredentialExchangeRecord } from '@adeya/ssi'
import { CredentialExchangeRecord, useConnections } from '@adeya/ssi'
import { LegacyBrandingOverlay } from '@hyperledger/aries-oca'
import { CredentialOverlay } from '@hyperledger/aries-oca/build/legacy'
import React, { useEffect, useState } from 'react'
Expand Down Expand Up @@ -75,7 +75,8 @@ const CredentialCard10: React.FC<CredentialCard10Props> = ({ credential, style =
const { OCABundleResolver } = useConfiguration()
const [overlay, setOverlay] = useState<CredentialOverlay<LegacyBrandingOverlay>>({})
const [isRevoked, setIsRevoked] = useState<boolean>(false)
const credentialConnectionLabel = getCredentialConnectionLabel(credential)
const { records } = useConnections()
const credentialConnectionLabel = getCredentialConnectionLabel(records, credential)

const styles = StyleSheet.create({
container: {
Expand Down
5 changes: 3 additions & 2 deletions app/components/misc/CredentialCard11.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { CredentialExchangeRecord } from '@adeya/ssi'
import { CredentialExchangeRecord, useConnections } from '@adeya/ssi'
import { BrandingOverlay } from '@hyperledger/aries-oca'
import { Attribute, CredentialOverlay, Predicate } from '@hyperledger/aries-oca/build/legacy'
import startCase from 'lodash.startcase'
Expand Down Expand Up @@ -91,7 +91,8 @@ const CredentialCard11: React.FC<CredentialCard11Props> = ({
const { ColorPallet, TextTheme, ListItems } = useTheme()
const { OCABundleResolver } = useConfiguration()
const [isRevoked, setIsRevoked] = useState<boolean>(credential?.revocationNotification !== undefined)
const credentialConnectionLabel = getCredentialConnectionLabel(credential, connectionLabel)
const { records } = useConnections()
const credentialConnectionLabel = getCredentialConnectionLabel(records, credential, connectionLabel)
const [isProofRevoked, setIsProofRevoked] = useState<boolean>(
credential?.revocationNotification !== undefined && !!proof,
)
Expand Down
1 change: 1 addition & 0 deletions app/localization/en/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -566,6 +566,7 @@ const translation = {
"Explore": "Explore",
"OrganizationDetails": "Organization Details",
"ProofChangeCredential": "Choose a credential",
"ProofChangeCredentialW3C": "Choose a W3C credential",
"DataRetention": "Data retention",
"Organization": "Explore",
"OrganizationConnection": "Connection"
Expand Down
6 changes: 6 additions & 0 deletions app/navigators/ContactStack.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import Home from '../screens/Home'
import ListContacts from '../screens/ListContacts'
import ProofDetails from '../screens/ProofDetails'
import ProofRequest from '../screens/ProofRequest'
import ProofRequestW3C from '../screens/ProofRequestW3C'
import WhatAreContacts from '../screens/WhatAreContacts'
import { ContactStackParams, Screens } from '../types/navigators'
import { testIdWithKey } from '../utils/testable'
Expand Down Expand Up @@ -81,6 +82,11 @@ const ContactStack: React.FC = () => {
component={ProofRequest}
options={{ title: t('Screens.ProofRequest') }}
/>
<Stack.Screen
name={Screens.ProofRequestW3C}
component={ProofRequestW3C}
options={{ title: t('Screens.ProofRequest') }}
/>
<Stack.Screen
name={Screens.ConnectionInvitation}
component={ConnectionInvitation}
Expand Down
6 changes: 6 additions & 0 deletions app/navigators/DeliveryStack.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import Connection from '../screens/Connection'
import ContactDetails from '../screens/ContactDetails'
import CredentialOffer from '../screens/CredentialOffer'
import ProofRequest from '../screens/ProofRequest'
import ProofRequestW3C from '../screens/ProofRequestW3C'
import { DeliveryStackParams, Screens, TabStacks } from '../types/navigators'
import { testIdWithKey } from '../utils/testable'

Expand Down Expand Up @@ -38,6 +39,11 @@ const DeliveryStack: React.FC = () => {
component={ProofRequest}
options={{ title: t('Screens.ProofRequest') }}
/>
<Stack.Screen
name={Screens.ProofRequestW3C}
component={ProofRequestW3C}
options={{ title: t('Screens.ProofRequest') }}
/>
<Stack.Screen
name={Screens.CredentialOffer}
component={CredentialOffer}
Expand Down
6 changes: 6 additions & 0 deletions app/navigators/NotificationStack.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { useTheme } from '../contexts/theme'
import CredentialDetails from '../screens/CredentialDetails'
import CredentialOffer from '../screens/CredentialOffer'
import ProofRequest from '../screens/ProofRequest'
import ProofRequestW3C from '../screens/ProofRequestW3C'
import { NotificationStackParams, Screens } from '../types/navigators'

import { createDefaultStackOptions } from './defaultStackOptions'
Expand Down Expand Up @@ -35,6 +36,11 @@ const NotificationStack: React.FC = () => {
component={ProofRequest}
options={{ title: t('Screens.ProofRequest') }}
/>
<Stack.Screen
name={Screens.ProofRequestW3C}
component={ProofRequestW3C}
options={{ title: t('Screens.ProofRequest') }}
/>
<Stack.Screen
name={Screens.CustomNotification}
component={customNotification.component}
Expand Down
6 changes: 6 additions & 0 deletions app/navigators/ProofRequestStack.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import HeaderRightHome from '../components/buttons/HeaderHome'
import { useTheme } from '../contexts/theme'
import ListProofRequests from '../screens/ListProofRequests'
import ProofChangeCredential from '../screens/ProofChangeCredential'
import ProofChangeCredentialW3C from '../screens/ProofChangeCredentialW3C'
import ProofDetails from '../screens/ProofDetails'
import ProofRequestDetails from '../screens/ProofRequestDetails'
import ProofRequestUsageHistory from '../screens/ProofRequestUsageHistory'
Expand Down Expand Up @@ -41,6 +42,11 @@ const ProofRequestStack: React.FC = () => {
component={ProofChangeCredential}
options={{ title: t('Screens.ProofChangeCredential') }}
/>
<Stack.Screen
name={Screens.ProofChangeCredentialW3C}
component={ProofChangeCredentialW3C}
options={{ title: t('Screens.ProofChangeCredentialW3C') }}
/>
<Stack.Screen
name={Screens.ProofRequesting}
component={ProofRequesting}
Expand Down
4 changes: 3 additions & 1 deletion app/screens/CredentialDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
CredentialExchangeRecord,
updateCredentialExchangeRecord,
deleteCredentialExchangeRecordById,
useConnections,
} from '@adeya/ssi'
import { BrandingOverlay } from '@hyperledger/aries-oca'
import { BrandingOverlayType, CredentialOverlay } from '@hyperledger/aries-oca/build/legacy'
Expand Down Expand Up @@ -89,7 +90,8 @@ const CredentialDetails: React.FC<CredentialDetailsProps> = ({ navigation, route
brandingOverlay: undefined,
})

const credentialConnectionLabel = getCredentialConnectionLabel(credential)
const { records } = useConnections()
const credentialConnectionLabel = getCredentialConnectionLabel(records, credential)
const isPresentationFieldsEmpty = !overlay.brandingOverlay?.digest
const styles = StyleSheet.create({
container: {
Expand Down
7 changes: 7 additions & 0 deletions app/screens/CredentialDetailsW3C.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { SafeAreaView } from 'react-native-safe-area-context'
import Toast from 'react-native-toast-message'

import CommonRemoveModal from '../components/modals/CommonRemoveModal'
import RecordRemove from '../components/record/RecordRemove'
import W3CCredentialRecord from '../components/record/W3CCredentialRecord'
import { ToastType } from '../components/toast/BaseToast'
import { EventTypes } from '../constants'
Expand Down Expand Up @@ -181,6 +182,11 @@ const CredentialDetailsW3C: React.FC<CredentialDetailsProps> = ({ navigation, ro
setIsRemoveModalDisplayed(false)
}

const handleOnRemove = () => {
setIsRemoveModalDisplayed(true)
}

const callOnRemove = useCallback(() => handleOnRemove(), [])
const callSubmitRemove = useCallback(() => handleSubmitRemove(), [])
const callCancelRemove = useCallback(() => handleCancelRemove(), [])

Expand Down Expand Up @@ -284,6 +290,7 @@ const CredentialDetailsW3C: React.FC<CredentialDetailsProps> = ({ navigation, ro
<Text style={TextTheme.normal}>{w3cCredential?.connectionLabel ?? ''}</Text>
</Text>
</View>
<RecordRemove onRemove={callOnRemove} />
</View>
)
}
Expand Down
32 changes: 9 additions & 23 deletions app/screens/CredentialOffer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
declineCredentialOffer,
sendCredentialProblemReport,
AutoAcceptCredential,
useConnections,
} from '@adeya/ssi'
import { BrandingOverlay } from '@hyperledger/aries-oca'
import { CredentialOverlay } from '@hyperledger/aries-oca/build/legacy'
Expand Down Expand Up @@ -64,7 +65,8 @@ const CredentialOffer: React.FC<CredentialOfferProps> = ({ navigation, route })
const credential = useCredentialById(credentialId)
const [jsonLdOffer, setJsonLdOffer] = useState<JsonLdFormatDataCredentialDetail>()
const [tables, setTables] = useState<W3CCredentialAttributeField[]>([])
const credentialConnectionLabel = getCredentialConnectionLabel(credential)
const { records } = useConnections()
const credentialConnectionLabel = getCredentialConnectionLabel(records, credential)

const styles = StyleSheet.create({
headerTextContainer: {
Expand Down Expand Up @@ -157,7 +159,10 @@ const CredentialOffer: React.FC<CredentialOfferProps> = ({ navigation, route })
const credentialFormatData = await getFormattedCredentialData(agent, credential.id)

// Added holder did as id if did is not present and negotiate offer
if (!credentialFormatData?.offer?.jsonld?.credential?.credentialSubject?.id) {
if (
!credentialFormatData?.offer?.jsonld?.credential?.credentialSubject?.id &&
credentialFormatData?.offer?.jsonld
) {
const holderDid = await getDefaultHolderDidDocument(agent)
await agent.credentials.negotiateOffer({
credentialFormats: {
Expand Down Expand Up @@ -218,31 +223,12 @@ const CredentialOffer: React.FC<CredentialOfferProps> = ({ navigation, route })
{t('CredentialOffer.IsOfferingYouACredential')}
</Text>
</View>
{!loading && credential && (
<View style={{ marginHorizontal: 15, marginBottom: 16 }}>
<CredentialCard credential={credential} />
</View>
)}
</>
)
}

const jsonLdHeader = () => {
return (
<>
<ConnectionImage connectionId={credential?.connectionId} />
<View style={styles.headerTextContainer}>
<Text style={styles.headerText} testID={testIdWithKey('HeaderText')}>
<Text>{credentialConnectionLabel || t('ContactDetails.AContact')}</Text>{' '}
{t('CredentialOffer.IsOfferingYouACredential')}
</Text>
</View>
{!loading && credential && (
<View style={{ marginHorizontal: 15, marginBottom: 16 }}>
<CredentialCard
credential={credential}
schemaId={jsonLdOffer?.credential?.type[1] ?? ''}
connectionLabel={credentialConnectionLabel}
schemaId={jsonLdOffer?.credential.type[1]}
/>
</View>
)}
Expand Down Expand Up @@ -291,7 +277,7 @@ const CredentialOffer: React.FC<CredentialOfferProps> = ({ navigation, route })
tables={tables}
fields={overlay.presentationFields || []}
hideFieldValues={false}
header={jsonLdHeader}
header={header}
footer={footer}
/>
) : (
Expand Down
Loading

0 comments on commit 8768578

Please sign in to comment.