diff --git a/.env.sample b/.env.sample
index 9119960b..dd1dcdd3 100644
--- a/.env.sample
+++ b/.env.sample
@@ -14,4 +14,11 @@ OCA_URL=https://raw.githubusercontent.com/credebl/credebl-aries-oca-bundles/rele
PUBLIC_ORG=https://example.com
#PROOF_TEMPLATE_URL
-PROOF_TEMPLATE_URL=
\ No newline at end of file
+PROOF_TEMPLATE_URL=
+
+# Google Signin
+GOOGLE_WEB_CLIENT_ID=CLIENT_ID
+GOOGLE_IOS_CLIENT_ID=CLIENT_ID
+
+# DATA ENCYPTION KEY
+DATA_ENCRYPTION_KEY=DATA_ENCRYPTION_KEY
diff --git a/.gitignore b/.gitignore
index 2b2c9587..d8a221e3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -68,3 +68,5 @@ yarn-error.log
.env
google-services.json
+# VS Code
+.vscode/
\ No newline at end of file
diff --git a/App.tsx b/App.tsx
index 1c7febee..9073981f 100644
--- a/App.tsx
+++ b/App.tsx
@@ -2,9 +2,11 @@
global.Buffer = require('buffer').Buffer
import { AdeyaAgentProvider } from '@adeya/ssi'
+import { GoogleSignin } from '@react-native-google-signin/google-signin'
import * as React from 'react'
import { useEffect, useMemo } from 'react'
import { StatusBar } from 'react-native'
+import { Config } from 'react-native-config'
import SplashScreen from 'react-native-splash-screen'
import Toast from 'react-native-toast-message'
@@ -38,6 +40,15 @@ const App = () => {
// Hide the native splash / loading screen so that our
// RN version can be displayed
SplashScreen.hide()
+
+ if (Config.GOOGLE_WEB_CLIENT_ID && Config.GOOGLE_IOS_CLIENT_ID) {
+ GoogleSignin.configure({
+ webClientId: Config.GOOGLE_WEB_CLIENT_ID,
+ iosClientId: Config.GOOGLE_IOS_CLIENT_ID,
+ offlineAccess: true,
+ scopes: ['https://www.googleapis.com/auth/drive.file', 'https://www.googleapis.com/auth/drive.metadata'],
+ })
+ }
}, [])
return (
diff --git a/android/app/build.gradle b/android/app/build.gradle
index 1761656b..336ca720 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -81,8 +81,8 @@ android {
applicationId "id.credebl.adeya"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
- versionCode 12
- versionName "1.0.9"
+ versionCode 16
+ versionName "1.0.10"
missingDimensionStrategy 'react-native-camera', 'general'
}
@@ -114,6 +114,15 @@ android {
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
}
}
+
+ packagingOptions {
+ pickFirst 'lib/x86/libc++_shared.so'
+ pickFirst 'lib/x86_64/libjsc.so'
+ pickFirst 'lib/arm64-v8a/libjsc.so'
+ pickFirst 'lib/arm64-v8a/libc++_shared.so'
+ pickFirst 'lib/x86_64/libc++_shared.so'
+ pickFirst 'lib/armeabi-v7a/libc++_shared.so'
+ }
}
dependencies {
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index 0b232e36..01db3c5f 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -59,9 +59,7 @@
-
-
-
+
diff --git a/android/build.gradle b/android/build.gradle
index 3b3cb80d..e4389a69 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -3,7 +3,7 @@
buildscript {
ext {
buildToolsVersion = "33.0.0"
- minSdkVersion = 21
+ minSdkVersion = 24
compileSdkVersion = 34
targetSdkVersion = 34
diff --git a/app/components/listItems/NotificationListItem.tsx b/app/components/listItems/NotificationListItem.tsx
index c61ea2b4..38994fce 100644
--- a/app/components/listItems/NotificationListItem.tsx
+++ b/app/components/listItems/NotificationListItem.tsx
@@ -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'
@@ -67,6 +69,7 @@ const NotificationListItem: React.FC = ({ notificatio
const { ColorPallet, TextTheme } = useTheme()
const { agent } = useAppAgent()
const [declineModalVisible, setDeclineModalVisible] = useState(false)
+ const [notificationDetails, setNotificationDetails] = useState(null)
const [details, setDetails] = useState({
type: InfoBoxType.Info,
title: undefined,
@@ -215,6 +218,7 @@ const NotificationListItem: React.FC = ({ 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,
@@ -222,6 +226,17 @@ const NotificationListItem: React.FC = ({ notificatio
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({
@@ -277,10 +292,21 @@ const NotificationListItem: React.FC = ({ 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
diff --git a/app/components/misc/CredentialCard10.tsx b/app/components/misc/CredentialCard10.tsx
index 558ccfef..39aff1f6 100644
--- a/app/components/misc/CredentialCard10.tsx
+++ b/app/components/misc/CredentialCard10.tsx
@@ -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'
@@ -75,7 +75,8 @@ const CredentialCard10: React.FC = ({ credential, style =
const { OCABundleResolver } = useConfiguration()
const [overlay, setOverlay] = useState>({})
const [isRevoked, setIsRevoked] = useState(false)
- const credentialConnectionLabel = getCredentialConnectionLabel(credential)
+ const { records } = useConnections()
+ const credentialConnectionLabel = getCredentialConnectionLabel(records, credential)
const styles = StyleSheet.create({
container: {
diff --git a/app/components/misc/CredentialCard11.tsx b/app/components/misc/CredentialCard11.tsx
index 6d389357..97afb7ee 100644
--- a/app/components/misc/CredentialCard11.tsx
+++ b/app/components/misc/CredentialCard11.tsx
@@ -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'
@@ -91,7 +91,8 @@ const CredentialCard11: React.FC = ({
const { ColorPallet, TextTheme, ListItems } = useTheme()
const { OCABundleResolver } = useConfiguration()
const [isRevoked, setIsRevoked] = useState(credential?.revocationNotification !== undefined)
- const credentialConnectionLabel = getCredentialConnectionLabel(credential, connectionLabel)
+ const { records } = useConnections()
+ const credentialConnectionLabel = getCredentialConnectionLabel(records, credential, connectionLabel)
const [isProofRevoked, setIsProofRevoked] = useState(
credential?.revocationNotification !== undefined && !!proof,
)
@@ -136,7 +137,7 @@ const CredentialCard11: React.FC = ({
},
primaryBodyContainer: {
flexGrow: 1,
- padding,
+ padding: 15,
},
imageAttr: {
height: 150,
@@ -308,6 +309,7 @@ const CredentialCard11: React.FC = ({
styles.textContainer,
{
lineHeight: 24,
+ width: '85%',
fontWeight: 'bold',
},
]}
@@ -379,7 +381,7 @@ const CredentialCard11: React.FC = ({
{
fontWeight: 'bold',
lineHeight: 24,
- flex: 1,
+ width: '85%',
flexWrap: 'wrap',
},
]}>
diff --git a/app/components/record/W3CCredentialRecord.tsx b/app/components/record/W3CCredentialRecord.tsx
index 7db03dda..71e0791e 100644
--- a/app/components/record/W3CCredentialRecord.tsx
+++ b/app/components/record/W3CCredentialRecord.tsx
@@ -1,7 +1,7 @@
+import { W3cCredentialRecord } from '@adeya/ssi'
import React, { useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'
-import { FlatList, StyleSheet, Text, TouchableOpacity, View } from 'react-native'
-import Icon from 'react-native-vector-icons/Feather'
+import { ActivityIndicator, FlatList, StyleSheet, Text, TouchableOpacity, View } from 'react-native'
import { useTheme } from '../../contexts/theme'
import { Field, W3CCredentialAttributeField } from '../../types/record'
@@ -17,13 +17,31 @@ export interface RecordProps {
fields: Field[]
hideFieldValues?: boolean
tables: W3CCredentialAttributeField[]
+ w3cCredential?: Pick & {
+ credential: Pick, 'credential'> & {
+ prettyVc?: string
+ }
+ }
+ renderCertificate?: () => void
+ isCertificateLoading?: boolean
}
-const W3CCredentialRecord: React.FC = ({ header, footer, fields, hideFieldValues = false, tables }) => {
+const W3CCredentialRecord: React.FC = ({
+ header,
+ footer,
+ hideFieldValues = false,
+ tables,
+ w3cCredential,
+ renderCertificate,
+ isCertificateLoading,
+}) => {
const { t } = useTranslation()
- const [shown, setShown] = useState([])
- const [showAll, setShowAll] = useState(false)
- const { ListItems, TextTheme } = useTheme()
+ const [shown, setShown] = useState([])
+ const [showAll, setShowAll] = useState(true)
+ const { ListItems, TextTheme, ColorPallet } = useTheme()
+
+ const isPrettyVcAvailable =
+ w3cCredential?.credential?.prettyVc && Object.keys(w3cCredential?.credential?.prettyVc).length > 0
const styles = StyleSheet.create({
linkContainer: {
@@ -37,22 +55,28 @@ const W3CCredentialRecord: React.FC = ({ header, footer, fields, hi
minHeight: TextTheme.normal.fontSize,
paddingVertical: 2,
},
+ container: {
+ padding: 16,
+ flexDirection: 'row',
+ },
+ rowContainer: {
+ flexDirection: 'row',
+ justifyContent: isPrettyVcAvailable ? 'space-between' : 'flex-end',
+ backgroundColor: ColorPallet.grayscale.white,
+ },
+ linkText: {
+ fontWeight: 'bold',
+ },
})
const resetShown = (): void => {
- setShown(fields.map(() => showAll))
+ setShown(tables.map(table => table.rows.map(() => showAll)))
setShowAll(!showAll)
}
- const toggleShownState = (newShowStates: boolean[]): void => {
- if (newShowStates.filter(shownState => shownState === showAll).length > Math.floor(fields.length / 2)) {
- setShowAll(!showAll)
- }
- }
-
useEffect(() => {
resetShown()
- }, [])
+ }, [tables])
return (
= ({ header, footer, fields, hi
keyExtractor={({ title }, index) => title || index.toString()}
renderItem={({ item: table, index }) => (
-
- {table.depth > 1 && }
+
{table.title && (
= ({ header, footer, fields, hi
hideFieldValue={hideFieldValues}
onToggleViewPressed={() => {
const newShowState = [...shown]
- newShowState[index] = !shown[index]
+ newShowState[index][idx] = !shown[index][idx]
setShown(newShowState)
- toggleShownState(newShowState)
}}
- shown={hideFieldValues ? !!shown[index] : true}
+ shown={hideFieldValues ? !!(shown?.[index]?.[idx] ?? false) : true}
hideBottomBorder={idx === table.rows.length - 1}
/>
))}
@@ -100,19 +122,39 @@ const W3CCredentialRecord: React.FC = ({ header, footer, fields, hi
header ? (
{header()}
- {hideFieldValues ? (
-
- resetShown()}
- testID={testIdWithKey('HideAll')}
- accessible={true}
- accessibilityLabel={showAll ? t('Record.ShowAll') : t('Record.HideAll')}>
- {showAll ? t('Record.ShowAll') : t('Record.HideAll')}
-
-
- ) : null}
+
+ {isPrettyVcAvailable && (
+
+ {isCertificateLoading ? (
+
+ ) : (
+
+ {t('Record.ViewCertificate')}
+
+ )}
+
+ )}
+
+ {hideFieldValues ? (
+
+ resetShown()}
+ testID={testIdWithKey('HideAll')}
+ accessible={true}
+ accessibilityLabel={showAll ? t('Record.ShowAll') : t('Record.HideAll')}>
+ {showAll ? t('Record.ShowAll') : t('Record.HideAll')}
+
+
+ ) : null}
+
) : null
}
diff --git a/app/components/record/W3CCredentialRecordField.tsx b/app/components/record/W3CCredentialRecordField.tsx
index c8e5c8cc..069fc697 100644
--- a/app/components/record/W3CCredentialRecordField.tsx
+++ b/app/components/record/W3CCredentialRecordField.tsx
@@ -98,7 +98,7 @@ const W3CCredentialRecordField: React.FC = ({
) : null}
>
- {}
+
)
}
diff --git a/app/constants.ts b/app/constants.ts
index 62896aea..42cb2aff 100644
--- a/app/constants.ts
+++ b/app/constants.ts
@@ -79,3 +79,5 @@ export const domain = 'didcomm://invite'
export const tourMargin = 25
export const hitSlop = { top: 44, bottom: 44, left: 44, right: 44 }
+
+export const CREDENTIAL = 'Credential'
diff --git a/app/contexts/auth.tsx b/app/contexts/auth.tsx
index 87088413..c6abdfa9 100644
--- a/app/contexts/auth.tsx
+++ b/app/contexts/auth.tsx
@@ -2,7 +2,9 @@
import 'reflect-metadata'
import { isWalletPinCorrect } from '@adeya/ssi'
-import React, { PropsWithChildren, createContext, useContext, useState } from 'react'
+import AsyncStorage from '@react-native-async-storage/async-storage'
+import { GoogleSignin } from '@react-native-google-signin/google-signin'
+import React, { PropsWithChildren, createContext, useContext, useState, useEffect } from 'react'
import { useTranslation } from 'react-i18next'
import { DeviceEventEmitter } from 'react-native'
@@ -29,15 +31,41 @@ export interface AuthContext {
setPIN: (PIN: string) => Promise
commitPIN: (useBiometry: boolean) => Promise
isBiometricsActive: () => Promise
+ isGoogleAccountSignedIn: boolean
+ googleSignIn: () => Promise
+ googleSignOut: () => Promise
}
export const AuthContext = createContext(null as unknown as AuthContext)
export const AuthProvider: React.FC = ({ children }) => {
const [walletSecret, setWalletSecret] = useState()
+ const [isGoogleAccountSignedIn, setIsGoogleAccountSignedIn] = useState(false)
const [, dispatch] = useStore()
const { t } = useTranslation()
+ useEffect(() => {
+ const checkGoogleSignInStatus = async () => {
+ const googleUserInfo = await AsyncStorage.getItem('googleUserInfo')
+ setIsGoogleAccountSignedIn(googleUserInfo !== null)
+ }
+ checkGoogleSignInStatus()
+ }, [])
+
+ const googleSignIn = async (): Promise => {
+ setIsGoogleAccountSignedIn(true)
+ }
+
+ const googleSignOut = async (): Promise => {
+ try {
+ await GoogleSignin.signOut()
+ await AsyncStorage.removeItem('googleUserInfo')
+ setIsGoogleAccountSignedIn(false)
+ } catch (error) {
+ // error message
+ }
+ }
+
const setPIN = async (PIN: string): Promise => {
const secret = await secretForPIN(PIN)
await storeWalletSecret(secret)
@@ -128,6 +156,9 @@ export const AuthProvider: React.FC = ({ children }) => {
commitPIN,
setPIN,
isBiometricsActive,
+ isGoogleAccountSignedIn,
+ googleSignIn,
+ googleSignOut,
}}>
{children}
diff --git a/app/localization/en/index.ts b/app/localization/en/index.ts
index ef217349..9d8a226b 100644
--- a/app/localization/en/index.ts
+++ b/app/localization/en/index.ts
@@ -486,6 +486,7 @@ const translation = {
"ScanMyQR": "Scan my QR code",
"Developer": "Developer options",
"Backup": "backup wallet",
+ "GoogleDriveBackup": "Google Drive Backup",
"Confirmation" : 'Confirmation'
},
"TabStack": {
@@ -514,6 +515,7 @@ const translation = {
"Hidden": "Hidden",
"InvalidDate": "Invalid Date: ",
"Zoom": "Zoom",
+ "ViewCertificate": "View Certificate",
},
"Screens": {
"Splash": "Splash",
@@ -566,9 +568,12 @@ const translation = {
"Explore": "Explore",
"OrganizationDetails": "Organization Details",
"ProofChangeCredential": "Choose a credential",
+ "ProofChangeCredentialW3C": "Choose a W3C credential",
"DataRetention": "Data retention",
"Organization": "Explore",
- "OrganizationConnection": "Connection"
+ "OrganizationConnection": "Connection",
+ "RenderCertificate": "Certificate",
+ "GoogleDriveSignIn": "Google Drive Sign In",
},
"Loading": {
"TakingTooLong": "This is taking longer than usual. You can return to home or continue waiting.",
@@ -692,6 +697,7 @@ const translation = {
"you_have_successfully": 'You have successfully selected the words.',
"complete_backup": 'Complete Backup',
"backup_wallet": 'Backup Wallet',
+ "backup_google_drive": 'Backup to Google Drive',
},
"PushNotifications": {
"BulletFour": "new messages",
@@ -704,7 +710,27 @@ const translation = {
"NotAvailable": " (Not Available)",
"Title": "Notifications",
"PushNotifications": "Push Notifications",
- }
+ },
+ "DIDs":{
+ "Dids": "My DID",
+ },
+ "GoogleDrive": {
+ "Backup": "Backup to Google Drive",
+ "BackupTitle": "Backup to Google Drive",
+ "SignInCancelled": "User cancelled the login flow",
+ "SignInProgress": "Operation is in progress already",
+ "PlayServicesNotAvailable": "Play services not available or outdated",
+ "SignInError": "An error occurred during sign-in",
+ "SignOutGoogle": "Sign Out of Google Account",
+ "SignOutGoogleSuccess": "Google Sign Out Successful",
+ "BackupFailed": "Backup failed to upload to Google Drive. Please try again later.",
+ "BackupSuccess": "Backup successfully uploaded to Google Drive.",
+ },
+ "Restore": {
+ "RestoreWallet": "Restore Wallet",
+ "RestoreInstructions": "Note: To restore your wallet, you can use a backup from your cloud storage or local device. Please ensure that the Google Drive app is installed on your device and you are signed in.",
+ "RestoreInstructionsIOS": "If you can't see Google Drive in the file picker, open the Files app --> tap on the three dots at the top --> select 'Edit' --> enable Google Drive.",
+ },
}
export default translation
diff --git a/app/navigators/ContactStack.tsx b/app/navigators/ContactStack.tsx
index e0518907..a813bc4f 100644
--- a/app/navigators/ContactStack.tsx
+++ b/app/navigators/ContactStack.tsx
@@ -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'
@@ -61,7 +62,7 @@ const ContactStack: React.FC = () => {
{
component={ProofRequest}
options={{ title: t('Screens.ProofRequest') }}
/>
+
{
+
diff --git a/app/navigators/DeliveryStack.tsx b/app/navigators/DeliveryStack.tsx
index 9775f4c7..250c40a5 100644
--- a/app/navigators/DeliveryStack.tsx
+++ b/app/navigators/DeliveryStack.tsx
@@ -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'
@@ -38,6 +39,11 @@ const DeliveryStack: React.FC = () => {
component={ProofRequest}
options={{ title: t('Screens.ProofRequest') }}
/>
+
{
component={ProofRequest}
options={{ title: t('Screens.ProofRequest') }}
/>
+
{
component={ProofChangeCredential}
options={{ title: t('Screens.ProofChangeCredential') }}
/>
+
{
// handle deeplink events
useEffect(() => {
async function handleDeepLink(deepLink: string) {
+ let invitationUrl = deepLink
try {
+ if (invitationUrl.includes('?url=')) {
+ const parts = invitationUrl.split('=')
+ invitationUrl = parts[1]
+ }
+
// check if connection already exists
- const isAlreadyConnected = await checkIfAlreadyConnected(agent, deepLink)
+ const isAlreadyConnected = await checkIfAlreadyConnected(agent, invitationUrl)
if (isAlreadyConnected) {
Toast.show({
@@ -100,25 +114,64 @@ const RootStack: React.FC = () => {
}
// Try connection based
- const { connectionRecord } = await connectFromInvitation(agent, deepLink)
+ const { connectionRecord, outOfBandRecord } = await connectFromInvitation(agent, invitationUrl)
navigation.navigate(Stacks.ConnectionStack as any, {
screen: Screens.Connection,
- params: { connectionId: connectionRecord?.id },
+ params: { connectionId: connectionRecord?.id, outOfBandId: outOfBandRecord.id },
})
} catch {
try {
- // Try connectionless here
- const message = await getOobDeepLink(deepLink, agent)
- navigation.navigate(Stacks.ConnectionStack as any, {
- screen: Screens.Connection,
- params: { threadId: message['@id'] },
- })
+ const json = getJson(invitationUrl)
+ if (json) {
+ await agent?.receiveMessage(json)
+ navigation.getParent()?.navigate(Stacks.ConnectionStack, {
+ screen: Screens.Connection,
+ params: { threadId: json['@id'] },
+ })
+ return
+ }
+
+ const urlData = await fetchUrlData(invitationUrl)
+ const isValidURL = isValidUrl(urlData)
+
+ if (isValidURL) {
+ const isAlreadyConnected = await checkIfAlreadyConnected(agent, urlData)
+
+ if (isAlreadyConnected) {
+ Toast.show({
+ type: ToastType.Warn,
+ text1: t('Contacts.AlreadyConnected'),
+ })
+ navigation.goBack()
+ return
+ }
+
+ const { connectionRecord, outOfBandRecord } = await connectFromInvitation(agent, urlData)
+
+ navigation.getParent()?.navigate(Stacks.ConnectionStack, {
+ screen: Screens.Connection,
+ params: { connectionId: connectionRecord?.id, outOfBandId: outOfBandRecord.id },
+ })
+ return
+ }
+ // if scanned value is url -> receive message from it
+
+ const url = getUrl(invitationUrl)
+
+ if (url) {
+ const message = await receiveMessageFromUrlRedirect(invitationUrl, agent)
+ navigation.getParent()?.navigate(Stacks.ConnectionStack, {
+ screen: Screens.Connection,
+ params: { threadId: message['@id'] },
+ })
+ return
+ }
} catch (error) {
// TODO:(am add error handling here)
}
}
- // set deeplink as inactive
+ // set deep link as inactive
dispatch({
type: DispatchAction.ACTIVE_DEEP_LINK,
payload: [undefined],
diff --git a/app/navigators/SettingStack.tsx b/app/navigators/SettingStack.tsx
index 3ccba712..2a241b21 100644
--- a/app/navigators/SettingStack.tsx
+++ b/app/navigators/SettingStack.tsx
@@ -10,6 +10,7 @@ import CreateWallet from '../screens/CreateWallet'
import DataRetention from '../screens/DataRetention'
import ExportWallet from '../screens/ExportWallet'
import ExportWalletConfirmation from '../screens/ExportWalletConfirmation'
+import GoogleDriveSignIn from '../screens/GoogleDriveSignIn'
import ImportSuccess from '../screens/ImportSuccess'
import ImportWalletVerify from '../screens/ImportWalletConfirmation'
import Language from '../screens/Language'
@@ -137,6 +138,11 @@ const SettingStack: React.FC = () => {
component={CreateWallet}
options={{ title: t('Screens.CreateWallet') }}
/>
+
)
}
diff --git a/app/screens/Chat.tsx b/app/screens/Chat.tsx
index 21add545..3fef5617 100644
--- a/app/screens/Chat.tsx
+++ b/app/screens/Chat.tsx
@@ -223,9 +223,18 @@ const Chat: React.FC = ({ navigation, route }) => {
[ProofState.PresentationSent]: toProofDetails,
[ProofState.PresentationReceived]: toProofDetails,
[ProofState.RequestReceived]: () => {
- navigation.navigate(Stacks.ContactStack as any, {
- screen: Screens.ProofRequest,
- params: { proofId: record.id },
+ agent.proofs.getFormatData(record.id).then(value => {
+ if (value?.request?.indy) {
+ navigation.navigate(Stacks.ContactStack as any, {
+ screen: Screens.ProofRequest,
+ params: { proofId: record.id },
+ })
+ } else {
+ navigation.navigate(Stacks.ContactStack as any, {
+ screen: Screens.ProofRequestW3C,
+ params: { proofId: record.id },
+ })
+ }
})
},
}
diff --git a/app/screens/Connection.tsx b/app/screens/Connection.tsx
index b390f316..049c4481 100644
--- a/app/screens/Connection.tsx
+++ b/app/screens/Connection.tsx
@@ -11,7 +11,7 @@ import Button, { ButtonType } from '../components/buttons/Button'
import { useAnimatedComponents } from '../contexts/animated-components'
import { useConfiguration } from '../contexts/configuration'
import { useTheme } from '../contexts/theme'
-import { useOutOfBandByConnectionId } from '../hooks/connections'
+import { useOutOfBandById } from '../hooks/connections'
import { useNotifications } from '../hooks/notifications'
import { Screens, TabStacks, DeliveryStackParams, Stacks } from '../types/navigators'
import { useAppAgent } from '../utils/agent'
@@ -35,7 +35,7 @@ const Connection: React.FC = ({ navigation, route }) => {
// delay message, the user should be redirected to the home screen.
const { connectionTimerDelay, autoRedirectConnectionToHome } = useConfiguration()
const connTimerDelay = connectionTimerDelay ?? 10000 // in ms
- const { connectionId, threadId } = route.params
+ const { connectionId, outOfBandId, threadId } = route.params
const timerRef = useRef(null)
const connection = connectionId ? useConnectionById(connectionId) : undefined
const { t } = useTranslation()
@@ -43,7 +43,7 @@ const Connection: React.FC = ({ navigation, route }) => {
const { ColorPallet, TextTheme } = useTheme()
const { ConnectionLoading } = useAnimatedComponents()
const { agent } = useAppAgent()
- const oobRecord = useOutOfBandByConnectionId(agent, connectionId ?? '')
+ const oobRecord = useOutOfBandById(agent, outOfBandId ?? '')
const goalCode = oobRecord?.outOfBandInvitation.goalCode
const merge: MergeFunction = (current, next) => ({ ...current, ...next })
const [state, dispatch] = useReducer(merge, {
@@ -52,6 +52,7 @@ const Connection: React.FC = ({ navigation, route }) => {
shouldShowDelayMessage: false,
connectionIsActive: false,
})
+
const styles = StyleSheet.create({
container: {
height: '100%',
@@ -168,7 +169,7 @@ const Connection: React.FC = ({ navigation, route }) => {
if (state.notificationRecord && goalCode) {
goalCodeAction(goalCode)()
}
- }, [connection, goalCode, state.notificationRecord])
+ }, [connection, oobRecord, goalCode, state.notificationRecord])
useMemo(() => {
startTimer()
diff --git a/app/screens/CreateWallet.tsx b/app/screens/CreateWallet.tsx
index 24874dc8..9f96732b 100644
--- a/app/screens/CreateWallet.tsx
+++ b/app/screens/CreateWallet.tsx
@@ -1,6 +1,8 @@
import { useNavigation } from '@react-navigation/core'
-import React from 'react'
-import { View, StyleSheet, Text } from 'react-native'
+import React, { useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import { View, StyleSheet, Text, Platform, Modal, TouchableOpacity } from 'react-native'
+import Icon from 'react-native-vector-icons/MaterialIcons'
import Button, { ButtonType } from '../components/buttons/Button'
import { useTheme } from '../contexts/theme'
@@ -9,6 +11,20 @@ import { Screens } from '../types/navigators'
const CreateWallet: React.FC = () => {
const { TextTheme, ColorPallet } = useTheme()
const navigation = useNavigation()
+ const { t } = useTranslation()
+ const [isModalVisible, setModalVisible] = useState(false)
+
+ const toggleModal = () => {
+ setModalVisible(!isModalVisible)
+ }
+
+ const proceedWithRestore = () => {
+ toggleModal()
+ setTimeout(() => {
+ navigation.navigate(Screens.ImportWalletVerify as never)
+ }, 300)
+ }
+
const styles = StyleSheet.create({
container: {
flex: 1,
@@ -21,6 +37,11 @@ const CreateWallet: React.FC = () => {
color: ColorPallet.brand.primary,
marginTop: 20,
},
+ instructionsText: {
+ fontSize: 16,
+ color: ColorPallet.brand.primary,
+ marginVertical: 10,
+ },
walletButtonView: {
marginTop: 'auto',
margin: 20,
@@ -28,6 +49,29 @@ const CreateWallet: React.FC = () => {
restoreWalletView: {
marginTop: 20,
},
+ modalOverlay: {
+ flex: 1,
+ backgroundColor: 'rgba(0, 0, 0, 0.5)',
+ justifyContent: 'center',
+ alignItems: 'center',
+ padding: 20,
+ },
+ modalHeader: {
+ flexDirection: 'row',
+ justifyContent: 'space-between',
+ alignItems: 'center',
+ marginBottom: 15,
+ },
+ modalContent: {
+ backgroundColor: ColorPallet.brand.modalSecondary,
+ padding: 22,
+ borderRadius: 4,
+ },
+ modalTitle: {
+ fontSize: 24,
+ color: ColorPallet.brand.primary,
+ fontWeight: 'bold',
+ },
})
return (
@@ -43,11 +87,35 @@ const CreateWallet: React.FC = () => {
+
+
+
+
+ {t('Restore.RestoreWallet')}
+
+
+
+
+ {t('Restore.RestoreInstructions')}
+ {Platform.OS === 'ios' && (
+ {t('Restore.RestoreInstructionsIOS')}
+ )}
+
+
+
+
+
+
)
}
diff --git a/app/screens/CredentialDetails.tsx b/app/screens/CredentialDetails.tsx
index 1308170e..7acf1bc5 100644
--- a/app/screens/CredentialDetails.tsx
+++ b/app/screens/CredentialDetails.tsx
@@ -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'
@@ -76,6 +77,7 @@ const CredentialDetails: React.FC = ({ navigation, route
const [isRevoked, setIsRevoked] = useState(false)
const [revocationDate, setRevocationDate] = useState('')
const [preciseRevocationDate, setPreciseRevocationDate] = useState('')
+ const [isDeletingCredential, setIsDeletingCredential] = useState(false)
const [isRemoveModalDisplayed, setIsRemoveModalDisplayed] = useState(false)
const [isRevokedMessageHidden, setIsRevokedMessageHidden] = useState(
(credential!.metadata.get(CredentialMetadata.customMetadata) as customMetadata)?.revoked_detail_dismissed ?? false,
@@ -89,7 +91,8 @@ const CredentialDetails: React.FC = ({ 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: {
@@ -140,16 +143,7 @@ const CredentialDetails: React.FC = ({ navigation, route
})
useEffect(() => {
- if (!agent) {
- DeviceEventEmitter.emit(
- EventTypes.ERROR_ADDED,
- new BifoldError(t('Error.Title1033'), t('Error.Message1033'), t('CredentialDetails.CredentialNotFound'), 1033),
- )
- }
- }, [])
-
- useEffect(() => {
- if (!credential) {
+ if (!agent || !credential) {
DeviceEventEmitter.emit(
EventTypes.ERROR_ADDED,
new BifoldError(t('Error.Title1033'), t('Error.Message1033'), t('CredentialDetails.CredentialNotFound'), 1033),
@@ -201,19 +195,25 @@ const CredentialDetails: React.FC = ({ navigation, route
if (!credential) {
return
}
+ setIsDeletingCredential(true)
+
+ await deleteCredentialExchangeRecordById(agent, credential.id, {
+ deleteAssociatedCredentials: true,
+ })
- await deleteCredentialExchangeRecordById(agent, credential.id)
+ setIsDeletingCredential(false)
navigation.pop()
// FIXME: This delay is a hack so that the toast doesn't appear until the modal is dismissed
- await new Promise(resolve => setTimeout(resolve, 1000))
+ await new Promise(resolve => setTimeout(resolve, 50))
Toast.show({
type: ToastType.Success,
text1: t('CredentialDetails.CredentialRemoved'),
})
} catch (err: unknown) {
+ setIsDeletingCredential(false)
const error = new BifoldError(t('Error.Title1032'), t('Error.Message1032'), (err as Error).message, 1025)
DeviceEventEmitter.emit(EventTypes.ERROR_ADDED, error)
@@ -423,6 +423,7 @@ const CredentialDetails: React.FC = ({ navigation, route
visible={isRemoveModalDisplayed}
onSubmit={callSubmitRemove}
onCancel={callCancelRemove}
+ disabled={isDeletingCredential}
/>
)
diff --git a/app/screens/CredentialDetailsW3C.tsx b/app/screens/CredentialDetailsW3C.tsx
index 3026e254..d4c3d6a2 100644
--- a/app/screens/CredentialDetailsW3C.tsx
+++ b/app/screens/CredentialDetailsW3C.tsx
@@ -4,19 +4,25 @@ import {
CredentialExchangeRecord,
W3cCredentialRecord,
getW3cCredentialRecordById,
- getAllCredentialExchangeRecords,
deleteCredentialExchangeRecordById,
+ useCredentialByState,
+ CredentialState,
+ useConnections,
} from '@adeya/ssi'
import { BrandingOverlay } from '@hyperledger/aries-oca'
-import { BrandingOverlayType, CredentialOverlay } from '@hyperledger/aries-oca/build/legacy'
+import { CredentialOverlay } from '@hyperledger/aries-oca/build/legacy'
+import * as CryptoJS from 'crypto-js'
+import { toString as toQRCodeString } from 'qrcode'
import React, { useCallback, useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'
-import { DeviceEventEmitter, Image, ImageBackground, StyleSheet, Text, View } from 'react-native'
+import { DeviceEventEmitter, Image, ImageBackground, Platform, StyleSheet, Text, View } from 'react-native'
+import { Config } from 'react-native-config'
+import RNHTMLtoPDF from 'react-native-html-to-pdf'
import { SafeAreaView } from 'react-native-safe-area-context'
import Toast from 'react-native-toast-message'
-import CredentialCard from '../components/misc/CredentialCard'
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'
@@ -54,6 +60,10 @@ const CredentialDetailsW3C: React.FC = ({ navigation, ro
const [isRemoveModalDisplayed, setIsRemoveModalDisplayed] = useState(false)
const [tables, setTables] = useState([])
const [w3cCredential, setW3cCredential] = useState()
+ const credentialsList = useCredentialByState(CredentialState.Done)
+ const [isDeletingCredential, setIsDeletingCredential] = useState(false)
+ const [isGeneratingPdf, setIsGeneratingPdf] = useState(false)
+ const { records: connectionRecords } = useConnections()
const [overlay, setOverlay] = useState>({
bundle: undefined,
@@ -103,16 +113,7 @@ const CredentialDetailsW3C: React.FC = ({ navigation, ro
})
useEffect(() => {
- if (!agent) {
- DeviceEventEmitter.emit(
- EventTypes.ERROR_ADDED,
- new BifoldError(t('Error.Title1033'), t('Error.Message1033'), t('CredentialDetails.CredentialNotFound'), 1033),
- )
- }
- }, [])
-
- useEffect(() => {
- if (!credential) {
+ if (!agent || !credential) {
DeviceEventEmitter.emit(
EventTypes.ERROR_ADDED,
new BifoldError(t('Error.Title1033'), t('Error.Message1033'), t('CredentialDetails.CredentialNotFound'), 1033),
@@ -131,6 +132,8 @@ const CredentialDetailsW3C: React.FC = ({ navigation, ro
} else if (credential instanceof CredentialExchangeRecord) {
const credentialRecordId = credential.credentials[0].credentialRecordId
const record = await getW3cCredentialRecordById(agent, credentialRecordId)
+ const connection = connectionRecords.find(connection => connection.id === credential?.connectionId)
+ record.connectionLabel = connection?.theirLabel
return record
}
}
@@ -148,7 +151,7 @@ const CredentialDetailsW3C: React.FC = ({ navigation, ro
credentialDefinitionId: w3cCredential.credential.type[1],
},
meta: {
- alias: w3cCredential.credential.issuerId,
+ alias: w3cCredential?.connectionLabel ?? w3cCredential.credential.issuerId,
credConnectionId: w3cCredential.credential.issuerId,
credName: w3cCredential.credential.type[1],
},
@@ -169,18 +172,25 @@ const CredentialDetailsW3C: React.FC = ({ navigation, ro
if (!(agent && credential)) {
return
}
- const credentialList = await getAllCredentialExchangeRecords(agent)
- const rec = credentialList.find(cred => cred.credentials[0]?.credentialRecordId === credential.id)
+ const rec = credentialsList.find(cred => cred.credentials[0]?.credentialRecordId === credential.id)
+ setIsDeletingCredential(true)
if (rec) {
- await deleteCredentialExchangeRecordById(agent, rec.id)
+ await deleteCredentialExchangeRecordById(agent, rec.id, {
+ deleteAssociatedCredentials: true,
+ })
}
+ setIsDeletingCredential(false)
+ navigation.pop()
+
+ // FIXME: This delay is a hack so that the toast doesn't appear until the modal is dismissed
+ await new Promise(resolve => setTimeout(resolve, 50))
+
Toast.show({
type: ToastType.Success,
text1: t('CredentialDetails.CredentialRemoved'),
})
-
- navigation.pop()
} catch (err: unknown) {
+ setIsDeletingCredential(false)
const error = new BifoldError(t('Error.Title1032'), t('Error.Message1032'), (err as Error).message, 1025)
DeviceEventEmitter.emit(EventTypes.ERROR_ADDED, error)
@@ -191,6 +201,11 @@ const CredentialDetailsW3C: React.FC = ({ navigation, ro
setIsRemoveModalDisplayed(false)
}
+ const handleOnRemove = () => {
+ setIsRemoveModalDisplayed(true)
+ }
+
+ const callOnRemove = useCallback(() => handleOnRemove(), [])
const callSubmitRemove = useCallback(() => handleSubmitRemove(), [])
const callCancelRemove = useCallback(() => handleCancelRemove(), [])
@@ -270,13 +285,7 @@ const CredentialDetailsW3C: React.FC = ({ navigation, ro
}
const header = () => {
- return OCABundleResolver.getBrandingOverlayType() === BrandingOverlayType.Branding10 ? (
-
- {credential && (
-
- )}
-
- ) : (
+ return (
@@ -297,13 +306,92 @@ const CredentialDetailsW3C: React.FC = ({ navigation, ro
}}>
{t('CredentialDetails.IssuedBy') + ' '}
- {w3cCredential?.credential.issuerId ?? ''}
+ {w3cCredential?.connectionLabel ?? ''}
+
)
}
+ const getA4Sizes = (type: 'landscape' | 'portrait') => {
+ return {
+ width: type === 'landscape' ? 842 : 595,
+ height: type === 'landscape' ? 595 : 842,
+ }
+ }
+
+ const generateQRCodeString = async (text: string) => {
+ return toQRCodeString(text, {
+ width: 95,
+ margin: 1,
+ color: {
+ light: '#0000',
+ },
+ })
+ }
+
+ const navigateToRenderCertificate = async () => {
+ try {
+ setIsGeneratingPdf(true)
+
+ const certificateAttributes = w3cCredential?.credential.credentialSubject.claims
+
+ const dataToEncrypt = JSON.stringify({
+ email: certificateAttributes['email'] ?? 'email',
+ schemaUrl: w3cCredential?.credential.contexts[1],
+ })
+
+ // eslint-disable-next-line import/namespace
+ const encryptedToken = CryptoJS.AES.encrypt(dataToEncrypt, Config.DATA_ENCRYPTION_KEY!).toString()
+
+ const qrCodeSvg = await generateQRCodeString(encryptedToken)
+
+ const prettyVc = w3cCredential?.credential.prettyVc
+ let content = prettyVc.certificate
+
+ const contactDetailsPlaceholder = '{{qrcode}}'
+ const contactDetailsEscapedPlaceholder = contactDetailsPlaceholder.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
+
+ content = content.replace(new RegExp(contactDetailsEscapedPlaceholder, 'g'), qrCodeSvg)
+
+ Object.keys(certificateAttributes).forEach(key => {
+ // Statically picking the value of placeholder
+ const placeholder = `{{credential['${key}']}}`
+ // Escaping the placeholder to avoid regex issues
+ const escapedPlaceholder = placeholder.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
+ // Replacing the placeholder with the actual value
+ content = content.replace(new RegExp(escapedPlaceholder, 'g'), certificateAttributes[key])
+ })
+
+ const options: RNHTMLtoPDF.Options = {
+ html: content,
+ fileName: w3cCredential?.credential.type[1],
+ directory: 'Documents',
+ // add height and width to the options of a4 paper size
+ ...getA4Sizes(prettyVc.orientation),
+ }
+
+ const file = await RNHTMLtoPDF.convert(options)
+
+ let filePath = file.filePath as string
+
+ if (Platform.OS === 'android') {
+ filePath = 'file://' + filePath
+ }
+
+ navigation.navigate(Screens.RenderCertificate, {
+ filePath,
+ })
+
+ setIsGeneratingPdf(false)
+ } catch (error) {
+ setIsGeneratingPdf(false)
+ // eslint-disable-next-line no-console
+ console.log('Error generating pdf : ', error)
+ }
+ }
+
return (
{w3cCredential && (
@@ -313,6 +401,9 @@ const CredentialDetailsW3C: React.FC = ({ navigation, ro
hideFieldValues
header={header}
footer={footer}
+ w3cCredential={w3cCredential}
+ renderCertificate={navigateToRenderCertificate}
+ isCertificateLoading={isGeneratingPdf}
/>
)}
= ({ navigation, ro
visible={isRemoveModalDisplayed}
onSubmit={callSubmitRemove}
onCancel={callCancelRemove}
+ disabled={isDeletingCredential}
/>
)
diff --git a/app/screens/CredentialOffer.tsx b/app/screens/CredentialOffer.tsx
index c490e7e6..327d6309 100644
--- a/app/screens/CredentialOffer.tsx
+++ b/app/screens/CredentialOffer.tsx
@@ -8,6 +8,8 @@ import {
acceptCredentialOffer,
declineCredentialOffer,
sendCredentialProblemReport,
+ AutoAcceptCredential,
+ useConnections,
} from '@adeya/ssi'
import { BrandingOverlay } from '@hyperledger/aries-oca'
import { CredentialOverlay } from '@hyperledger/aries-oca/build/legacy'
@@ -34,7 +36,7 @@ import { W3CCredentialAttributeField } from '../types/record'
import { ModalUsage } from '../types/remove'
import { useAppAgent } from '../utils/agent'
import { buildFieldsFromJSONLDCredential, formatCredentialSubject, getCredentialIdentifiers } from '../utils/credential'
-import { getCredentialConnectionLabel } from '../utils/helpers'
+import { getCredentialConnectionLabel, getDefaultHolderDidDocument } from '../utils/helpers'
import { buildFieldsFromAnonCredsCredential } from '../utils/oca'
import { testIdWithKey } from '../utils/testable'
@@ -63,7 +65,8 @@ const CredentialOffer: React.FC = ({ navigation, route })
const credential = useCredentialById(credentialId)
const [jsonLdOffer, setJsonLdOffer] = useState()
const [tables, setTables] = useState([])
- const credentialConnectionLabel = getCredentialConnectionLabel(credential)
+ const { records } = useConnections()
+ const credentialConnectionLabel = getCredentialConnectionLabel(records, credential)
const styles = StyleSheet.create({
headerTextContainer: {
@@ -83,16 +86,7 @@ const CredentialOffer: React.FC = ({ navigation, route })
})
useEffect(() => {
- if (!agent) {
- DeviceEventEmitter.emit(
- EventTypes.ERROR_ADDED,
- new BifoldError(t('Error.Title1035'), t('Error.Message1035'), t('CredentialOffer.CredentialNotFound'), 1035),
- )
- }
- }, [])
-
- useEffect(() => {
- if (!credential) {
+ if (!agent && !credential) {
DeviceEventEmitter.emit(
EventTypes.ERROR_ADDED,
new BifoldError(t('Error.Title1035'), t('Error.Message1035'), t('CredentialOffer.CredentialNotFound'), 1035),
@@ -161,7 +155,38 @@ const CredentialOffer: React.FC = ({ navigation, route })
return
}
setAcceptModalVisible(true)
- await acceptCredentialOffer(agent, { credentialRecordId: credential.id })
+
+ 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 &&
+ credentialFormatData?.offer?.jsonld
+ ) {
+ const holderDid = await getDefaultHolderDidDocument(agent)
+ await agent.credentials.negotiateOffer({
+ credentialFormats: {
+ jsonld: {
+ credential: {
+ ...credentialFormatData?.offer?.jsonld?.credential,
+ credentialSubject: {
+ ...credentialFormatData?.offer?.jsonld?.credential?.credentialSubject,
+ // Added holder did as id if did is not present
+ id: holderDid?.id,
+ },
+ },
+ options: {
+ ...credentialFormatData?.offer?.jsonld?.options,
+ },
+ },
+ },
+ credentialRecordId: credential.id,
+ // we added auto accept credential to always accept the credential further flows
+ autoAcceptCredential: AutoAcceptCredential.Always,
+ })
+ } else {
+ await acceptCredentialOffer(agent, { credentialRecordId: credential.id })
+ }
} catch (err: unknown) {
setButtonsVisible(true)
const error = new BifoldError(t('Error.Title1024'), t('Error.Message1024'), (err as Error).message, 1024)
@@ -198,31 +223,12 @@ const CredentialOffer: React.FC = ({ navigation, route })
{t('CredentialOffer.IsOfferingYouACredential')}
- {!loading && credential && (
-
-
-
- )}
- >
- )
- }
-
- const jsonLdHeader = () => {
- return (
- <>
-
-
-
- {credentialConnectionLabel || t('ContactDetails.AContact')}{' '}
- {t('CredentialOffer.IsOfferingYouACredential')}
-
-
{!loading && credential && (
)}
@@ -271,7 +277,7 @@ const CredentialOffer: React.FC = ({ navigation, route })
tables={tables}
fields={overlay.presentationFields || []}
hideFieldValues={false}
- header={jsonLdHeader}
+ header={header}
footer={footer}
/>
) : (
diff --git a/app/screens/ExportWallet.tsx b/app/screens/ExportWallet.tsx
index ccfdadf6..28b5b5a3 100644
--- a/app/screens/ExportWallet.tsx
+++ b/app/screens/ExportWallet.tsx
@@ -1,4 +1,5 @@
-import { useNavigation } from '@react-navigation/core'
+import { addWalletRecord, findWalletRecordsByQuery, useAdeyaAgent, utils } from '@adeya/ssi'
+import { useNavigation, useRoute } from '@react-navigation/core'
import { generateMnemonic } from 'bip39'
import React, { useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'
@@ -13,6 +14,9 @@ const ExportWallet: React.FC = () => {
const navigation = useNavigation()
const { t } = useTranslation()
const [phraseData, setPhraseData] = useState([])
+ const { agent } = useAdeyaAgent()
+ const route = useRoute()
+ const { backupType }: { backupType?: string } = route.params || {}
const { width: SCREEN_WIDTH, height: SCREEN_HEIGHT } = Dimensions.get('window')
@@ -86,15 +90,42 @@ const ExportWallet: React.FC = () => {
})
useEffect(() => {
- const mnemonic = generateMnemonic(128)
- const mnemonicArray = mnemonic.split(' ')
+ const createMnemonic = async () => {
+ const mnemonicRecord = await findWalletRecordsByQuery(agent, { type: 'mnemonic' })
+ if (mnemonicRecord?.length > 0) {
+ const mnemonic = mnemonicRecord[0].content.mnemonic as string
+ const mnemonicArray = mnemonic.split(' ')
- const mnemonicIndividualWordsArray: string[] = []
- mnemonicArray.forEach(word => {
- mnemonicIndividualWordsArray.push(word)
- })
+ const mnemonicIndividualWordsArray: string[] = []
+ mnemonicArray.forEach(word => {
+ mnemonicIndividualWordsArray.push(word)
+ })
- setPhraseData(mnemonicIndividualWordsArray.splice(1, 8))
+ setPhraseData(mnemonicIndividualWordsArray.splice(1, 8))
+ } else {
+ const mnemonic = generateMnemonic(128)
+ const mnemonicArray = mnemonic.split(' ')
+
+ const mnemonicIndividualWordsArray: string[] = []
+ mnemonicArray.forEach(word => {
+ mnemonicIndividualWordsArray.push(word)
+ })
+
+ await addWalletRecord(agent, {
+ id: utils.uuid(),
+ content: {
+ mnemonic,
+ },
+ tags: {
+ type: 'mnemonic',
+ },
+ })
+
+ setPhraseData(mnemonicIndividualWordsArray.splice(1, 8))
+ }
+ }
+
+ createMnemonic()
}, [])
return (
@@ -128,7 +159,7 @@ const ExportWallet: React.FC = () => {
title={'Continue'}
accessibilityLabel={'Okay'}
buttonType={ButtonType.Primary}
- onPress={() => navigation.navigate(Screens.ExportWalletConfirmation, { phraseData })}
+ onPress={() => navigation.navigate(Screens.ExportWalletConfirmation, { phraseData, backupType })}
/>
diff --git a/app/screens/ExportWalletConfirmation.tsx b/app/screens/ExportWalletConfirmation.tsx
index 56f48d65..e0cd768f 100644
--- a/app/screens/ExportWalletConfirmation.tsx
+++ b/app/screens/ExportWalletConfirmation.tsx
@@ -1,6 +1,9 @@
import { exportWallet as exportAdeyaWallet } from '@adeya/ssi'
+import { GoogleSignin } from '@react-native-google-signin/google-signin'
import { useNavigation, useRoute } from '@react-navigation/core'
+import { GDrive, ListQueryBuilder, MimeTypes } from '@robinbobin/react-native-google-drive-api-wrapper'
import shuffle from 'lodash.shuffle'
+import moment from 'moment'
import React, { useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'
import {
@@ -8,16 +11,15 @@ import {
Text,
TouchableOpacity,
ScrollView,
- PermissionsAndroid,
- Platform,
- Share,
Dimensions,
PixelRatio,
StyleSheet,
+ Platform,
+ Share,
} from 'react-native'
-import { DownloadDirectoryPath, exists, mkdir, unlink } from 'react-native-fs'
+import * as RNFS from 'react-native-fs'
import Toast from 'react-native-toast-message'
-import RNFetchBlob from 'rn-fetch-blob'
+import { zip } from 'react-native-zip-archive'
import ButtonLoading from '../components/animated/ButtonLoading'
import Button, { ButtonType } from '../components/buttons/Button'
@@ -136,19 +138,29 @@ function ExportWalletConfirmation() {
const encodeHash = seed
try {
- const documentDirectory: string = DownloadDirectoryPath
- const backupDirectory = `${documentDirectory}/Wallet_Backup`
- const destFileExists = await exists(backupDirectory)
+ let downloadDirectory = ''
+ if (Platform.OS === 'ios') {
+ downloadDirectory = RNFS.DocumentDirectoryPath
+ } else {
+ downloadDirectory = RNFS.DownloadDirectoryPath
+ }
+
+ const backupTimeStamp = moment().format('YYYY-MM-DD-HH-mm-ss')
+ // const backupDirectory = `${documentDirectory}/Wallet_Backup`
+ const zipUpDirectory = `${downloadDirectory}/ADEYA-Wallet-${backupTimeStamp}`
+
+ const destFileExists = await RNFS.exists(zipUpDirectory)
if (destFileExists) {
- await unlink(backupDirectory)
+ await RNFS.unlink(zipUpDirectory)
}
- const date = new Date()
- const dformat = `${date.getHours()}-${date.getMinutes()}-${date.getSeconds()}`
- const WALLET_FILE_NAME = `SSI_Wallet_${dformat}`
- await mkdir(backupDirectory)
+ const WALLET_FILE_NAME = 'ADEYA_WALLET'
+
+ const zipFileName = `${WALLET_FILE_NAME}-${backupTimeStamp}.zip`
+ await RNFS.mkdir(zipUpDirectory)
const encryptedFileName = `${WALLET_FILE_NAME}.wallet`
- const encryptedFileLocation = `${backupDirectory}/${encryptedFileName}`
+ const encryptedFileLocation = `${zipUpDirectory}/${encryptedFileName}`
+ const destinationZipPath = `${downloadDirectory}/${zipFileName}`
const exportConfig = {
key: encodeHash,
@@ -157,67 +169,79 @@ function ExportWalletConfirmation() {
await exportAdeyaWallet(agent, exportConfig)
- Toast.show({
- type: ToastType.Success,
- text1: 'Backup successfully',
- })
- setMatchPhrase(true)
- navigation.navigate(Screens.Success, { encryptedFileLocation })
- } catch (e) {
- Toast.show({
- type: ToastType.Error,
- text1: 'Backup failed',
- })
- }
- }
- const exportWalletIOS = async (seed: string) => {
- setMatchPhrase(true)
-
- const encodeHash = seed
- const { fs } = RNFetchBlob
- try {
- const documentDirectory = fs.dirs.DocumentDir
-
- const zipDirectory = `${documentDirectory}/Wallet_Backup`
+ await zip(zipUpDirectory, destinationZipPath)
- const destFileExists = await fs.exists(zipDirectory)
- if (destFileExists) {
- await fs.unlink(zipDirectory)
- }
+ await RNFS.unlink(zipUpDirectory)
- const date = new Date()
- const dformat = `${date.getHours()}-${date.getMinutes()}-${date.getSeconds()}`
- const WALLET_FILE_NAME = `SSI_Wallet_${dformat}`
+ if (parms?.params?.backupType === 'google_drive') {
+ const gdrive = new GDrive()
+ gdrive.accessToken = (await GoogleSignin.getTokens()).accessToken
+ gdrive.fetchCoercesTypes = true
+ gdrive.fetchRejectsOnHttpErrors = true
+ gdrive.fetchTimeout = 15000
- await fs.mkdir(zipDirectory).catch(err =>
- Toast.show({
- type: ToastType.Error,
- text1: err,
- }),
- )
- const encryptedFileName = `${WALLET_FILE_NAME}.wallet`
- const encryptedFileLocation = `${zipDirectory}/${encryptedFileName}`
+ const zipFileData = await RNFS.readFile(destinationZipPath, 'base64')
+ try {
+ const { result } = await gdrive.files.createIfNotExists(
+ {
+ q: new ListQueryBuilder()
+ .e('name', 'ADEYA Wallet Backups')
+ .and()
+ .e('mimeType', MimeTypes.FOLDER)
+ .and()
+ .in('root', 'parents'),
+ },
+ gdrive.files.newMetadataOnlyUploader().setRequestBody({
+ name: 'ADEYA Wallet Backups',
+ mimeType: MimeTypes.FOLDER,
+ parents: ['root'],
+ }),
+ )
- const exportConfig = {
- key: encodeHash,
- path: encryptedFileLocation,
- }
-
- await exportAdeyaWallet(agent, exportConfig)
+ const response = await gdrive.files
+ .newMultipartUploader()
+ .setData(zipFileData, 'application/zip')
+ .setIsBase64(true)
+ .setRequestBody({
+ name: zipFileName,
+ parents: [result.id],
+ })
+ .execute()
- if (Platform.OS === 'ios') {
- await Share.share({
- title: 'Share file',
- url: encryptedFileLocation,
- })
+ const folderData = await gdrive.files.getMetadata(result.id)
+ const fileData = await gdrive.files.getMetadata(response.id)
+ Toast.show({
+ type: ToastType.Success,
+ text1: t('GoogleDrive.BackupSuccess'),
+ })
+ setMatchPhrase(true)
+ navigation.navigate(Screens.Success, {
+ encryptedFileLocation: `Backup file uploaded successfully to Google Drive\n\nFolder: ${folderData.name}\n\nFile: ${fileData.name}`,
+ })
+ return
+ } catch (e) {
+ Toast.show({
+ type: ToastType.Error,
+ text1: t('GoogleDrive.BackupFailed'),
+ position: 'bottom',
+ })
+ return
+ }
+ } else {
+ if (Platform.OS === 'ios') {
+ await Share.share({
+ title: 'Share backup zip file',
+ url: destinationZipPath,
+ })
+ }
}
Toast.show({
type: ToastType.Success,
- text1: 'Backup successfully',
+ text1: 'Backup successfully completed',
})
setMatchPhrase(true)
- navigation.navigate(Screens.Success, { encryptedFileLocation })
+ navigation.navigate(Screens.Success, { encryptedFileLocation: destinationZipPath })
} catch (e) {
Toast.show({
type: ToastType.Error,
@@ -248,36 +272,14 @@ function ExportWalletConfirmation() {
setNextPhraseIndex(index)
}
- const askPermission = async (sysPassPhrase: string) => {
- if (Platform.OS === 'android') {
- try {
- const granted = await PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE, {
- title: 'Permission',
- message: 'ADEYA Wallet needs to write to storage',
- buttonPositive: '',
- })
- if (granted === PermissionsAndroid.RESULTS.GRANTED) {
- await exportWallet(sysPassPhrase)
- }
- } catch (error) {
- Toast.show({
- type: ToastType.Error,
- text1: `${error}`,
- })
- }
- } else {
- await exportWalletIOS(sysPassPhrase)
- }
- }
-
- const verifyPhrase = () => {
+ const verifyPhrase = async () => {
const addedPassPhraseData = arraySetPhraseData.join('')
const displayedPassphrase = parms?.params?.phraseData.map(item => item).join('')
if (displayedPassphrase.trim() !== '') {
const sysPassPhrase = addedPassPhraseData.trim()
const userPassphrase = displayedPassphrase.trim()
if (sysPassPhrase === userPassphrase) {
- askPermission(sysPassPhrase)
+ await exportWallet(sysPassPhrase)
} else {
Toast.show({
type: ToastType.Error,
diff --git a/app/screens/GoogleDriveSignIn.tsx b/app/screens/GoogleDriveSignIn.tsx
new file mode 100644
index 00000000..38b6f64a
--- /dev/null
+++ b/app/screens/GoogleDriveSignIn.tsx
@@ -0,0 +1,60 @@
+import AsyncStorage from '@react-native-async-storage/async-storage'
+import { GoogleSignin, GoogleSigninButton, statusCodes, User } from '@react-native-google-signin/google-signin'
+import { useNavigation } from '@react-navigation/core'
+import React, { useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import { View, StyleSheet, Alert } from 'react-native'
+
+import { useAuth } from '../contexts/auth'
+import { useTheme } from '../contexts/theme'
+import { Screens } from '../types/navigators'
+
+const GoogleDriveSignIn: React.FC = () => {
+ const [, setUserInfo] = useState(null)
+ const { ColorPallet } = useTheme()
+ const navigation = useNavigation()
+ const { t } = useTranslation()
+ const { googleSignIn } = useAuth()
+ const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ justifyContent: 'center',
+ alignItems: 'center',
+ backgroundColor: ColorPallet.brand.primaryBackground,
+ },
+ })
+
+ const authenticateWithGoogle = async () => {
+ try {
+ await GoogleSignin.hasPlayServices()
+ const googleUserInfo = await GoogleSignin.signIn()
+ setUserInfo(googleUserInfo)
+ await AsyncStorage.setItem('googleUserInfo', JSON.stringify(googleUserInfo))
+ googleSignIn()
+ navigation.replace(Screens.ExportWallet, { backupType: 'google_drive' })
+ } catch (error: any) {
+ if (error.code === statusCodes.SIGN_IN_CANCELLED) {
+ Alert.alert('Sign-In Cancelled', t('GoogleDrive.SignInCancelled'))
+ } else if (error.code === statusCodes.IN_PROGRESS) {
+ Alert.alert('Sign-In In Progress', t('GoogleDrive.SignInProgress'))
+ } else if (error.code === statusCodes.PLAY_SERVICES_NOT_AVAILABLE) {
+ Alert.alert('Play Services Not Available', t('GoogleDrive.PlayServicesNotAvailable'))
+ } else {
+ Alert.alert('Sign-In Error', t('GoogleDrive.SignInError'))
+ }
+ }
+ }
+
+ return (
+
+
+
+ )
+}
+
+export default GoogleDriveSignIn
diff --git a/app/screens/Home.tsx b/app/screens/Home.tsx
index 9194b925..54b9061f 100644
--- a/app/screens/Home.tsx
+++ b/app/screens/Home.tsx
@@ -1,6 +1,6 @@
-// import { useAdeyaAgent,TypedArrayEncoder } from '@adeya/ssi'
+import { useAdeyaAgent } from '@adeya/ssi'
import { StackScreenProps } from '@react-navigation/stack'
-import React, { ReactNode } from 'react'
+import React, { ReactNode, useEffect } from 'react'
import { useTranslation } from 'react-i18next'
import { FlatList, StyleSheet, View, Text, Dimensions, TouchableOpacity, Image } from 'react-native'
@@ -11,6 +11,8 @@ import { AttachTourStep } from '../components/tour/AttachTourStep'
import { useConfiguration } from '../contexts/configuration'
import { useTheme } from '../contexts/theme'
import { HomeStackParams, Screens } from '../types/navigators'
+import { AdeyaAgentModules } from '../utils/agent'
+import { getDefaultHolderDidDocument } from '../utils/helpers'
const { width } = Dimensions.get('window')
const offset = 25
@@ -19,27 +21,21 @@ const offsetPadding = 5
type HomeProps = StackScreenProps
const Home: React.FC = ({ navigation }) => {
+ const { agent } = useAdeyaAgent()
const { useCustomNotifications } = useConfiguration()
const { notifications } = useCustomNotifications()
const { t } = useTranslation()
- // const { agent } = useAdeyaAgent()
- // This syntax is required for the jest mocks to work
- // eslint-disable-next-line import/no-named-as-default-member
const { HomeTheme } = useTheme()
- // const createDid = async () => {
- // const holderDid = await agent.dids.create({
- // method: 'key',
- // options: {
- // keyType: 'ed25519',
- // },
- // secret: {
- // privateKey: TypedArrayEncoder.fromString('afjdemoverysecure000000000000key'),
- // },
- // })
- // // eslint-disable-next-line no-console
- // console.log('holderDid', holderDid)
- // }
+ useEffect(() => {
+ if (!agent) return
+
+ const setupDefaultDid = async () => {
+ await getDefaultHolderDidDocument(agent)
+ }
+
+ setupDefaultDid()
+ }, [agent])
const styles = StyleSheet.create({
container: {
diff --git a/app/screens/ImportWalletConfirmation.tsx b/app/screens/ImportWalletConfirmation.tsx
index 01b9b93f..75702469 100644
--- a/app/screens/ImportWalletConfirmation.tsx
+++ b/app/screens/ImportWalletConfirmation.tsx
@@ -4,11 +4,12 @@ import {
LogLevel,
InitConfig,
getAgentModules,
- isWalletImportable,
DidsModule,
IndyVdrIndyDidResolver,
SingleContextStorageLruCache,
CacheModule,
+ MediatorPickupStrategy,
+ WebDidResolver,
} from '@adeya/ssi'
import { PolygonDidResolver, PolygonModule } from '@ayanworks/credo-polygon-w3c-module'
import { StackScreenProps } from '@react-navigation/stack'
@@ -24,11 +25,13 @@ import {
Keyboard,
ScrollView,
} from 'react-native'
+import ReactNativeBlobUtil from 'react-native-blob-util'
import { Config } from 'react-native-config'
-import { DocumentPickerResponse, isCancel, pickSingle, types } from 'react-native-document-picker'
+import { isCancel, pickSingle, types } from 'react-native-document-picker'
import * as RNFS from 'react-native-fs'
import { heightPercentageToDP } from 'react-native-responsive-screen'
import { Toast } from 'react-native-toast-message/lib/src/Toast'
+import { unzip } from 'react-native-zip-archive'
import indyLedgers from '../../configs/ledgers/indy'
import ButtonLoading from '../components/animated/ButtonLoading'
@@ -128,9 +131,15 @@ const ImportWalletVerify: React.FC = ({ navigation }) =
key: credentials.key,
}
+ const { fs } = ReactNativeBlobUtil
+ const restoreDirectoryPath = `${fs.dirs.DocumentDir}`
+ const walletFilePath = `${restoreDirectoryPath}/ADEYA_WALLET_RESTORE/ADEYA_WALLET.wallet`
+
+ await unzip(selectedFilePath, restoreDirectoryPath + '/ADEYA_WALLET_RESTORE')
+
const importConfig = {
key: encodeHash,
- path: selectedFilePath,
+ path: walletFilePath,
}
const agentConfig: InitConfig = {
@@ -140,26 +149,18 @@ const ImportWalletVerify: React.FC = ({ navigation }) =
autoUpdateStorageOnStartup: true,
}
- const walletImportCheck = await isWalletImportable({ ...walletConfig }, importConfig)
-
- if (!walletImportCheck) {
- Toast.show({
- type: ToastType.Error,
- text1: `You've entered an invalid passphrase.`,
- position: 'bottom',
- })
- setVerify(false)
- return
- }
-
const agent = await importWalletWithAgent({
agentConfig,
importConfig,
modules: {
- ...getAgentModules(Config.MEDIATOR_URL!, indyLedgers),
+ ...getAgentModules({
+ indyNetworks: indyLedgers,
+ mediatorInvitationUrl: Config.MEDIATOR_URL!,
+ mediatorPickupStrategy: MediatorPickupStrategy.PickUpV2LiveMode,
+ }),
polygon: new PolygonModule({}),
dids: new DidsModule({
- resolvers: [new PolygonDidResolver(), new IndyVdrIndyDidResolver()],
+ resolvers: [new PolygonDidResolver(), new IndyVdrIndyDidResolver(), new WebDidResolver()],
}),
cache: new CacheModule({
cache: new SingleContextStorageLruCache({
@@ -169,6 +170,8 @@ const ImportWalletVerify: React.FC = ({ navigation }) =
},
})
+ await RNFS.unlink(restoreDirectoryPath + '/ADEYA_WALLET_RESTORE')
+
setAgent(agent!)
setVerify(true)
Toast.show({
@@ -204,21 +207,11 @@ const ImportWalletVerify: React.FC = ({ navigation }) =
const handleSelect = async () => {
try {
- const res: DocumentPickerResponse = await pickSingle({
- type: [types.allFiles],
+ const res = await pickSingle({
+ type: [types.zip],
copyTo: 'documentDirectory',
})
- if (!res.name?.endsWith('.wallet')) {
- Toast.show({
- type: ToastType.Error,
- text1: 'Please select a valid wallet file',
- visibilityTime: 2000,
- })
- navigation.goBack()
- return
- }
-
if (!res.fileCopyUri) {
Toast.show({
type: ToastType.Error,
diff --git a/app/screens/ListContacts.tsx b/app/screens/ListContacts.tsx
index 7850e9d9..c42a8530 100644
--- a/app/screens/ListContacts.tsx
+++ b/app/screens/ListContacts.tsx
@@ -1,4 +1,4 @@
-import { ConnectionRecord, ConnectionType, useConnections } from '@adeya/ssi'
+import { ConnectionRecord, ConnectionType, DidExchangeState, useConnections } from '@adeya/ssi'
import { StackNavigationProp } from '@react-navigation/stack'
import React, { useEffect } from 'react'
import { useTranslation } from 'react-i18next'
@@ -31,10 +31,12 @@ const ListContacts: React.FC = ({ navigation }) => {
})
const { records } = useConnections()
const [store] = useStore()
- // Filter out mediator agents
+ // Filter out mediator agents and connections that are not completed
let connections: ConnectionRecord[] = records
if (!store.preferences.developerModeEnabled) {
- connections = records.filter(r => !r.connectionTypes.includes(ConnectionType.Mediator))
+ connections = records.filter(
+ r => !r.connectionTypes.includes(ConnectionType.Mediator) && r.state === DidExchangeState.Completed,
+ )
}
const onPressAddContact = () => {
diff --git a/app/screens/ListCredentials.tsx b/app/screens/ListCredentials.tsx
index 79a370b7..f66901d8 100644
--- a/app/screens/ListCredentials.tsx
+++ b/app/screens/ListCredentials.tsx
@@ -4,8 +4,8 @@ import {
useCredentialByState,
CredentialExchangeRecord,
CredentialState,
- findConnectionById,
- getW3cCredentialRecordById,
+ useConnections,
+ getAllW3cCredentialRecords,
} from '@adeya/ssi'
import { useNavigation } from '@react-navigation/core'
import { StackNavigationProp } from '@react-navigation/stack'
@@ -42,6 +42,7 @@ const ListCredentials: React.FC = () => {
...useCredentialByState(CredentialState.Done),
]
const [credentialList, setCredentialList] = useState<(CredentialExchangeRecord | EnhancedW3CRecord)[] | undefined>([])
+ const { records: connectionRecords } = useConnections()
const navigation = useNavigation>()
const { ColorPallet } = useTheme()
@@ -52,33 +53,33 @@ const ListCredentials: React.FC = () => {
return
}
- const updatedCredentials = await Promise.all(
- credentials.map(async credential => {
- if (isW3CCredential(credential)) {
- const credentialRecordId = credential.credentials[0].credentialRecordId
- try {
- const record = await getW3cCredentialRecordById(agent, credentialRecordId)
- if (!credential?.connectionId) {
- throw new Error('Connection Id notfound')
- }
- const connection = await findConnectionById(agent, credential?.connectionId)
- const enhancedRecord = record as EnhancedW3CRecord
- enhancedRecord.connectionLabel = connection?.theirLabel
- return enhancedRecord
- } catch (e: unknown) {
- throw new Error(`${e}`)
+ const w3cCredentialRecords = await getAllW3cCredentialRecords(agent)
+
+ const updatedCredentials = credentials.map(credential => {
+ if (isW3CCredential(credential)) {
+ const credentialRecordId = credential.credentials[0].credentialRecordId
+ try {
+ const record = w3cCredentialRecords.find(record => record.id === credentialRecordId)
+ if (!credential?.connectionId) {
+ throw new Error('Connection Id notfound')
}
+ const connection = connectionRecords.find(connection => connection.id === credential?.connectionId)
+ const enhancedRecord = record as EnhancedW3CRecord
+ enhancedRecord.connectionLabel = connection?.theirLabel
+ return enhancedRecord
+ } catch (e: unknown) {
+ throw new Error(`${e}`)
}
- return credential
- }),
- )
+ }
+ return credential
+ })
return updatedCredentials
}
updateCredentials().then(updatedCredentials => {
setCredentialList(updatedCredentials)
})
- }, [])
+ }, [credentials])
return (
diff --git a/app/screens/OnboardingPages.tsx b/app/screens/OnboardingPages.tsx
index 6d19c7a3..8faba6ce 100644
--- a/app/screens/OnboardingPages.tsx
+++ b/app/screens/OnboardingPages.tsx
@@ -1,5 +1,3 @@
-/* eslint-disable import/order */
-
import React from 'react'
import { Image, ScrollView, StyleSheet, Text, View, ImageBackground } from 'react-native'
import { SvgProps } from 'react-native-svg'
@@ -9,10 +7,8 @@ import onBoardingDataSafe from '../assets/img/onBoardingdatasafe.svg'
import Button, { ButtonType } from '../components/buttons/Button'
import { useStore } from '../contexts/store'
import { styles } from '../onboardingStyles'
-
import { ITheme, theme } from '../theme'
import { GenericFn } from '../types/fn'
-
import { testIdWithKey } from '../utils/testable'
import { OnboardingStyleSheet } from './Onboarding'
diff --git a/app/screens/OrganizationDetails.tsx b/app/screens/OrganizationDetails.tsx
index 13c74fb7..fd5b2bcf 100644
--- a/app/screens/OrganizationDetails.tsx
+++ b/app/screens/OrganizationDetails.tsx
@@ -155,11 +155,11 @@ const OrganizationDetails: React.FC = () => {
const handleInvitation = async (value: string): Promise => {
try {
- const { connectionRecord } = await connectFromInvitation(agent, value)
+ const { connectionRecord, outOfBandRecord } = await connectFromInvitation(agent, value)
navigation.getParent()?.navigate(Stacks.ConnectionStack, {
screen: Screens.Connection,
- params: { connectionId: connectionRecord?.id },
+ params: { connectionId: connectionRecord?.id, outOfBandId: outOfBandRecord.id },
})
} catch (err: unknown) {
try {
@@ -188,11 +188,11 @@ const OrganizationDetails: React.FC = () => {
return
}
- const { connectionRecord } = await connectFromInvitation(agent, urlData)
+ const { connectionRecord, outOfBandRecord } = await connectFromInvitation(agent, urlData)
navigation.getParent()?.navigate(Stacks.ConnectionStack, {
screen: Screens.Connection,
- params: { connectionId: connectionRecord?.id },
+ params: { connectionId: connectionRecord?.id, outOfBandId: outOfBandRecord.id },
})
return
}
diff --git a/app/screens/ProofChangeCredentialW3C.tsx b/app/screens/ProofChangeCredentialW3C.tsx
new file mode 100644
index 00000000..ea0fa297
--- /dev/null
+++ b/app/screens/ProofChangeCredentialW3C.tsx
@@ -0,0 +1,128 @@
+import { StackScreenProps } from '@react-navigation/stack'
+import React, { useEffect, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import { DeviceEventEmitter, FlatList, StyleSheet, Text, View } from 'react-native'
+import { SafeAreaView } from 'react-native-safe-area-context'
+
+import RecordLoading from '../components/animated/RecordLoading'
+import { CredentialCard } from '../components/misc'
+import { EventTypes } from '../constants'
+import { useTheme } from '../contexts/theme'
+import { useAllCredentialsForProof } from '../hooks/proofs'
+import { BifoldError } from '../types/error'
+import { ProofRequestsStackParams, Screens } from '../types/navigators'
+import { ProofCredentialItems } from '../types/proof-items'
+import { testIdWithKey } from '../utils/testable'
+
+type ProofChangeProps = StackScreenProps
+
+const ProofChangeCredentialW3C: React.FC = ({ route, navigation }) => {
+ if (!route?.params) {
+ throw new Error('Change credential route params were not set properly')
+ }
+ const proofId = route.params.proofId
+ const selectedCred = route.params.selectedCred
+ const altCredentials = route.params.altCredentials
+ const onCredChange = route.params.onCredChange
+ const { ColorPallet, TextTheme } = useTheme()
+ const { t } = useTranslation()
+ const [loading, setLoading] = useState(false)
+ const [proofItems, setProofItems] = useState([])
+ const credProofPromise = useAllCredentialsForProof(proofId)
+ const styles = StyleSheet.create({
+ pageContainer: {
+ flex: 1,
+ },
+ pageMargin: {
+ marginHorizontal: 20,
+ },
+ cardLoading: {
+ backgroundColor: ColorPallet.brand.secondaryBackground,
+ flex: 1,
+ flexGrow: 1,
+ marginVertical: 35,
+ borderRadius: 15,
+ paddingHorizontal: 10,
+ },
+ selectedCred: {
+ borderWidth: 5,
+ borderRadius: 15,
+ borderColor: ColorPallet.semantic.focus,
+ },
+ })
+
+ useEffect(() => {
+ setLoading(true)
+
+ credProofPromise
+ ?.then(value => {
+ if (value) {
+ const { groupedProof } = value
+ setLoading(false)
+
+ const activeCreds = groupedProof.filter(proof => altCredentials.includes(proof.credId))
+
+ setProofItems(activeCreds)
+ }
+ })
+ .catch((err: unknown) => {
+ const error = new BifoldError(
+ t('Error.Title1026'),
+ t('Error.Message1026'),
+ (err as Error)?.message ?? err,
+ 1026,
+ )
+ DeviceEventEmitter.emit(EventTypes.ERROR_ADDED, error)
+ })
+ }, [])
+
+ const listHeader = () => {
+ return (
+
+ {loading ? (
+
+
+
+ ) : (
+ {t('ProofRequest.MultipleCredentials')}
+ )}
+
+ )
+ }
+
+ const changeCred = (credId: string) => {
+ onCredChange(credId)
+ navigation.goBack()
+ }
+
+ return (
+
+ {
+ return (
+
+
+ changeCred(item.credId ?? '')}
+ />
+
+
+ )
+ }}>
+
+ )
+}
+
+export default ProofChangeCredentialW3C
diff --git a/app/screens/ProofRequest.tsx b/app/screens/ProofRequest.tsx
index 33c1acdc..6df878b0 100644
--- a/app/screens/ProofRequest.tsx
+++ b/app/screens/ProofRequest.tsx
@@ -8,7 +8,6 @@ import {
AnonCredsRequestedPredicateMatch,
deleteConnectionRecordById,
getProofFormatData,
- selectCredentialsForProofRequest,
acceptProofRequest,
declineProofRequest,
sendProofProblemReport,
@@ -129,16 +128,7 @@ const ProofRequest: React.FC = ({ navigation, route }) => {
})
useEffect(() => {
- if (!agent) {
- DeviceEventEmitter.emit(
- EventTypes.ERROR_ADDED,
- new BifoldError(t('Error.Title1034'), t('Error.Message1034'), t('ProofRequest.ProofRequestNotFound'), 1034),
- )
- }
- }, [])
-
- useEffect(() => {
- if (!proof) {
+ if (!agent && !proof) {
DeviceEventEmitter.emit(
EventTypes.ERROR_ADDED,
new BifoldError(t('Error.Title1034'), t('Error.Message1034'), t('ProofRequest.ProofRequestNotFound'), 1034),
@@ -297,6 +287,21 @@ const ProofRequest: React.FC = ({ navigation, route }) => {
const hasSatisfiedPredicates = (fields: Fields, credId?: string) =>
activeCreds.flatMap(item => evaluatePredicates(fields, credId)(item)).every(p => p.satisfied)
+ const formatCredentials = (
+ retrievedItems: Record,
+ credList: string[],
+ ) => {
+ return Object.keys(retrievedItems)
+ .map(key => {
+ return {
+ [key]: retrievedItems[key].find(cred => credList.includes(cred.credentialId)),
+ }
+ })
+ .reduce((prev, current) => {
+ return { ...prev, ...current }
+ }, {})
+ }
+
const handleAcceptPress = async () => {
try {
if (!(agent && proof && assertConnectedNetwork())) {
@@ -312,14 +317,19 @@ const ProofRequest: React.FC = ({ navigation, route }) => {
const formatToUse = format.request?.anoncreds ? 'anoncreds' : 'indy'
- const automaticRequestedCreds =
- retrievedCredentials &&
- (await selectCredentialsForProofRequest(agent, {
- proofRecordId: proof.id,
- proofFormats: {
- [formatToUse]: {},
- },
- }))
+ const credObject = {
+ ...retrievedCredentials,
+ attributes: formatCredentials(
+ retrievedCredentials.attributes,
+ activeCreds.map(item => item.credId),
+ ),
+ predicates: formatCredentials(
+ retrievedCredentials.predicates,
+ activeCreds.map(item => item.credId),
+ ),
+ selfAttestedAttributes: {},
+ }
+ const automaticRequestedCreds = { proofFormats: { [formatToUse]: { ...credObject } } }
if (!automaticRequestedCreds) {
throw new Error(t('ProofRequest.RequestedCredentialsCouldNotBeFound'))
diff --git a/app/screens/ProofRequestW3C.tsx b/app/screens/ProofRequestW3C.tsx
new file mode 100644
index 00000000..362c56f9
--- /dev/null
+++ b/app/screens/ProofRequestW3C.tsx
@@ -0,0 +1,503 @@
+import type { StackScreenProps } from '@react-navigation/stack'
+
+import {
+ useConnectionById,
+ useProofById,
+ deleteConnectionRecordById,
+ acceptProofRequest,
+ declineProofRequest,
+ sendProofProblemReport,
+ GetCredentialsForRequestReturn,
+ DifPresentationExchangeProofFormatService,
+ utils,
+} from '@adeya/ssi'
+// eslint-disable-next-line import/no-extraneous-dependencies
+import { DifPexCredentialsForRequestRequirement, SubmissionEntryCredential } from '@credo-ts/core'
+import React, { useEffect, useMemo, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import { DeviceEventEmitter, FlatList, ScrollView, StyleSheet, Text, View } from 'react-native'
+import { SafeAreaView } from 'react-native-safe-area-context'
+import Icon from 'react-native-vector-icons/MaterialIcons'
+
+import Button, { ButtonType } from '../components/buttons/Button'
+import { CredentialCard } from '../components/misc'
+import ConnectionImage from '../components/misc/ConnectionImage'
+import CommonRemoveModal from '../components/modals/CommonRemoveModal'
+import { CREDENTIAL, EventTypes } from '../constants'
+import { useAnimatedComponents } from '../contexts/animated-components'
+import { useConfiguration } from '../contexts/configuration'
+import { useNetwork } from '../contexts/network'
+import { useTheme } from '../contexts/theme'
+import { useOutOfBandByConnectionId } from '../hooks/connections'
+import { useAllCredentialsForProof } from '../hooks/proofs'
+import { BifoldError } from '../types/error'
+import { NotificationStackParams, Screens, Stacks, TabStacks } from '../types/navigators'
+import { ProofCredentialItems } from '../types/proof-items'
+import { ModalUsage } from '../types/remove'
+import { useAppAgent } from '../utils/agent'
+import { testIdWithKey } from '../utils/testable'
+
+import ProofRequestAccept from './ProofRequestAccept'
+
+type ProofRequestProps = StackScreenProps
+
+interface CredentialListProps {
+ header?: JSX.Element
+ footer?: JSX.Element
+ items: ProofCredentialItems[]
+}
+
+const ProofRequestW3C: React.FC = ({ navigation, route }) => {
+ if (!route?.params) {
+ throw new Error('ProofRequest route prams were not set properly')
+ }
+
+ // eslint-disable-next-line no-unsafe-optional-chaining
+ const { proofId } = route?.params
+ const { agent } = useAppAgent()
+ const { t } = useTranslation()
+ const { assertConnectedNetwork } = useNetwork()
+ const proof = useProofById(proofId)
+ const connection = proof?.connectionId ? useConnectionById(proof.connectionId) : undefined
+ const proofConnectionLabel = connection?.theirLabel ?? proof?.connectionId ?? ''
+ const [pendingModalVisible, setPendingModalVisible] = useState(false)
+ const [retrievedCredentials, setRetrievedCredentials] = useState<{
+ attributes: Record
+ predicates: Record
+ }>()
+ const [loading, setLoading] = useState(true)
+ const [declineModalVisible, setDeclineModalVisible] = useState(false)
+ const { ColorPallet, ListItems, TextTheme } = useTheme()
+ const { RecordLoading } = useAnimatedComponents()
+ const goalCode = useOutOfBandByConnectionId(agent, proof?.connectionId ?? '')?.outOfBandInvitation.goalCode
+ const { OCABundleResolver } = useConfiguration()
+ const [containsPI, setContainsPI] = useState(false)
+ const [activeCreds, setActiveCreds] = useState([])
+ const [selectedCredentials, setSelectedCredentials] = useState([])
+ const credProofPromise = useAllCredentialsForProof(proofId)
+
+ const hasMatchingCredDef = useMemo(
+ () => activeCreds.some(cred => cred.credExchangeRecord !== undefined),
+ [activeCreds],
+ )
+ const styles = StyleSheet.create({
+ pageContainer: {
+ flex: 1,
+ },
+ pageContent: {
+ flexGrow: 1,
+ justifyContent: 'space-between',
+ },
+ pageMargin: {
+ marginHorizontal: 20,
+ },
+ pageFooter: {
+ marginBottom: 15,
+ },
+ headerTextContainer: {
+ paddingVertical: 16,
+ },
+ headerText: {
+ ...ListItems.recordAttributeText,
+ flexShrink: 1,
+ },
+ footerButton: {
+ paddingTop: 10,
+ },
+ link: {
+ ...ListItems.recordAttributeText,
+ ...ListItems.recordLink,
+ paddingVertical: 2,
+ },
+ valueContainer: {
+ minHeight: ListItems.recordAttributeText.fontSize,
+ paddingVertical: 4,
+ },
+ detailsButton: {
+ ...ListItems.recordAttributeText,
+ color: ColorPallet.brand.link,
+ textDecorationLine: 'underline',
+ },
+ cardLoading: {
+ backgroundColor: ColorPallet.brand.secondaryBackground,
+ flex: 1,
+ flexGrow: 1,
+ marginVertical: 35,
+ borderRadius: 15,
+ paddingHorizontal: 10,
+ },
+ })
+
+ useEffect(() => {
+ if (!agent && !proof) {
+ DeviceEventEmitter.emit(
+ EventTypes.ERROR_ADDED,
+ new BifoldError(t('Error.Title1034'), t('Error.Message1034'), t('ProofRequest.ProofRequestNotFound'), 1034),
+ )
+ }
+ }, [])
+
+ useEffect(() => {
+ setLoading(true)
+ credProofPromise
+ ?.then(value => {
+ if (value) {
+ const { groupedProof, retrievedCredentials } = value
+ const retrievedCreds = retrievedCredentials as GetCredentialsForRequestReturn<
+ [DifPresentationExchangeProofFormatService]
+ >['proofFormats']['presentationExchange']
+ setLoading(false)
+ let credList: string[] = []
+ if (selectedCredentials.length > 0) {
+ credList = selectedCredentials
+ } else {
+ // we only want one of each satisfying credential
+ groupedProof.forEach(item => {
+ const credId = item.altCredentials?.[0]
+ if (credId && !credList.includes(credId)) {
+ credList.push(credId)
+ }
+ })
+ }
+
+ const formatCredentials = (retrievedItems: DifPexCredentialsForRequestRequirement[], credList: string[]) => {
+ return retrievedItems
+ .map(item => {
+ return {
+ [item.submissionEntry[0].inputDescriptorId]: item.submissionEntry[0].verifiableCredentials.filter(
+ cred => credList.includes(cred.credentialRecord.id),
+ ),
+ }
+ })
+ .reduce((prev, curr) => {
+ return {
+ ...prev,
+ ...curr,
+ }
+ }, {})
+ }
+
+ const selectRetrievedCredentials = retrievedCreds
+ ? {
+ attributes: formatCredentials(retrievedCreds.requirements, credList),
+ predicates: {},
+ }
+ : undefined
+
+ setRetrievedCredentials(selectRetrievedCredentials)
+
+ const activeCreds = groupedProof.filter(item => credList.includes(item.credId))
+ setActiveCreds(activeCreds)
+ }
+ })
+ .catch((err: unknown) => {
+ const error = new BifoldError(
+ t('Error.Title1026'),
+ t('Error.Message1026'),
+ (err as Error)?.message ?? err,
+ 1026,
+ )
+ DeviceEventEmitter.emit(EventTypes.ERROR_ADDED, error)
+ })
+ }, [selectedCredentials])
+
+ const toggleDeclineModalVisible = () => {
+ setDeclineModalVisible(!declineModalVisible)
+ }
+
+ const getCredentialsFields = () => ({
+ ...retrievedCredentials?.attributes,
+ ...retrievedCredentials?.predicates,
+ })
+
+ useEffect(() => {
+ // get oca bundle to see if we're presenting personally identifiable elements
+ activeCreds.some(async item => {
+ if (!item || !(item.credDefId || item.schemaId)) {
+ return false
+ }
+ const labels = (item.attributes ?? []).map(field => field.label ?? field.name ?? '')
+ const bundle = await OCABundleResolver.resolveAllBundles({
+ identifiers: { credentialDefinitionId: item.credDefId, schemaId: item.schemaId },
+ })
+ const flaggedAttributes: string[] = (bundle as any).bundle.bundle.flaggedAttributes.map((attr: any) => attr.name)
+ const foundPI = labels.some(label => flaggedAttributes.includes(label))
+ setContainsPI(foundPI)
+ return foundPI
+ })
+ }, [activeCreds])
+
+ const hasAvailableCredentials = useMemo(() => {
+ const fields = getCredentialsFields()
+
+ return !!retrievedCredentials && Object.values(fields).every(c => c.length > 0)
+ }, [retrievedCredentials])
+
+ const handleAcceptPress = async () => {
+ try {
+ if (!(agent && proof && assertConnectedNetwork())) {
+ return
+ }
+ setPendingModalVisible(true)
+
+ if (!retrievedCredentials) {
+ throw new Error(t('ProofRequest.RequestedCredentialsCouldNotBeFound'))
+ }
+
+ const proofCreds = { ...retrievedCredentials?.attributes }
+
+ Object.keys(proofCreds).forEach(key => {
+ proofCreds[key] = [proofCreds[key][0].credentialRecord]
+ })
+
+ const proofFormats = {
+ presentationExchange: {
+ credentials: proofCreds,
+ },
+ }
+
+ if (!proofFormats) {
+ throw new Error(t('ProofRequest.RequestedCredentialsCouldNotBeFound'))
+ }
+
+ await acceptProofRequest(agent, {
+ proofRecordId: proof.id,
+ proofFormats,
+ })
+ if (proof.connectionId && goalCode && goalCode.endsWith('verify.once')) {
+ await deleteConnectionRecordById(agent, proof.connectionId)
+ }
+ } catch (err: unknown) {
+ setPendingModalVisible(false)
+
+ const error = new BifoldError(t('Error.Title1027'), t('Error.Message1027'), (err as Error).message, 1027)
+ DeviceEventEmitter.emit(EventTypes.ERROR_ADDED, error)
+ }
+ }
+
+ const handleDeclineTouched = async () => {
+ try {
+ if (proof) {
+ await declineProofRequest(agent, { proofRecordId: proof.id })
+
+ // sending a problem report fails if there is neither a connectionId nor a ~service decorator
+ if (proof.connectionId) {
+ await sendProofProblemReport(agent, { proofRecordId: proof.id, description: t('ProofRequest.Declined') })
+ if (goalCode && goalCode.endsWith('verify.once')) {
+ await deleteConnectionRecordById(agent, proof.connectionId)
+ }
+ }
+ }
+ } catch (err: unknown) {
+ const error = new BifoldError(t('Error.Title1028'), t('Error.Message1028'), (err as Error).message, 1028)
+
+ DeviceEventEmitter.emit(EventTypes.ERROR_ADDED, error)
+ }
+
+ toggleDeclineModalVisible()
+
+ navigation.getParent()?.navigate(TabStacks.HomeStack, { screen: Screens.Home })
+ }
+
+ const proofPageHeader = () => {
+ return (
+
+ {loading ? (
+
+
+
+ ) : (
+ <>
+
+
+
+ {proofConnectionLabel || t('ContactDetails.AContact')}{' '}
+ {t('ProofRequest.IsRequestingYouToShare')}
+ {` ${activeCreds?.length} `}
+ {activeCreds?.length > 1 ? t('ProofRequest.Credentials') : t('ProofRequest.Credential')}
+
+ {containsPI && (
+
+
+
+ {t('ProofRequest.SensitiveInformation')}
+
+
+ )}
+
+ {!hasAvailableCredentials && hasMatchingCredDef && (
+
+ {t('ProofRequest.FromYourWallet')}
+
+ )}
+ >
+ )}
+
+ )
+ }
+
+ const handleAltCredChange = (selectedCred: string, altCredentials: string[]) => {
+ const onCredChange = (cred: string) => {
+ const newSelectedCreds = (
+ selectedCredentials.length > 0 ? selectedCredentials : activeCreds.map(item => item.credId)
+ ).filter(id => !altCredentials.includes(id))
+ setSelectedCredentials([cred, ...newSelectedCreds])
+ }
+ navigation.getParent()?.navigate(Stacks.ProofRequestsStack, {
+ screen: Screens.ProofChangeCredentialW3C,
+ params: {
+ selectedCred,
+ altCredentials,
+ proofId,
+ onCredChange,
+ },
+ })
+ }
+
+ const proofPageFooter = () => {
+ return (
+
+ {!loading && proofConnectionLabel && goalCode !== 'aries.vc.verify.once' ? null : null}
+
+
+
+
+
+
+
+ )
+ }
+
+ const CredentialList = ({ header, footer, items }: CredentialListProps) => {
+ return (
+ {
+ return (
+
+ {loading ? null : (
+
+ 1}
+ handleAltCredChange={
+ item.altCredentials && item.altCredentials.length > 1
+ ? () => {
+ handleAltCredChange(item.credId, item.altCredentials ?? [item.credId])
+ }
+ : undefined
+ }
+ proof={true}>
+
+ )}
+
+ )
+ }}
+ />
+ )
+ }
+
+ return (
+
+
+
+ cred.credExchangeRecord === undefined)?.length > 0 ? [] : activeCreds}
+ />
+ {!hasAvailableCredentials && (
+
+ {!loading && (
+ <>
+ {hasMatchingCredDef && (
+
+ )}
+
+ {t('ProofRequest.MissingCredentials')}
+
+ >
+ )}
+
+ }
+ footer={proofPageFooter()}
+ items={activeCreds.filter(cred => cred.credExchangeRecord === undefined) ?? []}
+ />
+ )}
+
+
+
+
+
+ )
+}
+
+export default ProofRequestW3C
diff --git a/app/screens/RenderCertificate.tsx b/app/screens/RenderCertificate.tsx
new file mode 100644
index 00000000..603785ea
--- /dev/null
+++ b/app/screens/RenderCertificate.tsx
@@ -0,0 +1,62 @@
+import type { StackScreenProps } from '@react-navigation/stack'
+
+import React, { useEffect } from 'react'
+import { StyleSheet, TouchableOpacity } from 'react-native'
+import Pdf from 'react-native-pdf'
+import { SafeAreaView } from 'react-native-safe-area-context'
+import Share, { ShareOptions } from 'react-native-share'
+import Icon from 'react-native-vector-icons/MaterialIcons'
+
+import { ColorPallet } from '../theme'
+import { CredentialStackParams, Screens } from '../types/navigators'
+
+type RenderCertificateProps = StackScreenProps
+
+const RenderCertificate: React.FC = ({ navigation, route }) => {
+ if (!route?.params) {
+ throw new Error('RenderCertificate route prams were not set properly')
+ }
+
+ const { filePath } = route?.params
+
+ const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ justifyContent: 'flex-start',
+ alignItems: 'center',
+ marginTop: 25,
+ },
+ pdf: {
+ width: '100%',
+ height: '100%',
+ },
+ })
+
+ const downloadPdf = async () => {
+ try {
+ const shareOptions: ShareOptions = { url: filePath }
+ await Share.open(shareOptions)
+ } catch (e) {
+ // eslint-disable-next-line no-console
+ console.log('error downloading html to pdf', e)
+ }
+ }
+
+ useEffect(() => {
+ navigation.setOptions({
+ headerRight: () => (
+
+
+
+ ),
+ })
+ }, [navigation])
+
+ return (
+
+
+
+ )
+}
+
+export default RenderCertificate
diff --git a/app/screens/Scan.tsx b/app/screens/Scan.tsx
index 32c79387..e65dcdbb 100644
--- a/app/screens/Scan.tsx
+++ b/app/screens/Scan.tsx
@@ -58,11 +58,11 @@ const Scan: React.FC = ({ navigation, route }) => {
return
}
- const { connectionRecord } = await connectFromInvitation(agent, value)
+ const { connectionRecord, outOfBandRecord } = await connectFromInvitation(agent, value)
setLoading(false)
navigation.getParent()?.navigate(Stacks.ConnectionStack, {
screen: Screens.Connection,
- params: { connectionId: connectionRecord?.id },
+ params: { connectionId: connectionRecord?.id, outOfBandId: outOfBandRecord.id },
})
} catch (err: unknown) {
try {
@@ -95,12 +95,12 @@ const Scan: React.FC = ({ navigation, route }) => {
return
}
- const { connectionRecord } = await connectFromInvitation(agent, urlData)
+ const { connectionRecord, outOfBandRecord } = await connectFromInvitation(agent, urlData)
setLoading(false)
navigation.getParent()?.navigate(Stacks.ConnectionStack, {
screen: Screens.Connection,
- params: { connectionId: connectionRecord?.id },
+ params: { connectionId: connectionRecord?.id, outOfBandId: outOfBandRecord.id },
})
return
}
diff --git a/app/screens/Settings.tsx b/app/screens/Settings.tsx
index ff0a43c4..9abb9bd8 100644
--- a/app/screens/Settings.tsx
+++ b/app/screens/Settings.tsx
@@ -1,4 +1,5 @@
import AsyncStorage from '@react-native-async-storage/async-storage'
+import Clipboard from '@react-native-clipboard/clipboard'
import { StackScreenProps } from '@react-navigation/stack'
import React, { useEffect, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next'
@@ -14,8 +15,11 @@ import {
} from 'react-native'
import { getVersion, getBuildNumber } from 'react-native-device-info'
import { SafeAreaView } from 'react-native-safe-area-context'
+import Toast from 'react-native-toast-message'
import Icon from 'react-native-vector-icons/MaterialIcons'
+import { ToastType } from '../components/toast/BaseToast'
+import { useAuth } from '../contexts/auth'
import { useConfiguration } from '../contexts/configuration'
import { DispatchAction } from '../contexts/reducers/store'
import { useStore } from '../contexts/store'
@@ -26,6 +30,7 @@ import { Screens, SettingStackParams, Stacks } from '../types/navigators'
import { SettingSection } from '../types/settings'
import * as PushNotificationHelper from '../utils/PushNotificationHelper'
import { useAppAgent } from '../utils/agent'
+import { getDefaultHolderDidDocument } from '../utils/helpers'
import { testIdWithKey } from '../utils/testable'
type SettingsProps = StackScreenProps
@@ -41,6 +46,8 @@ const Settings: React.FC = ({ navigation }) => {
const { settings, enableTours } = useConfiguration()
const [enablePushNotifications, setEnablePushNotifications] = useState(false)
const [pushNotificationCapable, setPushNotificationCapable] = useState(true)
+ const [holderDid, setHolderDid] = useState('')
+ const { isGoogleAccountSignedIn, googleSignOut } = useAuth()
const languages = [{ id: Locales.en, value: t('Language.English') }]
@@ -104,6 +111,9 @@ const Settings: React.FC = ({ navigation }) => {
if (agent) {
getPushNotificationCapable()
initializePushNotificationsToggle()
+ getDefaultHolderDidDocument(agent).then(didDoc => {
+ setHolderDid(didDoc?.id)
+ })
}
}, [agent])
@@ -123,6 +133,15 @@ const Settings: React.FC = ({ navigation }) => {
developerOptionCount.current = developerOptionCount.current + 1
}
+ const copyToClipboard = () => {
+ Clipboard.setString(holderDid)
+ Toast.hide()
+ Toast.show({
+ type: ToastType.Success,
+ text1: 'DID copied',
+ })
+ }
+
const settingsSections: SettingSection[] = [
{
header: {
@@ -139,6 +158,21 @@ const Settings: React.FC = ({ navigation }) => {
},
],
},
+ {
+ header: {
+ icon: 'settings',
+ title: t('DIDs.Dids'),
+ },
+ data: [
+ {
+ title: holderDid,
+ accessibilityLabel: t('DIDs.Dids'),
+ testID: testIdWithKey('DID'),
+ onPress: copyToClipboard,
+ value: 'Copy',
+ },
+ ],
+ },
{
header: {
icon: 'apartment',
@@ -176,7 +210,30 @@ const Settings: React.FC = ({ navigation }) => {
onPress: () => navigation.navigate(Screens.ExportWallet as never),
value: undefined,
},
- ],
+ {
+ title: t('Backup.backup_google_drive'),
+ accessibilityLabel: t('Settings.GoogleDriveBackup'),
+ testID: testIdWithKey('BackupGoogleDrive'),
+ onPress: async () => {
+ if (isGoogleAccountSignedIn) {
+ navigation.navigate(Screens.ExportWallet, { backupType: 'google_drive' })
+ } else {
+ navigation.navigate(Screens.GoogleDriveSignIn as never)
+ }
+ },
+ value: undefined,
+ },
+ isGoogleAccountSignedIn && {
+ title: t('GoogleDrive.SignOutGoogle'),
+ accessibilityLabel: t('GoogleDrive.SignOutGoogle'),
+ testID: testIdWithKey('SignOutGoogleAccount'),
+ onPress: async () => {
+ await googleSignOut()
+ navigation.navigate(Screens.Settings)
+ },
+ value: undefined,
+ },
+ ].filter(Boolean),
},
{
@@ -369,7 +426,12 @@ const Settings: React.FC = ({ navigation }) => {
testID={testID}
style={styles.sectionRow}
onPress={onPress}>
- {title}
+
+ {title}
+
{value}
diff --git a/app/screens/Splash.tsx b/app/screens/Splash.tsx
index 36b33031..da72c5f2 100644
--- a/app/screens/Splash.tsx
+++ b/app/screens/Splash.tsx
@@ -8,6 +8,8 @@ import {
IndyVdrIndyDidResolver,
CacheModule,
SingleContextStorageLruCache,
+ MediatorPickupStrategy,
+ WebDidResolver,
} from '@adeya/ssi'
import { PolygonDidResolver, PolygonModule } from '@ayanworks/credo-polygon-w3c-module'
import AsyncStorage from '@react-native-async-storage/async-storage'
@@ -55,7 +57,7 @@ const resumeOnboardingAt = (state: StoreOnboardingState, enableWalletNaming: boo
(state.didNameWallet || !enableWalletNaming) &&
!state.didConsiderBiometry
) {
- return Screens.UseBiometry
+ return Screens.WalletOptions
}
if (
@@ -290,10 +292,14 @@ const Splash: React.FC = () => {
const newAgent = (await initializeAgent({
agentConfig,
modules: {
- ...getAgentModules(Config.MEDIATOR_URL, indyLedgers),
+ ...getAgentModules({
+ indyNetworks: indyLedgers,
+ mediatorInvitationUrl: Config.MEDIATOR_URL,
+ mediatorPickupStrategy: MediatorPickupStrategy.PickUpV2LiveMode,
+ }),
polygon: new PolygonModule({}),
dids: new DidsModule({
- resolvers: [new PolygonDidResolver(), new IndyVdrIndyDidResolver()],
+ resolvers: [new PolygonDidResolver(), new IndyVdrIndyDidResolver(), new WebDidResolver()],
}),
cache: new CacheModule({
cache: new SingleContextStorageLruCache({
diff --git a/app/types/navigators.ts b/app/types/navigators.ts
index 5d0844b7..d8cb78f2 100644
--- a/app/types/navigators.ts
+++ b/app/types/navigators.ts
@@ -15,6 +15,7 @@ export enum Screens {
Notifications = 'Notifications',
CredentialOffer = 'Credential Offer',
ProofRequest = 'Proof Request',
+ ProofRequestW3C = 'Proof Request W3C',
ProofRequestDetails = 'Proof Request Details',
ProofRequestUsageHistory = 'Proof Request Usage History',
Settings = 'Settings',
@@ -46,9 +47,12 @@ export enum Screens {
ImportSuccess = 'Import Success',
CredentialDetailsW3C = 'Credential Details W3C',
ProofChangeCredential = 'Choose a credential',
+ ProofChangeCredentialW3C = 'Choose a W3C credential',
DataRetention = 'Data Retention',
Explore = 'Explore',
OrganizationDetails = 'Organization Details',
+ RenderCertificate = 'Render Certificate',
+ GoogleDriveSignIn = 'Google Drive Sign In',
}
export enum Stacks {
@@ -114,7 +118,9 @@ export type ContactStackParams = {
[Screens.CredentialOffer]: { credentialId: string }
[Screens.ProofDetails]: { recordId: string; isHistory?: boolean }
[Screens.ProofRequest]: { proofId: string }
+ [Screens.ProofRequestW3C]: { proofId: string }
[Screens.Home]: undefined
+ [Screens.RenderCertificate]: { filePath: string }
}
export type ProofRequestsStackParams = {
@@ -129,12 +135,19 @@ export type ProofRequestsStackParams = {
proofId: string
onCredChange: (arg: string) => void
}
+ [Screens.ProofChangeCredentialW3C]: {
+ selectedCred: string
+ altCredentials: string[]
+ proofId: string
+ onCredChange: (arg: string) => void
+ }
}
export type CredentialStackParams = {
[Screens.Credentials]: undefined
[Screens.CredentialDetails]: { credential: CredentialExchangeRecord }
[Screens.CredentialDetailsW3C]: { credential: W3cCredentialRecord }
+ [Screens.RenderCertificate]: { filePath: string }
[Screens.Scan]: undefined
}
export type OrganizationStackParams = {
@@ -180,12 +193,13 @@ export type NotificationStackParams = {
[Screens.CredentialDetails]: { credentialId: string }
[Screens.CredentialOffer]: { credentialId: string }
[Screens.ProofRequest]: { proofId: string }
+ [Screens.ProofRequestW3C]: { proofId: string }
[Screens.CustomNotification]: undefined
[Screens.ProofDetails]: { recordId: string }
}
export type DeliveryStackParams = {
- [Screens.Connection]: { connectionId?: string; threadId?: string }
+ [Screens.Connection]: { connectionId?: string; threadId?: string; outOfBandId?: string }
[Screens.CredentialOffer]: { credentialId: string }
[Screens.ProofRequest]: { proofId: string }
[Screens.OnTheWay]: { credentialId: string }
diff --git a/app/types/proof-items.ts b/app/types/proof-items.ts
index 5b181645..f134a2b9 100644
--- a/app/types/proof-items.ts
+++ b/app/types/proof-items.ts
@@ -9,6 +9,7 @@ export interface ProofCredentialAttributes {
schemaId?: string
credName: string
attributes?: Attribute[]
+ inputDescriptorIds?: string[]
}
export interface ProofCredentialPredicates {
@@ -22,3 +23,20 @@ export interface ProofCredentialPredicates {
}
export interface ProofCredentialItems extends ProofCredentialAttributes, ProofCredentialPredicates {}
+
+export type W3cIssuerJson = {
+ id: string
+}
+
+export type W3cCredentialSubjectJson = {
+ id?: string
+ [key: string]: unknown
+}
+
+export type W3cCredentialJson = {
+ type: Array
+ issuer: W3cIssuerJson
+ issuanceDate: string
+ expiryDate?: string
+ credentialSubject: W3cCredentialSubjectJson | W3cCredentialSubjectJson[]
+}
diff --git a/app/types/record.ts b/app/types/record.ts
index 7d27635b..905ccb46 100644
--- a/app/types/record.ts
+++ b/app/types/record.ts
@@ -75,7 +75,7 @@ export class Predicate extends Field {
export type W3CCredentialAttribute = {
key: string
- value: string
+ value: string | number | boolean
}
export type W3CCredentialAttributeField = {
diff --git a/app/utils/cred-def.ts b/app/utils/cred-def.ts
index f7c2671a..4cace5ba 100644
--- a/app/utils/cred-def.ts
+++ b/app/utils/cred-def.ts
@@ -1,9 +1,11 @@
import { AnonCredsCredentialMetadataKey, CredentialExchangeRecord as CredentialRecord } from '@adeya/ssi'
+import { CREDENTIAL } from '../constants'
+
import { parseSchemaFromId, credentialSchema } from './schema'
export function parseCredDefFromId(credDefId?: string, schemaId?: string): string {
- let name = 'Credential'
+ let name = CREDENTIAL
if (credDefId) {
const credDefRegex = /[^:]+/g
const credDefIdParts = credDefId.match(credDefRegex)
diff --git a/app/utils/credential.ts b/app/utils/credential.ts
index fedb1bf8..70fca404 100644
--- a/app/utils/credential.ts
+++ b/app/utils/credential.ts
@@ -72,9 +72,9 @@ export const formatCredentialSubject = (
const value = subject[key]
- if (!value) return // omit properties with no value
+ // if (!value) return // omit properties with no value
- if (typeof value === 'string') {
+ if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
stringRows.push({
key: sanitizeString(key),
value: value,
diff --git a/app/utils/helpers.ts b/app/utils/helpers.ts
index 5c4c18d8..0bb7f54a 100644
--- a/app/utils/helpers.ts
+++ b/app/utils/helpers.ts
@@ -21,13 +21,19 @@ import {
acceptInvitationFromUrl,
createInvitation,
AnonCredsRequestedPredicate,
- getProofFormatData,
getCredentialsForProofRequest,
AnonCredsPredicateType,
AnonCredsRequestedAttribute,
parseInvitationFromUrl,
findByReceivedInvitationId,
+ DidRecord,
+ DidRepository,
+ KeyType,
+ DifPresentationExchangeProofFormatService,
+ W3cCredentialRecord,
} from '@adeya/ssi'
+// eslint-disable-next-line import/no-extraneous-dependencies
+import { DifPresentationExchangeProofFormat, DifPresentationExchangeDefinitionV1 } from '@credo-ts/core'
import { CaptureBaseAttributeType } from '@hyperledger/aries-oca'
import { TFunction } from 'i18next'
import moment from 'moment'
@@ -297,7 +303,11 @@ export function getConnectionName(connection: ConnectionRecord | void): string |
return connection?.alias || connection?.theirLabel
}
-export function getCredentialConnectionLabel(credential?: CredentialExchangeRecord, connectionLabel?: string) {
+export function getCredentialConnectionLabel(
+ connections: ConnectionRecord[],
+ credential?: CredentialExchangeRecord,
+ connectionLabel?: string,
+) {
if (!credential) {
if (connectionLabel) {
return connectionLabel
@@ -306,7 +316,7 @@ export function getCredentialConnectionLabel(credential?: CredentialExchangeReco
}
if (credential.connectionId) {
- const connection = useConnectionById(credential.connectionId)
+ const connection = connections.find(connection => connection.id === credential.connectionId)
return connection?.alias || connection?.theirLabel || credential.connectionId
}
@@ -492,6 +502,133 @@ const addMissingDisplayAttributes = (attrReq: AnonCredsRequestedAttribute) => {
return processedAttributes
}
+export const extractKeyFromPath = (path: string) => {
+ // Remove the initial '$.' if present
+ let cleanPath = path.replace(/^\$\./, '')
+
+ // Replace ['key'] with .key
+ cleanPath = cleanPath.replace(/\['/g, '.').replace(/'\]/g, '')
+
+ // Split the cleaned path by dot to get the parts
+ const parts = cleanPath.split('.')
+
+ // Return the last part which is the key
+ return parts[parts.length - 1]
+}
+
+const addW3CMissingDisplayAttributes = (attrReq: DifPresentationExchangeDefinitionV1['input_descriptors'][number]) => {
+ const credName = attrReq.id
+
+ //there is no credId in this context so use credName as a placeholder
+ const processedAttributes: ProofCredentialAttributes = {
+ credExchangeRecord: undefined,
+ altCredentials: [credName],
+ credId: credName,
+ schemaId: undefined,
+ credDefId: undefined,
+ credName: credName,
+ attributes: [] as Attribute[],
+ }
+ const { constraints } = attrReq
+
+ const paths = constraints?.fields[0].path ?? []
+
+ // Added a 0th path for now
+ for (const attributeName of paths) {
+ const attrName = extractKeyFromPath(attributeName)
+
+ processedAttributes.attributes?.push(
+ new Attribute({
+ revoked: false,
+ credentialId: credName,
+ name: attrName,
+ value: '',
+ }),
+ )
+ }
+ return processedAttributes
+}
+
+export const processW3CProofAttributes = (
+ request?: ProofFormatDataMessagePayload<[DifPresentationExchangeProofFormat], 'request'> | undefined,
+ credentials?: GetCredentialsForRequestReturn<[DifPresentationExchangeProofFormatService]>,
+): { [key: string]: ProofCredentialAttributes } => {
+ const processedAttributes = {} as { [key: string]: ProofCredentialAttributes }
+
+ const requestedProofAttributes = request?.presentationExchange?.presentation_definition
+ const retrievedCredentialAttributes = credentials?.proofFormats?.presentationExchange?.requirements
+
+ if (!requestedProofAttributes || !retrievedCredentialAttributes) {
+ return {}
+ }
+ for (const retrievedCredentialAttribute of retrievedCredentialAttributes) {
+ const currentInputDescriptorId = retrievedCredentialAttribute.submissionEntry[0].inputDescriptorId
+
+ const altCredentials = [...(retrievedCredentialAttribute.submissionEntry[0].verifiableCredentials ?? [])].map(
+ cred => cred.credentialRecord.id,
+ )
+
+ const credentialList = [...(retrievedCredentialAttribute.submissionEntry[0].verifiableCredentials ?? [])]
+
+ const inputDescriptor = requestedProofAttributes.input_descriptors.find(i => i.id === currentInputDescriptorId)
+
+ if (credentialList.length <= 0) {
+ const missingAttributes = addW3CMissingDisplayAttributes(inputDescriptor)
+ if (!processedAttributes[missingAttributes.credName]) {
+ processedAttributes[missingAttributes.credName] = missingAttributes
+ } else {
+ processedAttributes[missingAttributes.credName].attributes?.push(...(missingAttributes.attributes ?? []))
+ }
+ }
+
+ // iterate over all credentials that satisfy the proof
+ for (const credential of credentialList) {
+ const w3cCredentialRecord = credential.credentialRecord as W3cCredentialRecord
+ const credName = w3cCredentialRecord.credential.type[1]
+ const paths = inputDescriptor.constraints?.fields[0].path ?? []
+
+ const attributeNames = paths.map(path => extractKeyFromPath(path))
+ for (const attributeName of attributeNames) {
+ if (!processedAttributes[w3cCredentialRecord.id]) {
+ // init processedAttributes object
+ processedAttributes[w3cCredentialRecord.id] = {
+ credExchangeRecord: w3cCredentialRecord,
+ altCredentials,
+ credId: w3cCredentialRecord.id,
+ schemaId: undefined,
+ credDefId: undefined,
+ credName,
+ attributes: [],
+ inputDescriptorIds: [],
+ }
+ }
+
+ const isInputDescriptorIdPresent = processedAttributes[w3cCredentialRecord.id].inputDescriptorIds?.find(
+ id => id === currentInputDescriptorId,
+ )
+
+ if (!isInputDescriptorIdPresent) {
+ processedAttributes[w3cCredentialRecord.id].inputDescriptorIds?.push(currentInputDescriptorId)
+ }
+
+ let attributeValue = ''
+ if (w3cCredentialRecord) {
+ attributeValue = w3cCredentialRecord.credential.credentialSubject.claims[attributeName]
+ }
+ processedAttributes[w3cCredentialRecord.id].attributes?.push(
+ new Attribute({
+ credentialId: w3cCredentialRecord.id,
+ name: attributeName,
+ value: attributeValue,
+ }),
+ )
+ }
+ }
+ }
+
+ return processedAttributes
+}
+
export const processProofAttributes = (
request?: ProofFormatDataMessagePayload<[LegacyIndyProofFormat, AnonCredsProofFormat], 'request'> | undefined,
credentials?: GetCredentialsForRequestReturn<[LegacyIndyProofFormatService, AnonCredsProofFormatService]>,
@@ -577,6 +714,7 @@ export const processProofAttributes = (
}
}
}
+
return processedAttributes
}
@@ -717,7 +855,8 @@ export const retrieveCredentialsForProof = async (
t: TFunction<'translation', undefined>,
) => {
try {
- const format = await getProofFormatData(agent, proof.id)
+ const format = await agent.proofs.getFormatData(proof.id)
+ const hasPresentationExchange = format.request?.presentationExchange !== undefined
const hasAnonCreds = format.request?.anoncreds !== undefined
const hasIndy = format.request?.indy !== undefined
const credentials = await getCredentialsForProofRequest(agent, {
@@ -748,6 +887,7 @@ export const retrieveCredentialsForProof = async (
},
}
: {}),
+ ...(hasPresentationExchange ? { presentationExchange: {} } : {}),
},
})
if (!credentials) {
@@ -762,6 +902,20 @@ export const retrieveCredentialsForProof = async (
return
}
+ if (hasPresentationExchange) {
+ const presentationExchange = format.request?.presentationExchange
+ const difPexCredentialsForRequest = credentials.proofFormats.presentationExchange
+
+ if (!difPexCredentialsForRequest || !presentationExchange) throw new Error('Invalid presentation request')
+
+ const attributes = processW3CProofAttributes(format.request, credentials)
+
+ const proofFormat = credentials.proofFormats.presentationExchange
+
+ const groupedProof = Object.values(attributes)
+ return { groupedProof: groupedProof, retrievedCredentials: proofFormat, fullCredentials }
+ }
+
const proofFormat = credentials.proofFormats.anoncreds ?? credentials.proofFormats.indy
const attributes = processProofAttributes(format.request, credentials, fullCredentials)
@@ -893,7 +1047,9 @@ export const checkIfAlreadyConnected = async (agent: AdeyaAgent, invitationUrl:
* @returns a connection record from parsing and receiving the invitation
*/
export const connectFromInvitation = async (agent: AdeyaAgent, uri: string) => {
- return await acceptInvitationFromUrl(agent, uri)
+ return await acceptInvitationFromUrl(agent, uri, {
+ reuseConnection: true,
+ })
}
/**
@@ -1071,3 +1227,40 @@ export function generateRandomWalletName() {
)
return name
}
+
+export const getDefaultHolderDidDocument = async (agent: AdeyaAgent) => {
+ try {
+ let defaultDidRecord: DidRecord | null
+ const didRepository = await agent.dependencyManager.resolve(DidRepository)
+
+ defaultDidRecord = await didRepository.findSingleByQuery(agent.context, {
+ isDefault: true,
+ })
+
+ if (!defaultDidRecord) {
+ const did = await agent.dids.create({
+ method: 'key',
+ options: {
+ keyType: KeyType.Ed25519,
+ },
+ })
+
+ const [didRecord] = await agent.dids.getCreatedDids({
+ did: did.didState.did,
+ method: 'key',
+ })
+
+ didRecord.setTag('isDefault', true)
+
+ await didRepository.update(agent.context, didRecord)
+ defaultDidRecord = didRecord
+ }
+
+ const resolvedDidDocument = await agent.dids.resolveDidDocument(defaultDidRecord.did)
+
+ return resolvedDidDocument
+ } catch (error) {
+ // eslint-disable-next-line no-console
+ console.log('Error did create', error)
+ }
+}
diff --git a/app/utils/schema.ts b/app/utils/schema.ts
index 98586605..3a6a1591 100644
--- a/app/utils/schema.ts
+++ b/app/utils/schema.ts
@@ -1,7 +1,9 @@
import { AnonCredsCredentialMetadataKey, CredentialExchangeRecord as CredentialRecord } from '@adeya/ssi'
+import { CREDENTIAL } from '../constants'
+
export function parseSchemaFromId(schemaId?: string): { name: string; version: string } {
- let name = 'Credential'
+ let name = CREDENTIAL
let version = ''
if (schemaId) {
const schemaIdRegex = /(.*?):([0-9]):([a-zA-Z .\-_0-9]+):([a-z0-9._-]+)$/
diff --git a/ios/AdeyaWallet.xcodeproj/project.pbxproj b/ios/AdeyaWallet.xcodeproj/project.pbxproj
index d8a3296e..404eaa8d 100644
--- a/ios/AdeyaWallet.xcodeproj/project.pbxproj
+++ b/ios/AdeyaWallet.xcodeproj/project.pbxproj
@@ -507,7 +507,7 @@
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = AdeyaWallet/AdeyaWallet.entitlements;
- CURRENT_PROJECT_VERSION = 29;
+ CURRENT_PROJECT_VERSION = 47;
DEVELOPMENT_ASSET_PATHS = "";
DEVELOPMENT_TEAM = Z5W7KRPGHZ;
ENABLE_BITCODE = NO;
@@ -517,7 +517,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
- MARKETING_VERSION = 1.0.9;
+ MARKETING_VERSION = 1.0.10;
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
@@ -545,7 +545,7 @@
CODE_SIGN_ENTITLEMENTS = AdeyaWallet/AdeyaWallet.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 29;
+ CURRENT_PROJECT_VERSION = 47;
DEVELOPMENT_ASSET_PATHS = "";
DEVELOPMENT_TEAM = Z5W7KRPGHZ;
INFOPLIST_FILE = AdeyaWallet/Info.plist;
@@ -554,7 +554,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
- MARKETING_VERSION = 1.0.9;
+ MARKETING_VERSION = 1.0.10;
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
diff --git a/ios/AdeyaWallet/AdeyaWallet.entitlements b/ios/AdeyaWallet/AdeyaWallet.entitlements
index 0ca3bf6b..4bae17a9 100644
--- a/ios/AdeyaWallet/AdeyaWallet.entitlements
+++ b/ios/AdeyaWallet/AdeyaWallet.entitlements
@@ -6,8 +6,7 @@
development
com.apple.developer.associated-domains
- applinks:agent.credebl.id
- applinks:dev-agent.credebl.id
+ applinks:link.credebl.id
diff --git a/ios/AdeyaWallet/Info.plist b/ios/AdeyaWallet/Info.plist
index fd6bab5d..aafdb10c 100644
--- a/ios/AdeyaWallet/Info.plist
+++ b/ios/AdeyaWallet/Info.plist
@@ -39,9 +39,15 @@
id.credebl.adeya
CFBundleURLSchemes
- agent.credebl.id
- dev-agent.credebl.id
- s3.ap-south-1.amazonaws.com
+ link.credebl.id
+
+
+
+ CFBundleTypeRole
+ Editor
+ CFBundleURLSchemes
+
+ com.googleusercontent.apps.386865711438-33clai2qtm879j181u4nnhg3koh2ha6a
diff --git a/ios/Podfile.lock b/ios/Podfile.lock
index 9ea8326a..6c52928c 100644
--- a/ios/Podfile.lock
+++ b/ios/Podfile.lock
@@ -3,6 +3,12 @@ PODS:
- React
- React-callinvoker
- React-Core
+ - AppAuth (1.7.5):
+ - AppAuth/Core (= 1.7.5)
+ - AppAuth/ExternalUserAgent (= 1.7.5)
+ - AppAuth/Core (1.7.5)
+ - AppAuth/ExternalUserAgent (1.7.5):
+ - AppAuth/Core
- aries-askar (0.2.1):
- React
- React-callinvoker
@@ -95,6 +101,10 @@ PODS:
- GoogleUtilities/Environment (~> 7.7)
- nanopb (< 2.30911.0, >= 2.30908.0)
- PromisesObjC (< 3.0, >= 1.2)
+ - GoogleSignIn (7.1.0):
+ - AppAuth (< 2.0, >= 1.7.3)
+ - GTMAppAuth (< 5.0, >= 4.1.1)
+ - GTMSessionFetcher/Core (~> 3.3)
- GoogleUtilities (7.13.0):
- GoogleUtilities/AppDelegateSwizzler (= 7.13.0)
- GoogleUtilities/Environment (= 7.13.0)
@@ -139,6 +149,10 @@ PODS:
- GoogleUtilities/UserDefaults (7.13.0):
- GoogleUtilities/Logger
- GoogleUtilities/Privacy
+ - GTMAppAuth (4.1.1):
+ - AppAuth/Core (~> 1.7)
+ - GTMSessionFetcher/Core (< 4.0, >= 3.3)
+ - GTMSessionFetcher/Core (3.4.1)
- hermes-engine (0.72.3):
- hermes-engine/Pre-built (= 0.72.3)
- hermes-engine/Pre-built (0.72.3)
@@ -453,6 +467,8 @@ PODS:
- React-jsinspector (0.72.3)
- React-logger (0.72.3):
- glog
+ - react-native-blob-util (0.19.9):
+ - React-Core
- react-native-camera (4.2.1):
- React-Core
- react-native-camera/RCT (= 4.2.1)
@@ -469,8 +485,12 @@ PODS:
- React-Core
- react-native-get-random-values (1.9.0):
- React-Core
+ - react-native-html-to-pdf (0.12.0):
+ - React-Core
- react-native-netinfo (9.4.1):
- React-Core
+ - react-native-pdf (6.7.5):
+ - React-Core
- react-native-randombytes (3.6.1):
- React-Core
- react-native-safe-area-context (4.7.1):
@@ -592,13 +612,13 @@ PODS:
- React-jsi (= 0.72.3)
- React-logger (= 0.72.3)
- React-perflogger (= 0.72.3)
- - rn-fetch-blob (0.12.0):
- - React-Core
- RNArgon2 (2.0.1):
- CatCrypto
- React-Core
- RNCAsyncStorage (1.19.1):
- React-Core
+ - RNCClipboard (1.14.1):
+ - React-Core
- RNCMaskedView (0.1.11):
- React
- RNDeviceInfo (10.8.0):
@@ -615,6 +635,9 @@ PODS:
- React-Core
- RNGestureHandler (2.13.1):
- React-Core
+ - RNGoogleSignin (12.1.0):
+ - GoogleSignIn (~> 7.1)
+ - React-Core
- RNKeychain (8.1.2):
- React-Core
- RNLocalize (3.0.2):
@@ -661,7 +684,15 @@ PODS:
- React-Core
- RNVectorIcons (10.0.0):
- React-Core
+ - RNZipArchive (6.1.2):
+ - React-Core
+ - RNZipArchive/Core (= 6.1.2)
+ - SSZipArchive (~> 2.2)
+ - RNZipArchive/Core (6.1.2):
+ - React-Core
+ - SSZipArchive (~> 2.2)
- SocketRocket (0.6.1)
+ - SSZipArchive (2.4.3)
- Yoga (1.14.0)
DEPENDENCIES:
@@ -695,11 +726,14 @@ DEPENDENCIES:
- React-jsiexecutor (from `../node_modules/react-native/ReactCommon/jsiexecutor`)
- React-jsinspector (from `../node_modules/react-native/ReactCommon/jsinspector`)
- React-logger (from `../node_modules/react-native/ReactCommon/logger`)
+ - react-native-blob-util (from `../node_modules/react-native-blob-util`)
- react-native-camera (from `../node_modules/react-native-camera`)
- react-native-config (from `../node_modules/react-native-config`)
- react-native-document-picker (from `../node_modules/react-native-document-picker`)
- react-native-get-random-values (from `../node_modules/react-native-get-random-values`)
+ - react-native-html-to-pdf (from `../node_modules/react-native-html-to-pdf`)
- "react-native-netinfo (from `../node_modules/@react-native-community/netinfo`)"
+ - react-native-pdf (from `../node_modules/react-native-pdf`)
- react-native-randombytes (from `../node_modules/react-native-randombytes`)
- react-native-safe-area-context (from `../node_modules/react-native-safe-area-context`)
- react-native-splash-screen (from `../node_modules/react-native-splash-screen`)
@@ -722,15 +756,16 @@ DEPENDENCIES:
- React-runtimescheduler (from `../node_modules/react-native/ReactCommon/react/renderer/runtimescheduler`)
- React-utils (from `../node_modules/react-native/ReactCommon/react/utils`)
- ReactCommon/turbomodule/core (from `../node_modules/react-native/ReactCommon`)
- - rn-fetch-blob (from `../node_modules/rn-fetch-blob`)
- RNArgon2 (from `../node_modules/react-native-argon2`)
- "RNCAsyncStorage (from `../node_modules/@react-native-async-storage/async-storage`)"
+ - "RNCClipboard (from `../node_modules/@react-native-clipboard/clipboard`)"
- "RNCMaskedView (from `../node_modules/@react-native-community/masked-view`)"
- RNDeviceInfo (from `../node_modules/react-native-device-info`)
- "RNFBApp (from `../node_modules/@react-native-firebase/app`)"
- "RNFBMessaging (from `../node_modules/@react-native-firebase/messaging`)"
- RNFS (from `../node_modules/react-native-fs`)
- RNGestureHandler (from `../node_modules/react-native-gesture-handler`)
+ - "RNGoogleSignin (from `../node_modules/@react-native-google-signin/google-signin`)"
- RNKeychain (from `../node_modules/react-native-keychain`)
- RNLocalize (from `../node_modules/react-native-localize`)
- RNPermissions (from `../node_modules/react-native-permissions`)
@@ -740,10 +775,12 @@ DEPENDENCIES:
- RNShare (from `../node_modules/react-native-share`)
- RNSVG (from `../node_modules/react-native-svg`)
- RNVectorIcons (from `../node_modules/react-native-vector-icons`)
+ - RNZipArchive (from `../node_modules/react-native-zip-archive`)
- Yoga (from `../node_modules/react-native/ReactCommon/yoga`)
SPEC REPOS:
trunk:
+ - AppAuth
- CatCrypto
- CocoaAsyncSocket
- Firebase
@@ -756,11 +793,15 @@ SPEC REPOS:
- fmt
- GoogleAppMeasurement
- GoogleDataTransport
+ - GoogleSignIn
- GoogleUtilities
+ - GTMAppAuth
+ - GTMSessionFetcher
- libevent
- nanopb
- PromisesObjC
- SocketRocket
+ - SSZipArchive
EXTERNAL SOURCES:
anoncreds:
@@ -812,6 +853,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native/ReactCommon/jsinspector"
React-logger:
:path: "../node_modules/react-native/ReactCommon/logger"
+ react-native-blob-util:
+ :path: "../node_modules/react-native-blob-util"
react-native-camera:
:path: "../node_modules/react-native-camera"
react-native-config:
@@ -820,8 +863,12 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native-document-picker"
react-native-get-random-values:
:path: "../node_modules/react-native-get-random-values"
+ react-native-html-to-pdf:
+ :path: "../node_modules/react-native-html-to-pdf"
react-native-netinfo:
:path: "../node_modules/@react-native-community/netinfo"
+ react-native-pdf:
+ :path: "../node_modules/react-native-pdf"
react-native-randombytes:
:path: "../node_modules/react-native-randombytes"
react-native-safe-area-context:
@@ -866,12 +913,12 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native/ReactCommon/react/utils"
ReactCommon:
:path: "../node_modules/react-native/ReactCommon"
- rn-fetch-blob:
- :path: "../node_modules/rn-fetch-blob"
RNArgon2:
:path: "../node_modules/react-native-argon2"
RNCAsyncStorage:
:path: "../node_modules/@react-native-async-storage/async-storage"
+ RNCClipboard:
+ :path: "../node_modules/@react-native-clipboard/clipboard"
RNCMaskedView:
:path: "../node_modules/@react-native-community/masked-view"
RNDeviceInfo:
@@ -884,6 +931,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native-fs"
RNGestureHandler:
:path: "../node_modules/react-native-gesture-handler"
+ RNGoogleSignin:
+ :path: "../node_modules/@react-native-google-signin/google-signin"
RNKeychain:
:path: "../node_modules/react-native-keychain"
RNLocalize:
@@ -902,11 +951,14 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native-svg"
RNVectorIcons:
:path: "../node_modules/react-native-vector-icons"
+ RNZipArchive:
+ :path: "../node_modules/react-native-zip-archive"
Yoga:
:path: "../node_modules/react-native/ReactCommon/yoga"
SPEC CHECKSUMS:
anoncreds: c709906b5a3caaf6bbe871646e6c16b522c6531d
+ AppAuth: 501c04eda8a8d11f179dbe8637b7a91bb7e5d2fa
aries-askar: cb89b1fdc61cd8adf0408a0dd28f7eb6dbf0dec9
boost: 57d2868c099736d80fcd648bf211b4431e51a558
CatCrypto: a477899b6be4954e75be4897e732da098cc0a5a8
@@ -925,7 +977,10 @@ SPEC CHECKSUMS:
glog: 04b94705f318337d7ead9e6d17c019bd9b1f6b1b
GoogleAppMeasurement: 7fee012a868315d418f365fbc8d394d8e020e749
GoogleDataTransport: 6c09b596d841063d76d4288cc2d2f42cc36e1e2a
+ GoogleSignIn: d4281ab6cf21542b1cfaff85c191f230b399d2db
GoogleUtilities: d053d902a8edaa9904e1bd00c37535385b8ed152
+ GTMAppAuth: f69bd07d68cd3b766125f7e072c45d7340dea0de
+ GTMSessionFetcher: 8000756fc1c19d2e5697b90311f7832d2e33f6cd
hermes-engine: 10fbd3f62405c41ea07e71973ea61e1878d07322
indy-vdr: 790ab1fd9b12ad5adfce4905c327f5902253eeeb
libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913
@@ -946,11 +1001,14 @@ SPEC CHECKSUMS:
React-jsiexecutor: 59d1eb03af7d30b7d66589c410f13151271e8006
React-jsinspector: b511447170f561157547bc0bef3f169663860be7
React-logger: c5b527272d5f22eaa09bb3c3a690fee8f237ae95
+ react-native-blob-util: 18b510205c080a453574a7d2344d64673d0ad9af
react-native-camera: 3eae183c1d111103963f3dd913b65d01aef8110f
react-native-config: 86038147314e2e6d10ea9972022aa171e6b1d4d8
react-native-document-picker: 2b8f18667caee73a96708a82b284a4f40b30a156
react-native-get-random-values: dee677497c6a740b71e5612e8dbd83e7539ed5bb
+ react-native-html-to-pdf: 4c5c6e26819fe202971061594058877aa9b25265
react-native-netinfo: fefd4e98d75cbdd6e85fc530f7111a8afdf2b0c5
+ react-native-pdf: 103940c90d62adfd259f63cca99c7c0c306b514c
react-native-randombytes: 421f1c7d48c0af8dbcd471b0324393ebf8fe7846
react-native-safe-area-context: 9697629f7b2cda43cf52169bb7e0767d330648c2
react-native-splash-screen: 4312f786b13a81b5169ef346d76d33bc0c6dc457
@@ -973,15 +1031,16 @@ SPEC CHECKSUMS:
React-runtimescheduler: 837c1bebd2f84572db17698cd702ceaf585b0d9a
React-utils: bcb57da67eec2711f8b353f6e3d33bd8e4b2efa3
ReactCommon: 3ccb8fb14e6b3277e38c73b0ff5e4a1b8db017a9
- rn-fetch-blob: f065bb7ab7fb48dd002629f8bdcb0336602d3cba
RNArgon2: 1481820722fd4af1575c09f7fc9ad67c00ee8a42
RNCAsyncStorage: f47fe18526970a69c34b548883e1aeceb115e3e1
+ RNCClipboard: 0a720adef5ec193aa0e3de24c3977222c7e52a37
RNCMaskedView: 0e1bc4bfa8365eba5fbbb71e07fbdc0555249489
RNDeviceInfo: 5795b418ed3451ebcaf39384e6cf51f60cb931c9
RNFBApp: a0bc818210d2c452461842f7a0a4e456c11ed831
RNFBMessaging: 57ff90f2a60184838da1da7904dfee6b1ce99a20
RNFS: 4ac0f0ea233904cb798630b3c077808c06931688
RNGestureHandler: 38aa38413896620338948fbb5c90579a7b1c3fde
+ RNGoogleSignin: 97d8ec68fbbe6beb4820b374acf4470acac21756
RNKeychain: a65256b6ca6ba6976132cc4124b238a5b13b3d9c
RNLocalize: dbea38dcb344bf80ff18a1757b1becf11f70cae4
RNPermissions: f5763a7aa5b1aae3b0c0546791b002e3048042bd
@@ -991,7 +1050,9 @@ SPEC CHECKSUMS:
RNShare: bed7c4fbe615f3d977f22feb0902af9a790c1660
RNSVG: 80584470ff1ffc7994923ea135a3e5ad825546b9
RNVectorIcons: 8b5bb0fa61d54cd2020af4f24a51841ce365c7e9
+ RNZipArchive: 6d736ee4e286dbbd9d81206b7a4da355596ca04a
SocketRocket: f32cd54efbe0f095c4d7594881e52619cfe80b17
+ SSZipArchive: fe6a26b2a54d5a0890f2567b5cc6de5caa600aef
Yoga: 8796b55dba14d7004f980b54bcc9833ee45b28ce
PODFILE CHECKSUM: c4f2b64f733d5092ed97bf9c8913baae9338ea31
diff --git a/package.json b/package.json
index 7352a99c..7782afec 100644
--- a/package.json
+++ b/package.json
@@ -13,8 +13,8 @@
"prepare": "husky install"
},
"dependencies": {
- "@adeya/ssi": "0.0.1-alpha.27",
- "@ayanworks/credo-polygon-w3c-module": "0.0.2-alpha.10",
+ "@adeya/ssi": "0.0.1-alpha.30",
+ "@ayanworks/credo-polygon-w3c-module": "1.0.0",
"@ethersproject/shims": "^5.7.0",
"@formatjs/intl-datetimeformat": "^6.10.0",
"@formatjs/intl-displaynames": "^6.5.0",
@@ -29,37 +29,37 @@
"@hyperledger/aries-oca": "1.0.0-alpha.130",
"@hyperledger/indy-vdr-react-native": "0.2.2",
"@react-native-async-storage/async-storage": "^1.19.1",
+ "@react-native-clipboard/clipboard": "^1.14.1",
"@react-native-community/masked-view": "^0.1.11",
"@react-native-community/netinfo": "^9.4.1",
"@react-native-firebase/app": "^18.4.0",
"@react-native-firebase/messaging": "^18.4.0",
+ "@react-native-google-signin/google-signin": "12.1.0",
"@react-navigation/bottom-tabs": "^6.5.8",
"@react-navigation/core": "^6.4.9",
"@react-navigation/devtools": "^6.0.19",
"@react-navigation/native": "^6.1.7",
"@react-navigation/stack": "^6.3.17",
- "@sphereon/pex": "3.2.1-unstable.7",
- "@sphereon/pex-models": "^2.2.0",
- "@sphereon/ssi-types": "^0.18.1",
- "@types/ref-struct-di": "^1.1.9",
+ "@robinbobin/react-native-google-drive-api-wrapper": "^1.2.4",
"axios": "^1.6.0",
"bip39": "^3.1.0",
+ "crypto-js": "^4.2.0",
"events": "^1.1.1",
"expo-modules-core": "^1.2.7",
"i18next": "^23.4.1",
- "jsonpath": "^1.1.1",
"lodash.flatten": "^4.4.0",
"lodash.shuffle": "^4.2.0",
"lodash.startcase": "^4.4.0",
"moment": "^2.29.4",
- "patch-package": "^8.0.0",
"process": "^0.11.0",
+ "qrcode": "^1.5.3",
"query-string": "^8.1.0",
"react": "18.2.0",
"react-i18next": "^13.0.3",
"react-native": "0.72.3",
"react-native-animated-pagination-dots": "^0.1.73",
"react-native-argon2": "^2.0.1",
+ "react-native-blob-util": "^0.19.9",
"react-native-bouncy-checkbox": "^3.0.7",
"react-native-camera": "^4.2.1",
"react-native-collapsible": "^1.6.1",
@@ -72,8 +72,10 @@
"react-native-gesture-handler": "^2.12.1",
"react-native-get-random-values": "^1.9.0",
"react-native-gifted-chat": "^2.4.0",
+ "react-native-html-to-pdf": "^0.12.0",
"react-native-keychain": "^8.1.2",
"react-native-localize": "^3.0.2",
+ "react-native-pdf": "^6.7.5",
"react-native-permissions": "^3.9.0",
"react-native-qrcode-svg": "^6.2.0",
"react-native-randombytes": "^3.0.0",
@@ -90,8 +92,8 @@
"react-native-toast-message": "^2.1.6",
"react-native-vector-icons": "^10.0.0",
"react-native-webview": "^13.3.1",
+ "react-native-zip-archive": "^6.1.2",
"readable-stream": "1.0.33",
- "rn-fetch-blob": "^0.12.0",
"stream-browserify": "^1.0.0",
"unique-names-generator": "^4.7.1",
"util": "^0.10.4",
@@ -105,12 +107,15 @@
"@react-native/eslint-config": "^0.72.2",
"@react-native/metro-config": "^0.72.9",
"@tsconfig/react-native": "^3.0.0",
+ "@types/crypto-js": "^4.2.2",
"@types/lodash.flatten": "^4.4.7",
"@types/lodash.merge": "^4.6.7",
"@types/lodash.shuffle": "^4.2.7",
"@types/lodash.startcase": "^4.4.7",
+ "@types/qrcode": "^1.5.5",
"@types/react": "^18.0.24",
"@types/react-native": "^0.72.2",
+ "@types/react-native-html-to-pdf": "^0.8.3",
"@types/react-native-vector-icons": "^6.4.13",
"@types/react-test-renderer": "^18.0.0",
"@types/uuid": "^9.0.2",
diff --git a/patches/@ayanworks+polygon-did-resolver+0.0.16-alpha.10.patch b/patches/@ayanworks+polygon-did-resolver+0.0.16-alpha.10.patch
deleted file mode 100644
index 71457ff0..00000000
--- a/patches/@ayanworks+polygon-did-resolver+0.0.16-alpha.10.patch
+++ /dev/null
@@ -1,13 +0,0 @@
-diff --git a/node_modules/@ayanworks/polygon-did-resolver/build/config.js b/node_modules/@ayanworks/polygon-did-resolver/build/config.js
-index 6362a6b..a83b612 100644
---- a/node_modules/@ayanworks/polygon-did-resolver/build/config.js
-+++ b/node_modules/@ayanworks/polygon-did-resolver/build/config.js
-@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
- exports.networkConfig = void 0;
- exports.networkConfig = {
- testnet: {
-- URL: 'https://rpc-mumbai.maticvigil.com/',
-+ URL: 'https://polygon-mumbai.infura.io/v3/0579d305568d404e996e49695e9272a3',
- CONTRACT_ADDRESS: '0x12513116875BB3E4F098Ce74624739Ee51bAf023',
- },
- mainnet: {
diff --git a/patches/@credo-ts+core+0.5.3.patch b/patches/@credo-ts+core+0.5.3.patch
new file mode 100644
index 00000000..576d605d
--- /dev/null
+++ b/patches/@credo-ts+core+0.5.3.patch
@@ -0,0 +1,29 @@
+diff --git a/node_modules/@credo-ts/core/build/modules/routing/MediationRecipientApi.js b/node_modules/@credo-ts/core/build/modules/routing/MediationRecipientApi.js
+index 7344332..0250817 100644
+--- a/node_modules/@credo-ts/core/build/modules/routing/MediationRecipientApi.js
++++ b/node_modules/@credo-ts/core/build/modules/routing/MediationRecipientApi.js
+@@ -74,7 +74,7 @@ let MediationRecipientApi = class MediationRecipientApi {
+ }
+ async sendMessage(outboundMessageContext, pickupStrategy) {
+ const mediatorPickupStrategy = pickupStrategy !== null && pickupStrategy !== void 0 ? pickupStrategy : this.config.mediatorPickupStrategy;
+- const transportPriority = mediatorPickupStrategy === MediatorPickupStrategy_1.MediatorPickupStrategy.Implicit
++ const transportPriority = [MediatorPickupStrategy_1.MediatorPickupStrategy.Implicit, MediatorPickupStrategy_1.MediatorPickupStrategy.PickUpV2LiveMode].includes(mediatorPickupStrategy)
+ ? { schemes: ['wss', 'ws'], restrictive: true }
+ : undefined;
+ await this.messageSender.sendMessage(outboundMessageContext, {
+@@ -156,6 +156,7 @@ let MediationRecipientApi = class MediationRecipientApi {
+ this.logger.debug(`Websocket connection to mediator with connectionId '${mediator.connectionId}' is closed, attempting to reconnect...`);
+ try {
+ if (pickupStrategy === MediatorPickupStrategy_1.MediatorPickupStrategy.PickUpV2LiveMode) {
++ await this.openMediationWebSocket(mediator);
+ // Start Pickup v2 protocol in live mode (retrieve any queued message before)
+ await this.messagePickupApi.pickupMessages({
+ connectionId: mediator.connectionId,
+@@ -220,6 +221,7 @@ let MediationRecipientApi = class MediationRecipientApi {
+ // PickUp V2 in Live Mode will retrieve queued messages and then set up live delivery mode
+ this.logger.info(`Starting Live Mode pickup of messages from mediator '${mediatorRecord.id}'`);
+ await this.monitorMediatorWebSocketEvents(mediatorRecord, mediatorPickupStrategy);
++ await this.openMediationWebSocket(mediatorRecord);
+ await this.messagePickupApi.pickupMessages({
+ connectionId: mediatorConnection.id,
+ protocolVersion: 'v2',
diff --git a/patches/@credo-ts+indy-vdr+0.5.3.patch b/patches/@credo-ts+indy-vdr+0.5.3.patch
new file mode 100644
index 00000000..03283b6e
--- /dev/null
+++ b/patches/@credo-ts+indy-vdr+0.5.3.patch
@@ -0,0 +1,40 @@
+diff --git a/node_modules/@credo-ts/indy-vdr/build/anoncreds/IndyVdrAnonCredsRegistry.js b/node_modules/@credo-ts/indy-vdr/build/anoncreds/IndyVdrAnonCredsRegistry.js
+index 30ded2c..5928d48 100644
+--- a/node_modules/@credo-ts/indy-vdr/build/anoncreds/IndyVdrAnonCredsRegistry.js
++++ b/node_modules/@credo-ts/indy-vdr/build/anoncreds/IndyVdrAnonCredsRegistry.js
+@@ -182,7 +182,7 @@ class IndyVdrAnonCredsRegistry {
+ }
+ // Format the schema id based on the type of the credential definition id
+ const schemaId = credentialDefinitionId.startsWith('did:indy')
+- ? (0, identifiers_1.getDidIndySchemaId)(pool.indyNamespace, namespaceIdentifier, schema.schema.name, schema.schema.version)
++ ? (0, identifiers_1.getDidIndySchemaId)(pool.indyNamespace, schema.schema.issuerId, schema.schema.name, schema.schema.version)
+ : schema.schema.schemaId;
+ return {
+ credentialDefinitionId,
+@@ -624,7 +624,7 @@ class IndyVdrAnonCredsRegistry {
+ }
+ }
+ async fetchIndySchemaWithSeqNo(agentContext, seqNo, did) {
+- var _a, _b;
++ var _a, _b, _c;
+ const indyVdrPoolService = agentContext.dependencyManager.resolve(pool_1.IndyVdrPoolService);
+ const { pool } = await indyVdrPoolService.getPoolForDid(agentContext, did);
+ agentContext.config.logger.debug(`Getting transaction with seqNo '${seqNo}' from ledger '${pool.indyNamespace}'`);
+@@ -637,14 +637,15 @@ class IndyVdrAnonCredsRegistry {
+ return null;
+ }
+ const schema = (_b = response.result.data) === null || _b === void 0 ? void 0 : _b.txn.data;
+- const schemaId = (0, anoncreds_1.getUnqualifiedSchemaId)(did, schema.data.name, schema.data.version);
++ const schemaDid = (_c = response.result.data) === null || _c === void 0 ? void 0 : _c.txn.metadata.from;
++ const schemaId = (0, anoncreds_1.getUnqualifiedSchemaId)(schemaDid, schema.data.name, schema.data.version);
+ return {
+ schema: {
+ schemaId,
+ attr_name: schema.data.attr_names,
+ name: schema.data.name,
+ version: schema.data.version,
+- issuerId: did,
++ issuerId: schemaDid,
+ seqNo,
+ },
+ indyNamespace: pool.indyNamespace,
diff --git a/yarn.lock b/yarn.lock
index db58d246..a326ae36 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -7,10 +7,10 @@
resolved "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz"
integrity sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==
-"@adeya/ssi@0.0.1-alpha.27":
- version "0.0.1-alpha.27"
- resolved "https://registry.yarnpkg.com/@adeya/ssi/-/ssi-0.0.1-alpha.27.tgz#f1ba7965c3ed7866d5c9f861de7836cf952df10a"
- integrity sha512-eO0aASreaWDJhsoMNctYlA4QCWzj/cOASiM/r9UKqKzaTh/vcNR+H4+Bd244qllz5ZQQE1EE1hnmOBhN7U51rQ==
+"@adeya/ssi@0.0.1-alpha.30":
+ version "0.0.1-alpha.30"
+ resolved "https://registry.yarnpkg.com/@adeya/ssi/-/ssi-0.0.1-alpha.30.tgz#62e9131dc97af765ec9269fd418c3be2783c2265"
+ integrity sha512-v3O1MyZEPrYYQ64rADrWpvfFIdspAP43n+rsOk96nfpsQhono6UAU3wx5SP25TIr1mYMFOQyeDHXgFZJ2xKV5Q==
dependencies:
"@credo-ts/anoncreds" "0.5.3"
"@credo-ts/askar" "0.5.3"
@@ -85,26 +85,26 @@
dependencies:
static-eval "2.0.2"
-"@ayanworks/credo-polygon-w3c-module@0.0.2-alpha.10":
- version "0.0.2-alpha.10"
- resolved "https://registry.yarnpkg.com/@ayanworks/credo-polygon-w3c-module/-/credo-polygon-w3c-module-0.0.2-alpha.10.tgz#41d2a493aeed0fec4a92e3bd5d2f70d5e044e6c2"
- integrity sha512-M2IWdeEZxHwT7+oW3Pm/ycOSxad9VnJx315Wd1+PPZdonwSYKK6U2YdvLe3CiozevhjWReDjnIatRnCmk38Xnw==
+"@ayanworks/credo-polygon-w3c-module@1.0.0":
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/@ayanworks/credo-polygon-w3c-module/-/credo-polygon-w3c-module-1.0.0.tgz#e48dcb48f8708b2959ebe02fcf3a5e08b168d479"
+ integrity sha512-dqcPI07bxzzGlOUkSHsyTe6DNAcXC3kvVdzH6BtOzrRyQ6Pujtr+6Fwn9VAFEKI88Pdxsk2upHAtlj1TmaeFRw==
dependencies:
- "@ayanworks/polygon-did-registrar" "0.0.16-alpha.20"
- "@ayanworks/polygon-did-resolver" "0.0.16-alpha.15"
- "@ayanworks/polygon-schema-manager" "0.0.2-alpha.9"
+ "@ayanworks/polygon-did-registrar" "1.0.0"
+ "@ayanworks/polygon-did-resolver" "1.0.0"
+ "@ayanworks/polygon-schema-manager" "1.0.0"
"@credo-ts/askar" "0.5.3"
"@credo-ts/core" "0.5.3"
did-resolver "^4.1.0"
ethers "^6.9.0"
-"@ayanworks/polygon-did-registrar@0.0.16-alpha.20":
- version "0.0.16-alpha.20"
- resolved "https://registry.yarnpkg.com/@ayanworks/polygon-did-registrar/-/polygon-did-registrar-0.0.16-alpha.20.tgz#c17fc082db84959cf1fd745515ad41c16a810236"
- integrity sha512-4gH4Vq01fEtkgOzn43J/3B7sWs4N+KvkL2tvrtOF3cfELlUE4UuRx97JAXJlX9ayGWIspTYg+GMbnkvfTLT8GQ==
+"@ayanworks/polygon-did-registrar@1.0.0":
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/@ayanworks/polygon-did-registrar/-/polygon-did-registrar-1.0.0.tgz#6704a51b154e12c9484c90581a1c9dc41e01dcd3"
+ integrity sha512-pK6WELi9avhxFk7BGioMFu9U/VL6GLvW6n18QFq8G4EMPMWsAvTfiiqUadTVWU8nuHSOrgpBBW8kN5DPWwJPFg==
dependencies:
- "@ayanworks/polygon-did-registry-contract" "2.0.1-alpha.7"
- "@ayanworks/polygon-did-resolver" "^0.0.16-alpha.15"
+ "@ayanworks/polygon-did-registry-contract" "3.0.0"
+ "@ayanworks/polygon-did-resolver" "1.0.0"
"@credo-ts/core" "0.5.3"
"@ethersproject/basex" "^5.7.0"
"@ethersproject/signing-key" "^5.7.0"
@@ -114,27 +114,27 @@
ethers "^6.9.0"
uuid "^9.0.1"
-"@ayanworks/polygon-did-registry-contract@2.0.1-alpha.7":
- version "2.0.1-alpha.7"
- resolved "https://registry.yarnpkg.com/@ayanworks/polygon-did-registry-contract/-/polygon-did-registry-contract-2.0.1-alpha.7.tgz#4f694602701ac1f7b0503c150a8764a289b0294c"
- integrity sha512-pwX45XsGT3LrIBpnIJ6FrzPuB3gSTWiNVSyGGniL0ofUgcsNGqXOv2g3WQSDcG9b7/+AGeoJ6tYqshCbnjsmvQ==
+"@ayanworks/polygon-did-registry-contract@3.0.0":
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/@ayanworks/polygon-did-registry-contract/-/polygon-did-registry-contract-3.0.0.tgz#52b18768b887e933d44a9713b33dc2efbb1dcf53"
+ integrity sha512-RnW31nkDIMG1YzuOycxGGrJFpgTcpBwS/UZR6/wMPrsJBKBEN28k2CZImwXkbgaknyTfL7xe1u3C8NxfDvhI4Q==
-"@ayanworks/polygon-did-resolver@0.0.16-alpha.15", "@ayanworks/polygon-did-resolver@^0.0.16-alpha.15":
- version "0.0.16-alpha.15"
- resolved "https://registry.yarnpkg.com/@ayanworks/polygon-did-resolver/-/polygon-did-resolver-0.0.16-alpha.15.tgz#f12969e6d7b7eba2432ccd2f6d9b4a1de5f3dcf9"
- integrity sha512-JyjgFaWWSQzzj1LKsopYVvIJjeo6lzqfVIheILmgxcxvTo1/skFatthocBNmyQ4Vc8QyKc05s5AbTUkm74wNbg==
+"@ayanworks/polygon-did-resolver@1.0.0":
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/@ayanworks/polygon-did-resolver/-/polygon-did-resolver-1.0.0.tgz#4d267004a509fad9a75bb18c6f449f6c51e1f198"
+ integrity sha512-mzYh3XNQ4HJ0GakP1QD7UOW8PjMAhdtu/TXzeOqMtHLhWktFMQcgJuqNMNxMGbJFdIe12qFJROlle6p1BjF01g==
dependencies:
- "@ayanworks/polygon-did-registry-contract" "2.0.1-alpha.7"
+ "@ayanworks/polygon-did-registry-contract" "3.0.0"
did-resolver "^4.1.0"
ethers "^5.1.0"
-"@ayanworks/polygon-schema-manager@0.0.2-alpha.9":
- version "0.0.2-alpha.9"
- resolved "https://registry.yarnpkg.com/@ayanworks/polygon-schema-manager/-/polygon-schema-manager-0.0.2-alpha.9.tgz#24566f6d41bffc16d0483576df8b766217312fef"
- integrity sha512-eHGNWQE8sYEPzYynnDswSLUlkF+BHMDHN5iSIfupbxPObScfMXPtYO/qSu0V4F+QmmmqH5WUpZ7qGBgOyi7j8Q==
+"@ayanworks/polygon-schema-manager@1.0.0":
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/@ayanworks/polygon-schema-manager/-/polygon-schema-manager-1.0.0.tgz#5f71320d93e874477906df15be1aacc32906d6aa"
+ integrity sha512-XByf/mydccNEnfiW83K9WlayvPgrRpLVqX7CwuHtdBTSlrhed+Vc9FnZLIQUsGGnlbowQVLaPteSaKg/lEYUzw==
dependencies:
- "@ayanworks/polygon-did-registry-contract" "2.0.1-alpha.7"
- "@ayanworks/polygon-did-resolver" "^0.0.16-alpha.15"
+ "@ayanworks/polygon-did-registry-contract" "3.0.0"
+ "@ayanworks/polygon-did-resolver" "1.0.0"
"@nomicfoundation/hardhat-verify" "^2.0.3"
axios "^1.6.3"
did-resolver "^4.1.0"
@@ -2392,6 +2392,18 @@
resolved "https://registry.yarnpkg.com/@hyperledger/indy-vdr-shared/-/indy-vdr-shared-0.2.2.tgz#9ca8b56cd89ab18792d129a0358b641e211274e3"
integrity sha512-9425MHU3K+/ahccCRjOIX3Z/51gqxvp3Nmyujyqlx9cd7PWG2Rianx7iNWecFBkdAEqS0DfHsb6YqqH39YZp/A==
+"@isaacs/cliui@^8.0.2":
+ version "8.0.2"
+ resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550"
+ integrity sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==
+ dependencies:
+ string-width "^5.1.2"
+ string-width-cjs "npm:string-width@^4.2.0"
+ strip-ansi "^7.0.1"
+ strip-ansi-cjs "npm:strip-ansi@^6.0.1"
+ wrap-ansi "^8.1.0"
+ wrap-ansi-cjs "npm:wrap-ansi@^7.0.0"
+
"@istanbuljs/load-nyc-config@^1.0.0":
version "1.1.0"
resolved "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz"
@@ -2808,6 +2820,11 @@
tslib "^2.5.0"
webcrypto-core "^1.7.7"
+"@pkgjs/parseargs@^0.11.0":
+ version "0.11.0"
+ resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33"
+ integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==
+
"@pkgr/utils@^2.3.1":
version "2.4.2"
resolved "https://registry.npmjs.org/@pkgr/utils/-/utils-2.4.2.tgz"
@@ -2827,6 +2844,11 @@
dependencies:
merge-options "^3.0.4"
+"@react-native-clipboard/clipboard@^1.14.1":
+ version "1.14.1"
+ resolved "https://registry.yarnpkg.com/@react-native-clipboard/clipboard/-/clipboard-1.14.1.tgz#835f82fc86881a0808a8405f2576617bb5383554"
+ integrity sha512-SM3el0A28SwoeJljVNhF217o0nI4E7RfalLmuRQcT1/7tGcxUjgFa3jyrEndYUct8/uxxK5EUNGUu1YEDqzxqw==
+
"@react-native-community/cli-clean@11.3.5":
version "11.3.5"
resolved "https://registry.yarnpkg.com/@react-native-community/cli-clean/-/cli-clean-11.3.5.tgz#07c8a01e433ea6c6e32eb647908be48952888cdd"
@@ -3014,6 +3036,11 @@
resolved "https://registry.yarnpkg.com/@react-native-firebase/messaging/-/messaging-18.4.0.tgz#7f05bbfa6841f84e96d97935f33ac9638bee346c"
integrity sha512-oVxOHRmLrdEXBVHgnrTkzWFiL/SbXi9oaXf/kYuqgcMGkupIhBNpPxvnqq4Z1QO0d9huZp0KHDeTgNEwA5hq1Q==
+"@react-native-google-signin/google-signin@12.1.0":
+ version "12.1.0"
+ resolved "https://registry.yarnpkg.com/@react-native-google-signin/google-signin/-/google-signin-12.1.0.tgz#9111dc068d1ec40b1b24d73ca5c0b171ba08e543"
+ integrity sha512-Vn2zXCAz0Vh43xEtFebqd0wGvQWXGPkTZvfff/3V7+5BQKR7nL52mlry10llCLNRiVDDz0oWoBGETifpBz7W8A==
+
"@react-native/assets-registry@^0.72.0":
version "0.72.0"
resolved "https://registry.npmjs.org/@react-native/assets-registry/-/assets-registry-0.72.0.tgz"
@@ -3073,6 +3100,11 @@
metro-react-native-babel-transformer "0.76.8"
metro-runtime "0.76.8"
+"@react-native/normalize-color@*":
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/@react-native/normalize-color/-/normalize-color-2.1.0.tgz#939b87a9849e81687d3640c5efa2a486ac266f91"
+ integrity sha512-Z1jQI2NpdFJCVgpY+8Dq/Bt3d+YUi1928Q+/CZm/oh66fzM0RUl54vvuXlPJKybH4pdCZey1eDTPaLHkMPNgWA==
+
"@react-native/normalize-colors@*":
version "0.73.0"
resolved "https://registry.npmjs.org/@react-native/normalize-colors/-/normalize-colors-0.73.0.tgz"
@@ -3152,6 +3184,15 @@
color "^4.2.3"
warn-once "^0.1.0"
+"@robinbobin/react-native-google-drive-api-wrapper@^1.2.4":
+ version "1.2.4"
+ resolved "https://registry.yarnpkg.com/@robinbobin/react-native-google-drive-api-wrapper/-/react-native-google-drive-api-wrapper-1.2.4.tgz#b5c0c30c3754b9abba9034897b66a4afd7f1755c"
+ integrity sha512-X4qa6mmINpOU/1KCV7xa+NGKmKOtBKyqvlkuntmXg6RDq+7ojYH4fhH/dO/wKMss6n77kDrT9WPKW/zdsc9ESQ==
+ dependencies:
+ base64-js "^1.5.1"
+ simple-common-utils "^2.3.0"
+ utf8 "^3.0.0"
+
"@sd-jwt/core@^0.6.1":
version "0.6.1"
resolved "https://registry.yarnpkg.com/@sd-jwt/core/-/core-0.6.1.tgz#d28be10d0f4b672636fcf7ad71737cb08e5dae96"
@@ -3464,6 +3505,11 @@
dependencies:
"@babel/types" "^7.20.7"
+"@types/crypto-js@^4.2.2":
+ version "4.2.2"
+ resolved "https://registry.yarnpkg.com/@types/crypto-js/-/crypto-js-4.2.2.tgz#771c4a768d94eb5922cc202a3009558204df0cea"
+ integrity sha512-sDOLlVbHhXpAUAL0YHDUUwDZf3iN4Bwi4W6a0W0b+QcAezUbRtH4FVb+9J4h+XFPW7l/gQ9F8qC7P+Ec4k8QVQ==
+
"@types/graceful-fs@^4.1.3":
version "4.1.6"
resolved "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.6.tgz"
@@ -3569,6 +3615,18 @@
resolved "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz"
integrity sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==
+"@types/qrcode@^1.5.5":
+ version "1.5.5"
+ resolved "https://registry.yarnpkg.com/@types/qrcode/-/qrcode-1.5.5.tgz#993ff7c6b584277eee7aac0a20861eab682f9dac"
+ integrity sha512-CdfBi/e3Qk+3Z/fXYShipBT13OJ2fDO2Q2w5CIP5anLTLIndQG9z6P1cnm+8zCWSpm5dnxMFd/uREtb0EXuQzg==
+ dependencies:
+ "@types/node" "*"
+
+"@types/react-native-html-to-pdf@^0.8.3":
+ version "0.8.3"
+ resolved "https://registry.yarnpkg.com/@types/react-native-html-to-pdf/-/react-native-html-to-pdf-0.8.3.tgz#0e41b666c711b114957e42f7a7c665fb2fea8045"
+ integrity sha512-KjyR1F9KhcmX8p9y/8WYMiaK4DV/cYBUO1XHEzD9dDVZBkY9ujbdMLYO7ZvmAffNT2Q484Qvg+t6szgVcnN22g==
+
"@types/react-native-vector-icons@^6.4.13":
version "6.4.13"
resolved "https://registry.npmjs.org/@types/react-native-vector-icons/-/react-native-vector-icons-6.4.13.tgz"
@@ -3608,20 +3666,6 @@
"@types/scheduler" "*"
csstype "^3.0.2"
-"@types/ref-napi@*":
- version "3.0.12"
- resolved "https://registry.yarnpkg.com/@types/ref-napi/-/ref-napi-3.0.12.tgz#2ddde995ecf769f1e5da01604e468348949c72c3"
- integrity sha512-UZPKghRaLlWx2lPAphpdtYe62TbGBaPeqUM6gF1vI6FPRIu/Tff/WMAzpJRFU3jJIiD8HiXpVt2RjcFHtA6YRg==
- dependencies:
- "@types/node" "*"
-
-"@types/ref-struct-di@^1.1.9":
- version "1.1.12"
- resolved "https://registry.yarnpkg.com/@types/ref-struct-di/-/ref-struct-di-1.1.12.tgz#5d9167488692816754c6d2b9064d9b0313609d59"
- integrity sha512-R2RNkGIROGoJTbXYTXrsXybnsQD4iAy26ih/G6HCeCB9luWFQKkr537XGz0uGJ1kH8y8RMkdbQmD/wBulrOPHw==
- dependencies:
- "@types/ref-napi" "*"
-
"@types/scheduler@*":
version "0.16.3"
resolved "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz"
@@ -3870,11 +3914,6 @@
expo-modules-autolinking "^0.0.3"
invariant "^2.2.4"
-"@yarnpkg/lockfile@^1.1.0":
- version "1.1.0"
- resolved "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz"
- integrity sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==
-
abbrev@1:
version "1.1.1"
resolved "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz"
@@ -4012,7 +4051,7 @@ ansi-styles@^5.0.0:
resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz"
integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==
-ansi-styles@^6.0.0:
+ansi-styles@^6.0.0, ansi-styles@^6.1.0:
version "6.2.1"
resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz"
integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==
@@ -4420,7 +4459,7 @@ base-64@0.1.0, base-64@^0.1.0:
resolved "https://registry.npmjs.org/base-64/-/base-64-0.1.0.tgz"
integrity sha512-Y5gU45svrR5tI2Vt/X9GPd3L0HNIKzGu202EjxrXMpuc2V2CiKgemAbUUsqYmZJvPtCXoUKjNZwBJzsNScUbXA==
-base64-js@*, base64-js@^1.0.2, base64-js@^1.1.2, base64-js@^1.3.0, base64-js@^1.3.1:
+base64-js@*, base64-js@^1.0.2, base64-js@^1.1.2, base64-js@^1.3.0, base64-js@^1.3.1, base64-js@^1.5.1:
version "1.5.1"
resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz"
integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
@@ -4628,14 +4667,6 @@ buffer-xor@^1.0.3:
resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9"
integrity sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==
-buffer@*, buffer@^6.0.3:
- version "6.0.3"
- resolved "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz"
- integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==
- dependencies:
- base64-js "^1.3.1"
- ieee754 "^1.2.1"
-
buffer@^4.9.1:
version "4.9.2"
resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.2.tgz#230ead344002988644841ab0244af8c44bbe3ef8"
@@ -4653,6 +4684,14 @@ buffer@^5.4.3, buffer@^5.5.0:
base64-js "^1.3.1"
ieee754 "^1.1.13"
+buffer@^6.0.3:
+ version "6.0.3"
+ resolved "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz"
+ integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==
+ dependencies:
+ base64-js "^1.3.1"
+ ieee754 "^1.2.1"
+
bundle-name@^3.0.0:
version "3.0.0"
resolved "https://registry.npmjs.org/bundle-name/-/bundle-name-3.0.0.tgz"
@@ -4777,7 +4816,7 @@ ci-info@^2.0.0:
resolved "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz"
integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==
-ci-info@^3.2.0, ci-info@^3.7.0:
+ci-info@^3.2.0:
version "3.8.0"
resolved "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz"
integrity sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==
@@ -5139,7 +5178,7 @@ cross-fetch@^4.0.0:
dependencies:
node-fetch "^2.6.12"
-cross-spawn@^7.0.2, cross-spawn@^7.0.3:
+cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3:
version "7.0.3"
resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz"
integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==
@@ -5148,6 +5187,11 @@ cross-spawn@^7.0.2, cross-spawn@^7.0.3:
shebang-command "^2.0.0"
which "^2.0.1"
+crypto-js@4.2.0, crypto-js@^4.2.0:
+ version "4.2.0"
+ resolved "https://registry.yarnpkg.com/crypto-js/-/crypto-js-4.2.0.tgz#4d931639ecdfd12ff80e8186dba6af2c2e856631"
+ integrity sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==
+
crypto-ld@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/crypto-ld/-/crypto-ld-6.0.0.tgz#cf8dcf566cb3020bdb27f0279e6cc9b46d031cd7"
@@ -5385,6 +5429,15 @@ deprecated-react-native-prop-types@4.1.0:
invariant "*"
prop-types "*"
+deprecated-react-native-prop-types@^2.3.0:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/deprecated-react-native-prop-types/-/deprecated-react-native-prop-types-2.3.0.tgz#c10c6ee75ff2b6de94bb127f142b814e6e08d9ab"
+ integrity sha512-pWD0voFtNYxrVqvBMYf5gq3NA2GCpfodS1yNynTPc93AYA/KEMGeWDqqeUB6R2Z9ZofVhks2aeJXiuQqKNpesA==
+ dependencies:
+ "@react-native/normalize-color" "*"
+ invariant "*"
+ prop-types "*"
+
des.js@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.1.0.tgz#1d37f5766f3bbff4ee9638e871a8768c173b81da"
@@ -6349,13 +6402,6 @@ find-up@^5.0.0, find-up@~5.0.0:
locate-path "^6.0.0"
path-exists "^4.0.0"
-find-yarn-workspace-root@^2.0.0:
- version "2.0.0"
- resolved "https://registry.npmjs.org/find-yarn-workspace-root/-/find-yarn-workspace-root-2.0.0.tgz"
- integrity sha512-1IMnbjt4KzsQfnhnzNd8wUEgXZ44IzZaZmnLYx7D5FZlaHt2gW20Cri8Q+E/t5tIj4+epTBub+2Zxu/vNILzqQ==
- dependencies:
- micromatch "^4.0.2"
-
fix-esm@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/fix-esm/-/fix-esm-1.0.1.tgz#e0e2199d841e43ff7db9b5f5ba7496bc45130ebb"
@@ -6427,6 +6473,14 @@ for-own@^1.0.0:
dependencies:
for-in "^1.0.1"
+foreground-child@^3.1.0:
+ version "3.2.1"
+ resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.2.1.tgz#767004ccf3a5b30df39bed90718bab43fe0a59f7"
+ integrity sha512-PXUUyLqrR2XCWICfv6ukppP96sdFwWbNEnfEMt7jNsISjMsvaLNinAHNDYyvkyU+SZG2BTSbT5NjG+vZslfGTA==
+ dependencies:
+ cross-spawn "^7.0.0"
+ signal-exit "^4.0.1"
+
form-data@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.1.tgz#ebd53791b78356a99af9a300d4282c4d5eb9755f"
@@ -6466,7 +6520,7 @@ fs-extra@^8.1.0:
jsonfile "^4.0.0"
universalify "^0.1.0"
-fs-extra@^9.0.0, fs-extra@^9.1.0:
+fs-extra@^9.1.0:
version "9.1.0"
resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz"
integrity sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==
@@ -6622,17 +6676,17 @@ glob-parent@^6.0.2:
dependencies:
is-glob "^4.0.3"
-glob@7.0.6:
- version "7.0.6"
- resolved "https://registry.yarnpkg.com/glob/-/glob-7.0.6.tgz#211bafaf49e525b8cd93260d14ab136152b3f57a"
- integrity sha512-f8c0rE8JiCxpa52kWPAOa3ZaYEnzofDzCQLCn3Vdk0Z5OVLq3BsRFJI4S4ykpeVW6QMGBUkMeUpoEgWnMTnw5Q==
+glob@^10.3.10:
+ version "10.4.4"
+ resolved "https://registry.yarnpkg.com/glob/-/glob-10.4.4.tgz#d60943feb6f8140522117e6576a923b715718380"
+ integrity sha512-XsOKvHsu38Xe19ZQupE6N/HENeHQBA05o3hV8labZZT2zYDg1+emxWHnc/Bm9AcCMPXfD6jt+QC7zC5JSFyumw==
dependencies:
- fs.realpath "^1.0.0"
- inflight "^1.0.4"
- inherits "2"
- minimatch "^3.0.2"
- once "^1.3.0"
- path-is-absolute "^1.0.0"
+ foreground-child "^3.1.0"
+ jackspeak "^3.1.2"
+ minimatch "^9.0.4"
+ minipass "^7.1.2"
+ package-json-from-dist "^1.0.0"
+ path-scurry "^1.11.1"
glob@^7.1.3, glob@^7.1.4:
version "7.2.3"
@@ -7269,7 +7323,7 @@ is-wsl@^1.1.0:
resolved "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz"
integrity sha512-gfygJYZ2gLTDlmbWMI0CE2MwnFzSN/2SZfkMlItC4K/JBlsWVDB0bO6XhqcY13YXE7iMcAJnzTCJjPiTeJJ0Mw==
-is-wsl@^2.1.1, is-wsl@^2.2.0:
+is-wsl@^2.2.0:
version "2.2.0"
resolved "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz"
integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==
@@ -7366,6 +7420,15 @@ istanbul-reports@^3.1.3:
html-escaper "^2.0.0"
istanbul-lib-report "^3.0.0"
+jackspeak@^3.1.2:
+ version "3.4.2"
+ resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-3.4.2.tgz#c3d1e00071d52dba8b0dac17cd2a12d0187d2989"
+ integrity sha512-qH3nOSj8q/8+Eg8LUPOq3C+6HWkpUioIjDsq1+D4zY91oZvpPttw8GwtF1nReRYKXl+1AORyFqtm2f5Q1SB6/Q==
+ dependencies:
+ "@isaacs/cliui" "^8.0.2"
+ optionalDependencies:
+ "@pkgjs/parseargs" "^0.11.0"
+
jest-changed-files@^29.5.0:
version "29.5.0"
resolved "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.5.0.tgz"
@@ -7861,13 +7924,6 @@ json-stable-stringify-without-jsonify@^1.0.1:
resolved "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz"
integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==
-json-stable-stringify@^1.0.2:
- version "1.0.2"
- resolved "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.2.tgz"
- integrity sha512-eunSSaEnxV12z+Z73y/j5N37/In40GK4GmsSy+tEHJMxknvqnA7/djeYtAgW0GsWHUfg+847WJjKaEylk2y09g==
- dependencies:
- jsonify "^0.0.1"
-
json-text-sequence@~0.3.0:
version "0.3.0"
resolved "https://registry.npmjs.org/json-text-sequence/-/json-text-sequence-0.3.0.tgz"
@@ -7903,11 +7959,6 @@ jsonfile@^6.0.1:
optionalDependencies:
graceful-fs "^4.1.6"
-jsonify@^0.0.1:
- version "0.0.1"
- resolved "https://registry.npmjs.org/jsonify/-/jsonify-0.0.1.tgz"
- integrity sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg==
-
jsonld-signatures@^11.0.0:
version "11.2.1"
resolved "https://registry.yarnpkg.com/jsonld-signatures/-/jsonld-signatures-11.2.1.tgz#e2ff23ac7476fcdb92e5fecd9a1734ceaf904bb0"
@@ -7979,13 +8030,6 @@ kind-of@^6.0.0, kind-of@^6.0.1, kind-of@^6.0.2:
resolved "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz"
integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==
-klaw-sync@^6.0.0:
- version "6.0.0"
- resolved "https://registry.npmjs.org/klaw-sync/-/klaw-sync-6.0.0.tgz"
- integrity sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ==
- dependencies:
- graceful-fs "^4.1.11"
-
kleur@^3.0.3:
version "3.0.3"
resolved "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz"
@@ -8199,6 +8243,11 @@ lower-case@^2.0.2:
dependencies:
tslib "^2.0.3"
+lru-cache@^10.2.0:
+ version "10.4.2"
+ resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.4.2.tgz#78c38f194b747174cff90e60afabcae40c3619f2"
+ integrity sha512-voV4dDrdVZVNz84n39LFKDaRzfwhdzJ7akpyXfTMxCgRUp07U3lcJUXRlhTKP17rgt09sUzLi5iCitpEAr+6ug==
+
lru-cache@^5.1.1:
version "5.1.1"
resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz"
@@ -8835,7 +8884,7 @@ metro@0.76.8:
ws "^7.5.1"
yargs "^17.6.2"
-micromatch@^4.0.2, micromatch@^4.0.4, micromatch@^4.0.5:
+micromatch@^4.0.4, micromatch@^4.0.5:
version "4.0.5"
resolved "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz"
integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==
@@ -8907,6 +8956,13 @@ minimatch@^5.0.1:
dependencies:
brace-expansion "^2.0.1"
+minimatch@^9.0.4:
+ version "9.0.5"
+ resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5"
+ integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==
+ dependencies:
+ brace-expansion "^2.0.1"
+
minimist@^1.2.0, minimist@^1.2.6:
version "1.2.8"
resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz"
@@ -8924,6 +8980,11 @@ minipass@^5.0.0:
resolved "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz"
integrity sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==
+"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.1.2:
+ version "7.1.2"
+ resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.2.tgz#93a9626ce5e5e66bd4db86849e7515e92340a707"
+ integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==
+
minizlib@^2.1.1:
version "2.1.2"
resolved "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz"
@@ -9306,14 +9367,6 @@ open@^6.2.0:
dependencies:
is-wsl "^1.1.0"
-open@^7.4.2:
- version "7.4.2"
- resolved "https://registry.npmjs.org/open/-/open-7.4.2.tgz"
- integrity sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==
- dependencies:
- is-docker "^2.0.0"
- is-wsl "^2.1.1"
-
open@^9.1.0:
version "9.1.0"
resolved "https://registry.npmjs.org/open/-/open-9.1.0.tgz"
@@ -9368,11 +9421,6 @@ ora@^5.4.1:
strip-ansi "^6.0.0"
wcwidth "^1.0.1"
-os-tmpdir@~1.0.2:
- version "1.0.2"
- resolved "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz"
- integrity sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==
-
p-limit@^2.0.0, p-limit@^2.2.0:
version "2.3.0"
resolved "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz"
@@ -9420,6 +9468,11 @@ p-try@^2.0.0:
resolved "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz"
integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==
+package-json-from-dist@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz#e501cd3094b278495eb4258d4c9f6d5ac3019f00"
+ integrity sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==
+
pako@^2.0.4:
version "2.1.0"
resolved "https://registry.yarnpkg.com/pako/-/pako-2.1.0.tgz#266cc37f98c7d883545d11335c00fbd4062c9a86"
@@ -9466,27 +9519,6 @@ parseurl@~1.3.3:
resolved "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz"
integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==
-patch-package@^8.0.0:
- version "8.0.0"
- resolved "https://registry.npmjs.org/patch-package/-/patch-package-8.0.0.tgz"
- integrity sha512-da8BVIhzjtgScwDJ2TtKsfT5JFWz1hYoBl9rUQ1f38MC2HwnEIkK8VN3dKMKcP7P7bvvgzNDbfNHtx3MsQb5vA==
- dependencies:
- "@yarnpkg/lockfile" "^1.1.0"
- chalk "^4.1.2"
- ci-info "^3.7.0"
- cross-spawn "^7.0.3"
- find-yarn-workspace-root "^2.0.0"
- fs-extra "^9.0.0"
- json-stable-stringify "^1.0.2"
- klaw-sync "^6.0.0"
- minimist "^1.2.6"
- open "^7.4.2"
- rimraf "^2.6.3"
- semver "^7.5.3"
- slash "^2.0.0"
- tmp "^0.0.33"
- yaml "^2.2.2"
-
path-dirname@^1.0.2:
version "1.0.2"
resolved "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz"
@@ -9522,6 +9554,14 @@ path-parse@^1.0.7:
resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz"
integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
+path-scurry@^1.11.1:
+ version "1.11.1"
+ resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.11.1.tgz#7960a668888594a0720b12a911d1a742ab9f11d2"
+ integrity sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==
+ dependencies:
+ lru-cache "^10.2.0"
+ minipass "^5.0.0 || ^6.0.2 || ^7.0.0"
+
path-type@^4.0.0:
version "4.0.0"
resolved "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz"
@@ -9724,9 +9764,9 @@ pvutils@^1.1.3:
resolved "https://registry.npmjs.org/pvutils/-/pvutils-1.1.3.tgz"
integrity sha512-pMpnA0qRdFp32b1sJl1wOJNxZLQ2cbQx+k6tjNtZ8CpvVhNqEPRgivZ2WOUev2YMajecdH7ctUPDvEe87nariQ==
-qrcode@^1.5.1:
+qrcode@^1.5.1, qrcode@^1.5.3:
version "1.5.3"
- resolved "https://registry.npmjs.org/qrcode/-/qrcode-1.5.3.tgz"
+ resolved "https://registry.yarnpkg.com/qrcode/-/qrcode-1.5.3.tgz#03afa80912c0dccf12bc93f615a535aad1066170"
integrity sha512-puyri6ApkEHYiVl4CFzo1tDkAZ+ATcnbJrJ6RiBM1Fhctdn/ix9MTE3hRph33omisEbC/2fcfemsseiKgBPKZg==
dependencies:
dijkstrajs "^1.0.1"
@@ -9838,6 +9878,14 @@ react-native-argon2@^2.0.1:
resolved "https://registry.npmjs.org/react-native-argon2/-/react-native-argon2-2.0.1.tgz"
integrity sha512-/iOi0S+VVgS1gQGtQgL4ZxUVS4gz6Lav3bgIbtNmr9KbOunnBYzP6/yBe/XxkbpXvasHDwdQnuppOH/nuOBn7w==
+react-native-blob-util@^0.19.9:
+ version "0.19.9"
+ resolved "https://registry.yarnpkg.com/react-native-blob-util/-/react-native-blob-util-0.19.9.tgz#6f2c27d77cd36b9e03c967c54930491404d9d780"
+ integrity sha512-gIuErPqGbBIAPWf+K07x/8mRZ80Waz9DWgwMdQ8zWgms8kYfAji0GNk2gvZZ0y9MKe61jme7oOdZ7InWLRy2GA==
+ dependencies:
+ base-64 "0.1.0"
+ glob "^10.3.10"
+
react-native-bouncy-checkbox@^3.0.7:
version "3.0.7"
resolved "https://registry.npmjs.org/react-native-bouncy-checkbox/-/react-native-bouncy-checkbox-3.0.7.tgz"
@@ -9940,6 +9988,11 @@ react-native-gifted-chat@^2.4.0:
use-memo-one "1.1.3"
uuid "3.4.0"
+react-native-html-to-pdf@^0.12.0:
+ version "0.12.0"
+ resolved "https://registry.yarnpkg.com/react-native-html-to-pdf/-/react-native-html-to-pdf-0.12.0.tgz#2b467296f85c9c9783a7288b19722a7028dcbcb8"
+ integrity sha512-Yb5WO9SfF86s5Yv9PqXQ7fZDr9zZOJ+6jtweT9zFLraPNHWX7pSxe2dSkeg3cGiNrib65ZXGN6ksHymfYLFSSg==
+
react-native-iphone-x-helper@1.3.1:
version "1.3.1"
resolved "https://registry.npmjs.org/react-native-iphone-x-helper/-/react-native-iphone-x-helper-1.3.1.tgz"
@@ -9967,6 +10020,14 @@ react-native-parsed-text@0.0.22:
dependencies:
prop-types "^15.7.x"
+react-native-pdf@^6.7.5:
+ version "6.7.5"
+ resolved "https://registry.yarnpkg.com/react-native-pdf/-/react-native-pdf-6.7.5.tgz#1bc5479f2161189f938912b4080ea9eef8a9d84d"
+ integrity sha512-d1S76p2Vwax2iG+kTnjINiUMvpjtJJvtMiYwHRbgGczT8GJjtXH49YCWOd+HfnUAU29cB+knzsKGYoZBMQM8Ow==
+ dependencies:
+ crypto-js "4.2.0"
+ deprecated-react-native-prop-types "^2.3.0"
+
react-native-permissions@^3.9.0:
version "3.9.0"
resolved "https://registry.yarnpkg.com/react-native-permissions/-/react-native-permissions-3.9.0.tgz#e3ba0460509dce6766e4728173dfa8bbf0886e0b"
@@ -10097,6 +10158,11 @@ react-native-webview@^13.3.1:
escape-string-regexp "2.0.0"
invariant "2.2.4"
+react-native-zip-archive@^6.1.2:
+ version "6.1.2"
+ resolved "https://registry.yarnpkg.com/react-native-zip-archive/-/react-native-zip-archive-6.1.2.tgz#6febcf2ac1b30ef1ed85c88ed29849571c1ba8c8"
+ integrity sha512-LcJomSY/6O3KHy/LF6Gb7F/yRJiZJ0lTlPQPbfeOHBQzfvqNJFJZ8x6HrdeYeokFf/UGB5bY7jfh4es6Y/PhBA==
+
react-native@0.72.3:
version "0.72.3"
resolved "https://registry.yarnpkg.com/react-native/-/react-native-0.72.3.tgz#f8d85ec81c9f3592d091ec8e9ac1694956a72765"
@@ -10389,13 +10455,6 @@ rfdc@^1.3.0:
resolved "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz"
integrity sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==
-rimraf@^2.6.3:
- version "2.7.1"
- resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz"
- integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==
- dependencies:
- glob "^7.1.3"
-
rimraf@^3.0.2:
version "3.0.2"
resolved "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz"
@@ -10418,14 +10477,6 @@ ripemd160@^2.0.0, ripemd160@^2.0.1:
hash-base "^3.0.0"
inherits "^2.0.1"
-rn-fetch-blob@^0.12.0:
- version "0.12.0"
- resolved "https://registry.yarnpkg.com/rn-fetch-blob/-/rn-fetch-blob-0.12.0.tgz#ec610d2f9b3f1065556b58ab9c106eeb256f3cba"
- integrity sha512-+QnR7AsJ14zqpVVUbzbtAjq0iI8c9tCg49tIoKO2ezjzRunN7YL6zFSFSWZm6d+mE/l9r+OeDM3jmb2tBb2WbA==
- dependencies:
- base-64 "0.1.0"
- glob "7.0.6"
-
run-applescript@^5.0.0:
version "5.0.0"
resolved "https://registry.npmjs.org/run-applescript/-/run-applescript-5.0.0.tgz"
@@ -10669,6 +10720,16 @@ signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7:
resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz"
integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==
+signal-exit@^4.0.1:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04"
+ integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==
+
+simple-common-utils@^2.3.0:
+ version "2.6.0"
+ resolved "https://registry.yarnpkg.com/simple-common-utils/-/simple-common-utils-2.6.0.tgz#457f126c20c82ba10212427886f4c8ebe86cc6d7"
+ integrity sha512-K0gtyfMQ1+iDQvZKgdY2L+pbaG0MHp1ke6ho7IL6UKR8f59st+QJgw27FADF+3Hut19C3WUb7IhgENdY/OJG8w==
+
simple-swizzle@^0.2.2:
version "0.2.2"
resolved "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz"
@@ -10686,11 +10747,6 @@ sjcl@^1.0.3:
resolved "https://registry.yarnpkg.com/sjcl/-/sjcl-1.0.8.tgz#f2ec8d7dc1f0f21b069b8914a41a8f236b0e252a"
integrity sha512-LzIjEQ0S0DpIgnxMEayM1rq9aGwGRG4OnZhCdjx7glTaJtf4zRfpg87ImfjSJjoW9vKpagd82McDOwbRT5kQKQ==
-slash@^2.0.0:
- version "2.0.0"
- resolved "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz"
- integrity sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==
-
slash@^3.0.0:
version "3.0.0"
resolved "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz"
@@ -10874,6 +10930,15 @@ string-natural-compare@^3.0.1:
resolved "https://registry.npmjs.org/string-natural-compare/-/string-natural-compare-3.0.1.tgz"
integrity sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw==
+"string-width-cjs@npm:string-width@^4.2.0":
+ version "4.2.3"
+ resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
+ integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
+ dependencies:
+ emoji-regex "^8.0.0"
+ is-fullwidth-code-point "^3.0.0"
+ strip-ansi "^6.0.1"
+
"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
version "4.2.3"
resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz"
@@ -10883,7 +10948,7 @@ string-natural-compare@^3.0.1:
is-fullwidth-code-point "^3.0.0"
strip-ansi "^6.0.1"
-string-width@^5.0.0:
+string-width@^5.0.0, string-width@^5.0.1, string-width@^5.1.2:
version "5.1.2"
resolved "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz"
integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==
@@ -10994,6 +11059,13 @@ string_decoder@~1.1.1:
dependencies:
safe-buffer "~5.1.0"
+"strip-ansi-cjs@npm:strip-ansi@^6.0.1":
+ version "6.0.1"
+ resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
+ integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
+ dependencies:
+ ansi-regex "^5.0.1"
+
strip-ansi@^5.0.0, strip-ansi@^5.2.0:
version "5.2.0"
resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz"
@@ -11191,13 +11263,6 @@ titleize@^3.0.0:
resolved "https://registry.npmjs.org/titleize/-/titleize-3.0.0.tgz"
integrity sha512-KxVu8EYHDPBdUYdKZdKtU2aj2XfEx9AfjXxE/Aj0vT06w2icA09Vus1rh6eSu1y01akYg6BjIK/hxyLJINoMLQ==
-tmp@^0.0.33:
- version "0.0.33"
- resolved "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz"
- integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==
- dependencies:
- os-tmpdir "~1.0.2"
-
tmpl@1.0.5:
version "1.0.5"
resolved "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz"
@@ -11730,6 +11795,15 @@ word-wrap@~1.2.3:
resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34"
integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==
+"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0":
+ version "7.0.0"
+ resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
+ integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
+ dependencies:
+ ansi-styles "^4.0.0"
+ string-width "^4.1.0"
+ strip-ansi "^6.0.0"
+
wrap-ansi@^6.2.0:
version "6.2.0"
resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz"
@@ -11748,6 +11822,15 @@ wrap-ansi@^7.0.0:
string-width "^4.1.0"
strip-ansi "^6.0.0"
+wrap-ansi@^8.1.0:
+ version "8.1.0"
+ resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"
+ integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==
+ dependencies:
+ ansi-styles "^6.1.0"
+ string-width "^5.0.1"
+ strip-ansi "^7.0.1"
+
wrappy@1:
version "1.0.2"
resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz"