diff --git a/apps/easypid/eas.json b/apps/easypid/eas.json index 1c5c3ec5..1c00851d 100644 --- a/apps/easypid/eas.json +++ b/apps/easypid/eas.json @@ -1,6 +1,10 @@ { "build": { + "base": { + "node": "20.11.1" + }, "development": { + "extends": "base", "developmentClient": true, "distribution": "internal", "android": { @@ -15,12 +19,14 @@ } }, "preview": { + "extends": "base", "distribution": "internal", "env": { "APP_VARIANT": "preview" } }, "production": { + "extends": "base", "autoIncrement": true, "distribution": "store", "android": { diff --git a/apps/easypid/package.json b/apps/easypid/package.json index b2ad162d..49cd4afb 100644 --- a/apps/easypid/package.json +++ b/apps/easypid/package.json @@ -7,7 +7,8 @@ "start": "APP_VARIANT=development expo start -c --dev-client", "android": "APP_VARIANT=development expo run:android", "ios": "APP_VARIANT=development expo run:ios", - "prebuild": "APP_VARIANT=development expo prebuild --no-install" + "prebuild": "APP_VARIANT=development expo prebuild --no-install", + "eas-build-pre-install": "corepack enable" }, "dependencies": { "@animo-id/expo-ausweis-sdk": "catalog:", diff --git a/apps/easypid/src/agent/initialize.ts b/apps/easypid/src/agent/initialize.ts index e7fbf3e8..634a89b2 100644 --- a/apps/easypid/src/agent/initialize.ts +++ b/apps/easypid/src/agent/initialize.ts @@ -30,7 +30,9 @@ export async function initializeAppAgent({ await wsp.createSalt() await wsp.register() } - if (getShouldUseCloudHsm()) shouldUseFallbackSecureEnvironment(true) + + const shouldUseCloudHsm = getShouldUseCloudHsm() + if (shouldUseCloudHsm) shouldUseFallbackSecureEnvironment(true) setFallbackSecureEnvironment(wsp) return agent diff --git a/apps/easypid/src/app/(app)/credentials/[id]/attributes.tsx b/apps/easypid/src/app/(app)/credentials/[id]/attributes.tsx index 5aacdeaf..6fc191eb 100644 --- a/apps/easypid/src/app/(app)/credentials/[id]/attributes.tsx +++ b/apps/easypid/src/app/(app)/credentials/[id]/attributes.tsx @@ -2,6 +2,7 @@ import { FunkeCredentialDetailAttributesScreen } from '@easypid/features/wallet/ import { useLocalSearchParams } from 'expo-router' export default function Screen() { + // TODO: this should take an id const { attributes, metadata } = useLocalSearchParams<{ attributes: string metadata: string diff --git a/apps/easypid/src/app/(app)/notifications/offlinePresentation.tsx b/apps/easypid/src/app/(app)/notifications/offlinePresentation.tsx index 756cb9cc..aef0bf3d 100644 --- a/apps/easypid/src/app/(app)/notifications/offlinePresentation.tsx +++ b/apps/easypid/src/app/(app)/notifications/offlinePresentation.tsx @@ -2,17 +2,10 @@ import { FunkeMdocOfflineSharingScreen } from '@easypid/features/share/FunkeMdoc import { useLocalSearchParams } from 'expo-router' export default function Screen() { - const { sessionTranscript, deviceRequest, requestedAttributes } = useLocalSearchParams() + const { sessionTranscript, deviceRequest } = useLocalSearchParams() const sessionTranscriptArray = new Uint8Array(Buffer.from(sessionTranscript as string, 'base64')) const deviceRequestArray = new Uint8Array(Buffer.from(deviceRequest as string, 'base64')) - const requestedAttributesArray = JSON.parse(requestedAttributes as string) - return ( - - ) + return } diff --git a/apps/easypid/src/constants.ts b/apps/easypid/src/constants.ts index 23028440..38fd84e7 100644 --- a/apps/easypid/src/constants.ts +++ b/apps/easypid/src/constants.ts @@ -22,7 +22,7 @@ export const trustedX509Certificates = [ animoFunkeRelyingPartyCertificate, ubiqueRootCertificate, oldAnimoFunkeRelyingPartyCertificate, - 'MIIBKTCBz6ADAgECAhB6T2+09ZDXvmIu0tNzisQWMAoGCCqGSM49BAMCMA0xCzAJBgNVBAYTAk5MMB4XDTcwMDEwMTAwMDAwMFoXDTI1MTEyMjA4MjIxMlowDTELMAkGA1UEBhMCTkwwOTATBgcqhkjOPQIBBggqhkjOPQMBBwMiAALcD1XzKepFxWMAOqV+ln1fybBt7DRO5CV0f9A6mRp2xaMxMC8wLQYDVR0RBCYwJIIiMTkxYi0xMDktMzctMTQ4LTE0OC5uZ3Jvay1mcmVlLmFwcDAKBggqhkjOPQQDAgNJADBGAiEA5oy5/mmbcGuLRlDyXPPVecmrKAaoqDIARdwepx4dIj0CIQCdpXI7GbjIVun1unF4OIzA3IzingADBsjEQvQwuD9s0Q==', + 'MIIBKDCBzqADAgECAhAyWHL4SEss2wMO1QQybg/fMAoGCCqGSM49BAMCMA0xCzAJBgNVBAYTAk5MMB4XDTcwMDEwMTAwMDAwMFoXDTI1MTEyMjA4MjIxMlowDTELMAkGA1UEBhMCTkwwOTATBgcqhkjOPQIBBggqhkjOPQMBBwMiAALcD1XzKepFxWMAOqV+ln1fybBt7DRO5CV0f9A6mRp2xaMwMC4wLAYDVR0RBCUwI4IhMDRkNy0yMTctMTIzLTE4LTI2Lm5ncm9rLWZyZWUuYXBwMAoGCCqGSM49BAMCA0kAMEYCIQDWjkAm/iLhGWcgKILW48f43vEUByvJd2R4lxdTdK9w+wIhALcZIgrH2h9SoXHjuI9ktOMbfVHxt59iq+lOKsC4yOUQ', ] // https://gitlab.opencode.de/bmi/eudi-wallet/eidas-2.0-architekturkonzept/-/blob/main/architecture-proposal.md#pid-contents diff --git a/apps/easypid/src/crypto/WalletServiceProviderClient.ts b/apps/easypid/src/crypto/WalletServiceProviderClient.ts index bce9c084..b1933352 100644 --- a/apps/easypid/src/crypto/WalletServiceProviderClient.ts +++ b/apps/easypid/src/crypto/WalletServiceProviderClient.ts @@ -10,10 +10,12 @@ import { import type { EasyPIDAppAgent } from 'packages/agent/src' import { deriveKeypairFromPin } from './pin' +// TODO: should auto reset after X seconds let __pin: Array | undefined export const setWalletServiceProviderPin = (pin?: Array) => { __pin = pin } + export const getWalletServiceProviderPin = () => __pin const GENERIC_RECORD_WALLET_SERVICE_PROVIDER_SALT_ID = 'GENERIC_RECORD_WALLET_SERVICE_PROVIDER_SALT_ID' diff --git a/apps/easypid/src/features/activity/FunkeActivityDetailScreen.tsx b/apps/easypid/src/features/activity/FunkeActivityDetailScreen.tsx index c891f2d9..2364428e 100644 --- a/apps/easypid/src/features/activity/FunkeActivityDetailScreen.tsx +++ b/apps/easypid/src/features/activity/FunkeActivityDetailScreen.tsx @@ -2,10 +2,7 @@ import { Circle, FlexPage, Heading, Paragraph, ScrollView, Stack, YStack } from import React from 'react' import { createParam } from 'solito' -import type { ClaimFormat } from '@credo-ts/core' -import { getPidDisclosedAttributeNames, isPidCredential, usePidCredential } from '@easypid/hooks' -import { getPidAttributesForDisplay } from '@easypid/hooks' -import { useCredentialsWithCustomDisplay } from '@easypid/hooks/useCredentialsWithCustomDisplay' +import { useCredentialsForDisplay } from '@package/agent' import { CardWithAttributes, TextBackButton, activityInteractions } from '@package/app' import { useScrollViewPosition } from '@package/app/src/hooks' import { formatRelativeDate } from 'packages/utils/src' @@ -21,10 +18,9 @@ export function FunkeActivityDetailScreen() { const { params } = useParams() const router = useRouter() const { bottom } = useSafeAreaInsets() - const { pidCredentialForDisplay } = usePidCredential() const { activities } = useActivities() - const { credentials } = useCredentialsWithCustomDisplay() + const { credentials } = useCredentialsForDisplay() const activity = activities.find((activity) => activity.id === params.id) if (!activity || activity.type === 'received') { @@ -77,55 +73,30 @@ export function FunkeActivityDetailScreen() { {activity.request.credentials && activity.request.credentials.length > 0 ? ( activity.request.credentials.map((activityCredential) => { - const credential = credentials.find((credential) => credential.id.includes(activityCredential.id)) + if ('id' in activityCredential) { + const credential = credentials.find((credential) => credential.id === activityCredential.id) - if (!credential) - return ( - - ) + if (!credential) { + return ( + + ) + } - const isExpired = credential.metadata.validUntil - ? new Date(credential.metadata.validUntil) < new Date() - : false + const isExpired = credential.metadata.validUntil + ? new Date(credential.metadata.validUntil) < new Date() + : false - const isNotYetActive = credential.metadata.validFrom - ? new Date(credential.metadata.validFrom) > new Date() - : false + const isNotYetActive = credential.metadata.validFrom + ? new Date(credential.metadata.validFrom) > new Date() + : false - if (isPidCredential(credential.metadata.type)) { - return ( - - ) - } - - if (credential) return ( ) + } }) ) : ( diff --git a/apps/easypid/src/features/activity/activityRecord.ts b/apps/easypid/src/features/activity/activityRecord.ts index 8f642d78..d432bd40 100644 --- a/apps/easypid/src/features/activity/activityRecord.ts +++ b/apps/easypid/src/features/activity/activityRecord.ts @@ -1,6 +1,17 @@ import { utils } from '@credo-ts/core' -import { type DisplayImage, type EasyPIDAppAgent, getWalletJsonStore, useWalletJsonRecord } from '@package/agent' +import { + type CredentialForDisplayId, + type CredentialsForProofRequest, + type DisplayImage, + type EasyPIDAppAgent, + type FormattedSubmission, + getDisclosedAttributeNamesForDisplay, + getUnsatisfiedAttributePathsForDisplay, + getWalletJsonStore, + useWalletJsonRecord, +} from '@package/agent' import { useMemo } from 'react' +import type { AppAgent } from '../../agent' export type ActivityType = 'shared' | 'received' export type ActivityStatus = 'success' | 'failed' | 'stopped' @@ -22,14 +33,23 @@ interface BaseActivity { } } +export interface PresentationActivityCredentialNotFound { + attributeNames: string[] + name?: string +} + +export interface PresentationActivityCredential { + id: CredentialForDisplayId + name?: string + attributeNames: string[] + attributes: Record + metadata: Record +} + interface PresentationActivity extends BaseActivity { type: 'shared' request: { - credentials: Array<{ - id: string - disclosedAttributes: string[] - disclosedPayload: Record - }> + credentials: Array name?: string purpose?: string failureReason?: SharingFailureReason @@ -38,7 +58,7 @@ interface PresentationActivity extends BaseActivity { interface IssuanceActivity extends BaseActivity { type: 'received' - credentialIds: string[] + credentialIds: CredentialForDisplayId[] } export type Activity = PresentationActivity | IssuanceActivity @@ -72,7 +92,7 @@ export const useActivities = ({ filters }: { filters?: { entityId?: string } } = return [...record.activities] .sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime()) - .filter((activity) => activity.entity.id === filters?.entityId) + .filter((activity) => !filters?.entityId || activity.entity.id === filters?.entityId) }, [record?.activities, filters?.entityId]) return { @@ -89,7 +109,7 @@ export const addReceivedActivity = async ( host?: string logo?: DisplayImage backgroundColor?: string - credentialIds: string[] + credentialIds: CredentialForDisplayId[] } ) => { await activityStorage.addActivity(agent, { @@ -98,53 +118,74 @@ export const addReceivedActivity = async ( type: 'received', status: 'success', entity: { + id: input.entityId, name: input.name, host: input.host, logo: input.logo, backgroundColor: input.backgroundColor, }, credentialIds: input.credentialIds, - } as IssuanceActivity) + }) } export const addSharedActivity = async ( agent: EasyPIDAppAgent, - input: { - status: ActivityStatus - entity: { - id: string - host: string - name?: string - logo?: DisplayImage - } - request: { - credentials: Array<{ - id: string - disclosedAttributes: string[] - disclosedPayload: Record - }> - name?: string - purpose?: string - failureReason?: SharingFailureReason - } - } + input: Omit ) => { await activityStorage.addActivity(agent, { + ...input, id: utils.uuid(), date: new Date().toISOString(), type: 'shared', - status: input.status, + }) +} + +export function addSharedActivityForCredentialsForRequest( + agent: AppAgent, + credentialsForRequest: Pick, + status: ActivityStatus +) { + return addSharedActivity(agent, { + status, entity: { - id: input.entity.id, - name: input.entity.name, - host: input.entity.host, - logo: input.entity.logo, + id: credentialsForRequest.verifier.entityId, + host: credentialsForRequest.verifier.hostName, + name: credentialsForRequest?.verifier.name, + logo: credentialsForRequest.verifier.logo, }, request: { - name: input.request.name, - purpose: input.request.purpose, - credentials: input.request.credentials, - failureReason: input.request.failureReason, + name: credentialsForRequest.formattedSubmission.name, + purpose: credentialsForRequest.formattedSubmission.purpose, + credentials: getDisclosedCredentialForSubmission(credentialsForRequest.formattedSubmission), + failureReason: + status === 'failed' + ? !credentialsForRequest.formattedSubmission.areAllSatisfied + ? 'missing_credentials' + : 'unknown' + : undefined, }, - } as PresentationActivity) + }) +} + +export function getDisclosedCredentialForSubmission( + formattedSubmission: FormattedSubmission +): Array { + return formattedSubmission.entries.map((entry) => { + if (!entry.isSatisfied) { + return { + name: entry.name, + attributeNames: getUnsatisfiedAttributePathsForDisplay(entry.requestedAttributePaths), + } satisfies PresentationActivityCredentialNotFound + } + + // TODO: once we support selection we should update [0] to the selected credential + const credential = entry.credentials[0] + + return { + id: credential.credential.id, + attributeNames: getDisclosedAttributeNamesForDisplay(credential), + attributes: credential.disclosed.attributes, + metadata: credential.disclosed.metadata as unknown as Record, + } satisfies PresentationActivityCredential + }) } diff --git a/apps/easypid/src/features/menu/FunkeMenuScreen.tsx b/apps/easypid/src/features/menu/FunkeMenuScreen.tsx index a89e75a6..eec3269a 100644 --- a/apps/easypid/src/features/menu/FunkeMenuScreen.tsx +++ b/apps/easypid/src/features/menu/FunkeMenuScreen.tsx @@ -36,13 +36,13 @@ const menuItems = [ export function FunkeMenuScreen() { const { handleScroll, isScrolledByOffset, scrollEventThrottle } = useScrollViewPosition() const onResetWallet = useWalletReset() - const { pidCredentialForDisplay } = usePidCredential() + const { credential } = usePidCredential() - const idItem = pidCredentialForDisplay ? ( + const idItem = credential ? ( () const [receivePidUseCaseState, setReceivePidUseCaseState] = useState() @@ -211,6 +212,11 @@ export function OnboardingContextProvider({ const isSimulatorPinCode = pin === SIMULATOR_PIN if (isSimulatorPinCode) { + toast.show('Simulator eID card activated', { + customData: { + preset: 'success', + }, + }) setAllowSimulatorCard(true) } else if (!walletPin || walletPin !== pin) { toast.show('Pin entries do not match', { @@ -505,11 +511,15 @@ export function OnboardingContextProvider({ await new Promise((resolve) => setTimeout(resolve, 1000)) setIdCardScanningState((state) => ({ ...state, showScanModal: false })) await new Promise((resolve) => setTimeout(resolve, Platform.OS === 'android' ? 500 : 1000)) - setCurrentStepName('id-card-fetch') + + setCurrentStepName(shouldUseCloudHsm ? 'id-card-fetch' : 'id-card-verify') // Acquire access token await receivePidUseCase.acquireAccessToken() - setCurrentStepName('id-card-verify') + + if (shouldUseCloudHsm) { + await retrieveCredential() + } } catch (error) { await reset({ resetToStep: 'id-card-pin', error }) } @@ -547,13 +557,14 @@ export function OnboardingContextProvider({ )}` ) + const { display } = getCredentialForDisplay(credential) await addReceivedActivity(secureUnlock.context.agent, { entityId: receivePidUseCase.resolvedCredentialOffer.credentialOfferPayload.credential_issuer, host: getHostNameFromUrl(parsed.prettyClaims.iss) as string, - name: pidDisplay?.issuer.name, - logo: pidDisplay?.issuer.logo, + name: display.issuer.name, + logo: display.issuer.logo, backgroundColor: '#ffffff', // PID Logo needs white background - credentialIds: [credential.id], + credentialIds: [getCredentialForDisplayId(credential)], }) } } @@ -581,7 +592,9 @@ export function OnboardingContextProvider({ Linking.openSettings().then(() => setCurrentStepName('id-card-verify')) } - const onIdCardStart = async () => { + const onIdCardStart = async (shouldUseCloudHsm: boolean) => { + setShouldUseCloudHsm(shouldUseCloudHsm) + if (secureUnlock.state !== 'unlocked') { await reset({ error: 'onIdCardStart: Secure unlock state is not unlocked', @@ -628,15 +641,7 @@ export function OnboardingContextProvider({ let screen: React.JSX.Element if (currentStep.step === 'welcome') { - screen = ( - { - // TODO: make configurable - setShouldUseCloudHsm(true) - goToNextStep() - }} - /> - ) + screen = } else if (currentStep.step === 'pin' || currentStep.step === 'pin-reenter') { screen = ( @@ -27,13 +25,11 @@ export function OnboardingIdCardRequestedAttributes({ These {requestedAttributes.length} attributes will be read from your eID card. sanitizeString(a))} - disableNavigation + issuerImage={{ url: bdrPidIssuerDisplay.logo }} + backgroundImage={{ url: bdrPidCredentialDisplay.backgroundImage }} + backgroundColor={bdrPidCredentialDisplay.backgroundColor} + formattedDisclosedAttributes={requestedAttributes.map((a) => sanitizeString(a))} /> diff --git a/apps/easypid/src/features/onboarding/screens/id-card-start.tsx b/apps/easypid/src/features/onboarding/screens/id-card-start.tsx index 00eef092..ed467cee 100644 --- a/apps/easypid/src/features/onboarding/screens/id-card-start.tsx +++ b/apps/easypid/src/features/onboarding/screens/id-card-start.tsx @@ -1,15 +1,47 @@ -import { Button, HeroIcons, IdCardImage, ScrollView, Spinner, YStack } from '@package/ui' +import { Button, HeroIcons, IdCardImage, ScrollView, Spinner, XStack, YStack, useToastController } from '@package/ui' import { IllustrationContainer } from '@package/ui' import { useState } from 'react' +import { Platform } from 'react-native' +import { useCanUseSecureEnclave } from '../../../hooks/useCanUseSecureEnclave' interface OnboardingIdCardStartScanProps { - goToNextStep: () => Promise + goToNextStep: (shouldUseCloudHsm: boolean) => Promise onSkipCardSetup?: () => void } export function OnboardingIdCardStart({ goToNextStep, onSkipCardSetup }: OnboardingIdCardStartScanProps) { const [isLoading, setIsLoading] = useState(false) + const canUseSecureEnclave = useCanUseSecureEnclave() + const [shouldUseCloudHsm, setShouldUseCloudHsm] = useState(true) + const toast = useToastController() + + const onToggleCloudHsm = () => { + const newShouldUseCloudHsm = !shouldUseCloudHsm + + if (newShouldUseCloudHsm === false && !canUseSecureEnclave) { + toast.show(`You device does not support on-device ${Platform.OS === 'ios' ? 'Secure Enclave' : 'Strongbox'}.`, { + message: 'Only Cloud HSM supported for PID cryptogrpahic keys.', + customData: { + preset: 'danger', + }, + }) + return + } + + toast.show( + newShouldUseCloudHsm + ? 'Now using Cloud HSM for PID cryptographic keys.' + : `Now using ${Platform.OS === 'ios' ? 'Secure Enclave' : 'Strongbox'} for PID cryptographic keys.`, + { + customData: { + preset: 'none', + }, + } + ) + + setShouldUseCloudHsm(newShouldUseCloudHsm) + } const onSetupLater = () => { if (isLoading || !onSkipCardSetup) return @@ -23,7 +55,7 @@ export function OnboardingIdCardStart({ goToNextStep, onSkipCardSetup }: Onboard if (isLoading) return setIsLoading(true) - goToNextStep().finally(() => setIsLoading(false)) + goToNextStep(shouldUseCloudHsm).finally(() => setIsLoading(false)) } return ( @@ -43,9 +75,14 @@ export function OnboardingIdCardStart({ goToNextStep, onSkipCardSetup }: Onboard Set up later )} - - {isLoading ? : 'Continue'} - + + + {shouldUseCloudHsm ? : } + + + {isLoading ? : 'Continue'} + + ) diff --git a/apps/easypid/src/features/onboarding/screens/welcome.tsx b/apps/easypid/src/features/onboarding/screens/welcome.tsx index acfdebc6..1be8bc36 100644 --- a/apps/easypid/src/features/onboarding/screens/welcome.tsx +++ b/apps/easypid/src/features/onboarding/screens/welcome.tsx @@ -13,7 +13,7 @@ import { } from '@package/ui' import { Image } from '@tamagui/image' import type React from 'react' -import { Alert } from 'react-native' +import { Alert, Platform } from 'react-native' import Animated, { FadingTransition } from 'react-native-reanimated' import inAppLogo from '../../../../assets/icon.png' @@ -56,7 +56,7 @@ export default function OnboardingWelcome({ goToNextStep }: OnboardingWelcomePro onPress={() => { Alert.alert( 'This is the EasyPID wallet', - `\nThis is your digital wallet. With it, you can store and share information about yourself. \n\n You can switch between the C and B' flow by pressing the grey button in the bottom left.` + '\nThis is your digital wallet. With it, you can store and share information about yourself.' ) }} /> diff --git a/apps/easypid/src/features/onboarding/useShouldUseCloudHsm.ts b/apps/easypid/src/features/onboarding/useShouldUseCloudHsm.ts index b625b45e..8de371a2 100644 --- a/apps/easypid/src/features/onboarding/useShouldUseCloudHsm.ts +++ b/apps/easypid/src/features/onboarding/useShouldUseCloudHsm.ts @@ -1,3 +1,5 @@ +import { shouldUseFallbackSecureEnvironment } from '@animo-id/expo-secure-environment' +import { useCallback } from 'react' import { useMMKVBoolean } from 'react-native-mmkv' import { mmkv } from '../../storage/mmkv' @@ -6,7 +8,17 @@ export function getShouldUseCloudHsm() { } export function useShouldUseCloudHsm() { - return useMMKVBoolean('shouldUseCloudHsm', mmkv) + const [shouldUseCloudHsm, _setShouldUseCloudHsm] = useMMKVBoolean('shouldUseCloudHsm', mmkv) + + const setShouldUseCloudHsm = useCallback( + (shouldUseCloudHsm: boolean) => { + _setShouldUseCloudHsm(shouldUseCloudHsm) + shouldUseFallbackSecureEnvironment(shouldUseCloudHsm) + }, + [_setShouldUseCloudHsm] + ) + + return [shouldUseCloudHsm, setShouldUseCloudHsm] as const } export function removeShouldUseCloudHsm() { mmkv.delete('shouldUseCloudHsm') diff --git a/apps/easypid/src/features/pid/FunkePidSetupScreen.tsx b/apps/easypid/src/features/pid/FunkePidSetupScreen.tsx index 47d0a5c5..f625698e 100644 --- a/apps/easypid/src/features/pid/FunkePidSetupScreen.tsx +++ b/apps/easypid/src/features/pid/FunkePidSetupScreen.tsx @@ -1,7 +1,7 @@ import { sendCommand } from '@animo-id/expo-ausweis-sdk' import { type SdJwtVcHeader, SdJwtVcRecord } from '@credo-ts/core' import { useSecureUnlock } from '@easypid/agent' -import { type PidSdJwtVcAttributes, usePidDisplay } from '@easypid/hooks' +import type { PidSdJwtVcAttributes } from '@easypid/hooks' import { ReceivePidUseCaseCFlow } from '@easypid/use-cases/ReceivePidUseCaseCFlow' import type { CardScanningErrorDetails, @@ -9,17 +9,25 @@ import type { ReceivePidUseCaseState, } from '@easypid/use-cases/ReceivePidUseCaseFlow' import { type CardScanningState, SIMULATOR_PIN, getPidSetupSlideContent } from '@easypid/utils/sharedPidSetup' -import { SlideWizard, usePushToWallet } from '@package/app' -import { BiometricAuthenticationCancelledError, BiometricAuthenticationNotEnabledError } from 'packages/agent/src' +import { SlideWizard, type SlideWizardRef, usePushToWallet } from '@package/app' +import { + BiometricAuthenticationCancelledError, + BiometricAuthenticationNotEnabledError, + getCredentialForDisplay, + getCredentialForDisplayId, +} from 'packages/agent/src' import { useToastController } from 'packages/ui/src' import { capitalizeFirstLetter, getHostNameFromUrl, sleep } from 'packages/utils/src' import type React from 'react' import { useCallback, useEffect, useRef, useState } from 'react' import { Platform } from 'react-native' +import { setWalletServiceProviderPin } from '../../crypto/WalletServiceProviderClient' import { addReceivedActivity } from '../activity/activityRecord' +import { useShouldUseCloudHsm } from '../onboarding/useShouldUseCloudHsm' import { PidCardScanSlide } from './PidCardScanSlide' import { PidIdCardFetchSlide } from './PidEidCardFetchSlide' import { PidEidCardPinSlide } from './PidEidCardPinSlide' +import { PidIdCardVerifySlide } from './PidEidCardVerifySlide' import { PidReviewRequestSlide } from './PidReviewRequestSlide' import { PidSetupStartSlide } from './PidSetupStartSlide' import { PidWalletPinSlide } from './PidWalletPinSlide' @@ -28,7 +36,6 @@ export function FunkePidSetupScreen() { const toast = useToastController() const pushToWallet = usePushToWallet() const secureUnlock = useSecureUnlock() - const pidDisplay = usePidDisplay() const [idCardPin, setIdCardPin] = useState() const [receivePidUseCase, setReceivePidUseCase] = useState() @@ -43,6 +50,9 @@ export function FunkePidSetupScreen() { const [onIdCardPinReEnter, setOnIdCardPinReEnter] = useState<(idCardPin: string) => Promise>() const [userName, setUserName] = useState() const [isScanning, setIsScanning] = useState(false) + const [allowSimulatorCard, setAllowSimulatorCard] = useState(false) + const [shouldUseCloudHsm, setShouldUseCloudHsm] = useShouldUseCloudHsm() + const slideWizardRef = useRef(null) const onEnterPin: ReceivePidUseCaseFlowOptions['onEnterPin'] = useCallback( (options) => { @@ -166,10 +176,26 @@ export function FunkePidSetupScreen() { // setWalletPin(pin) // }) + // If pin is simulator pin we require the user to retry so that second time + // they can set the real pin const isSimulatorPinCode = pin === SIMULATOR_PIN - await onIdCardStart({ walletPin: pin, allowSimulatorCard: isSimulatorPinCode }) + if (isSimulatorPinCode) { + toast.show('Simulator eID card activated', { + message: 'Enter your real PIN to continue', + customData: { + preset: 'success', + }, + }) + setAllowSimulatorCard(true) + throw new Error('Retry') + } + + if (shouldUseCloudHsm) setWalletServiceProviderPin(pin.split('').map(Number)) + await onIdCardStart({ walletPin: pin, allowSimulatorCard: allowSimulatorCard }) } + const onStart = (shouldUseCloudHsm: boolean) => setShouldUseCloudHsm(shouldUseCloudHsm) + const onIdCardPinEnter = (pin: string) => setIdCardPin(pin) const onStartScanning = async () => { @@ -224,14 +250,6 @@ export function FunkePidSetupScreen() { return } - } - - const onScanningComplete = async () => { - if (!receivePidUseCase) { - toast.show('Not ready to receive PID', { customData: { preset: 'danger' } }) - pushToWallet() - return - } try { setIdCardScanningState((state) => ({ @@ -249,7 +267,11 @@ export function FunkePidSetupScreen() { // Acquire access token await receivePidUseCase.acquireAccessToken() - await retrieveCredential() + slideWizardRef.current?.goToNextSlide() + // If not using cloud hsm we first want approval from the user + if (shouldUseCloudHsm) { + await retrieveCredential() + } } catch (error) { toast.show('Something went wrong', { customData: { @@ -275,7 +297,6 @@ export function FunkePidSetupScreen() { try { // Retrieve Credential - const credentials = await receivePidUseCase.retrieveCredentials() for (const credential of credentials) { @@ -289,14 +310,15 @@ export function FunkePidSetupScreen() { )}` ) + const { display } = getCredentialForDisplay(credential) await addReceivedActivity(secureUnlock.context.agent, { // TODO: should host be entityId or the iss? entityId: receivePidUseCase.resolvedCredentialOffer.credentialOfferPayload.credential_issuer, host: getHostNameFromUrl(parsed.prettyClaims.iss) as string, - name: pidDisplay?.issuer.name, - logo: pidDisplay?.issuer.logo, + name: display.issuer.name, + logo: display.issuer.logo, backgroundColor: '#ffffff', // PID Logo needs white background - credentialIds: [credential.id], + credentialIds: [getCredentialForDisplayId(credential)], }) } } @@ -324,11 +346,12 @@ export function FunkePidSetupScreen() { return ( , + screen: , }, { step: 'id-card-pin', @@ -382,20 +405,32 @@ export function FunkePidSetupScreen() { /> ), }, + !shouldUseCloudHsm + ? { + step: 'id-card-verify', + progress: 80, + backIsCancel: true, + screen: ( + + ), + } + : undefined, { step: 'id-card-fetch', - progress: 80, + progress: 90, backIsCancel: true, screen: ( pushToWallet('replace')} /> ), }, - ]} + ].filter((s): s is NonNullable => s !== undefined)} confirmation={{ title: 'Stop ID Setup?', description: 'If you stop, you can do the setup later.', diff --git a/apps/easypid/src/features/pid/PidCardScanSlide.tsx b/apps/easypid/src/features/pid/PidCardScanSlide.tsx index f9018bad..f91764a2 100644 --- a/apps/easypid/src/features/pid/PidCardScanSlide.tsx +++ b/apps/easypid/src/features/pid/PidCardScanSlide.tsx @@ -16,9 +16,7 @@ export function PidCardScanSlide({ title, subtitle, onStartScanning, ...props }: if (isLoading) return setIsLoading(true) - await onStartScanning?.().then(() => { - onNext() - }) + await onStartScanning?.() setIsLoading(false) } diff --git a/apps/easypid/src/features/pid/PidEidCardFetchSlide.tsx b/apps/easypid/src/features/pid/PidEidCardFetchSlide.tsx index 591b44aa..5fc2853f 100644 --- a/apps/easypid/src/features/pid/PidEidCardFetchSlide.tsx +++ b/apps/easypid/src/features/pid/PidEidCardFetchSlide.tsx @@ -7,18 +7,11 @@ interface PidIdCardFetchSlideProps { title: string subtitle?: string userName?: string - onFetch: () => void onComplete: () => void } -export function PidIdCardFetchSlide({ title, subtitle, userName, onFetch, onComplete }: PidIdCardFetchSlideProps) { +export function PidIdCardFetchSlide({ title, subtitle, userName, onComplete }: PidIdCardFetchSlideProps) { const { completeProgressBar } = useWizard() - // biome-ignore lint/correctness/useExhaustiveDependencies: We fetch when this slide is mounted - useEffect(() => { - // We can't navigate to the next step from the SlideWizard, so we start the fetching of the credential - // when this slide is mounted. - void onFetch() - }, []) useEffect(() => { if (userName) { diff --git a/apps/easypid/src/features/pid/PidEidCardVerifySlide.tsx b/apps/easypid/src/features/pid/PidEidCardVerifySlide.tsx new file mode 100644 index 00000000..ba7c033b --- /dev/null +++ b/apps/easypid/src/features/pid/PidEidCardVerifySlide.tsx @@ -0,0 +1,20 @@ +import { Heading, Paragraph, YStack } from '@package/ui' +import { OnboardingIdCardVerify } from '../onboarding/screens/id-card-verify' + +interface PidIdCardVerifySlideProps { + onVerifyWithBiometrics: () => Promise + title: string + subtitle?: string +} + +export function PidIdCardVerifySlide({ onVerifyWithBiometrics, subtitle, title }: PidIdCardVerifySlideProps) { + return ( + + + {title} + {subtitle && {subtitle}} + + + + ) +} diff --git a/apps/easypid/src/features/pid/PidSetupStartSlide.tsx b/apps/easypid/src/features/pid/PidSetupStartSlide.tsx index a594db9e..74dc46c1 100644 --- a/apps/easypid/src/features/pid/PidSetupStartSlide.tsx +++ b/apps/easypid/src/features/pid/PidSetupStartSlide.tsx @@ -6,9 +6,10 @@ interface PidSetupStartSlideProps { title: string subtitle?: string caption?: string + onStart: (useShouldUseCloudHsm: boolean) => void } -export function PidSetupStartSlide({ title, subtitle, caption }: PidSetupStartSlideProps) { +export function PidSetupStartSlide({ title, subtitle, caption, onStart }: PidSetupStartSlideProps) { const { onNext } = useWizard() return ( @@ -25,7 +26,12 @@ export function PidSetupStartSlide({ title, subtitle, caption }: PidSetupStartSl - onNext()} /> + { + onNext() + onStart(shouldUseCloudHsm) + }} + /> ) diff --git a/apps/easypid/src/features/pid/PidWalletPinSlide.tsx b/apps/easypid/src/features/pid/PidWalletPinSlide.tsx index c7a14fb5..04c57135 100644 --- a/apps/easypid/src/features/pid/PidWalletPinSlide.tsx +++ b/apps/easypid/src/features/pid/PidWalletPinSlide.tsx @@ -17,9 +17,14 @@ export function PidWalletPinSlide({ title, subtitle, onEnterPin }: PidWalletPinS if (isLoading) return setIsLoading(true) - await onEnterPin(pin).then(() => { - onNext() - }) + await onEnterPin(pin) + .then(() => { + onNext() + }) + .catch(() => { + ref.current?.shake() + ref.current?.clear() + }) setIsLoading(false) } diff --git a/apps/easypid/src/features/pid/WithBackPidRefresh.tsx b/apps/easypid/src/features/pid/WithBackPidRefresh.tsx index 222d0b72..ff00fcaa 100644 --- a/apps/easypid/src/features/pid/WithBackPidRefresh.tsx +++ b/apps/easypid/src/features/pid/WithBackPidRefresh.tsx @@ -3,7 +3,7 @@ import { useBackgroundPidRefresh } from '../../hooks/useBackgroundPidRefresh' export function WithBackgroundPidRefresh({ children }: PropsWithChildren) { // Refresh PID once it reaches 1 - useBackgroundPidRefresh(1) + // useBackgroundPidRefresh(1) return children } diff --git a/apps/easypid/src/features/proximity/mdocProximity.ts b/apps/easypid/src/features/proximity/mdocProximity.ts index 7ecd249c..7ef4869a 100644 --- a/apps/easypid/src/features/proximity/mdocProximity.ts +++ b/apps/easypid/src/features/proximity/mdocProximity.ts @@ -2,13 +2,14 @@ import { mdocDataTransfer } from '@animo-id/expo-mdoc-data-transfer' import { COSEKey, DeviceRequest, DeviceResponse, MDoc, type MdocContext, parseIssuerSigned } from '@animo-id/mdoc' import { TypedArrayEncoder } from '@credo-ts/core' import { getMdocContext } from '@credo-ts/core/build/modules/mdoc/MdocContext' -import type { EasyPIDAppAgent } from '@package/agent' +import type { EasyPIDAppAgent, FormattedSubmission, MdocRecord } from '@package/agent' import { type Permission, PermissionsAndroid, Platform } from 'react-native' type ShareDeviceResponseOptions = { sessionTranscript: Uint8Array deviceRequest: Uint8Array agent: EasyPIDAppAgent + submission: FormattedSubmission } const PERMISSIONS = [ @@ -49,9 +50,8 @@ export const waitForDeviceRequest = async () => { const mdt = mdocDataTransfer.instance() const { deviceRequest, sessionTranscript } = await mdt.waitForDeviceRequest() const decodedDeviceRequest = DeviceRequest.parse(deviceRequest) - const requestedItems = decodedDeviceRequest.docRequests.map((d) => d.itemsRequest.data.nameSpaces) - return { deviceRequest, sessionTranscript, requestedItems } + return { deviceRequest, sessionTranscript } } /** @@ -65,10 +65,15 @@ export const waitForDeviceRequest = async () => { * */ export const shareDeviceResponse = async (options: ShareDeviceResponseOptions) => { - const mdocs = await options.agent.mdoc.getAll() - const issuerSignedDocuments = mdocs.map((mdoc) => { - const docType = mdoc.getTag('DocType') as string - return parseIssuerSigned(TypedArrayEncoder.fromBase64(mdoc.base64Url), docType) + if (!options.submission.areAllSatisfied) { + throw new Error('Not all requirements are satisfied') + } + + const issuerSignedDocuments = options.submission.entries.map((e) => { + if (!e.isSatisfied) throw new Error(`Requirement for doctype ${e.inputDescriptorId} not satisfied`) + + const credential = e.credentials[0].credential.record as MdocRecord + return parseIssuerSigned(TypedArrayEncoder.fromBase64(credential.base64Url), credential.getTags().docType) }) const mdoc = new MDoc(issuerSignedDocuments) @@ -80,6 +85,9 @@ export const shareDeviceResponse = async (options: ShareDeviceResponseOptions) = const mdt = mdocDataTransfer.instance() + if (mdoc.documents.length > 0) { + throw new Error('Only one mdoc supported at the moment due to only bein able to sign with one device key') + } const mso = mdoc.documents[0].issuerSigned.issuerAuth.decodedPayload const deviceKeyInfo = mso.deviceKeyInfo if (!deviceKeyInfo?.deviceKey) { @@ -87,7 +95,6 @@ export const shareDeviceResponse = async (options: ShareDeviceResponseOptions) = } const publicDeviceJwk = COSEKey.import(deviceKeyInfo.deviceKey).toJWK() - const deviceRequest = DeviceRequest.parse(options.deviceRequest) const deviceResponse = await DeviceResponse.from(mdoc) diff --git a/apps/easypid/src/features/receive/FunkeCredentialNotificationScreen.tsx b/apps/easypid/src/features/receive/FunkeCredentialNotificationScreen.tsx index 9ee25a63..a41d0cb8 100644 --- a/apps/easypid/src/features/receive/FunkeCredentialNotificationScreen.tsx +++ b/apps/easypid/src/features/receive/FunkeCredentialNotificationScreen.tsx @@ -14,6 +14,7 @@ import { extractOpenId4VcCredentialMetadata, getCredentialDisplayWithDefaults, getCredentialForDisplay, + getCredentialForDisplayId, getCredentialsForProofRequest, getOpenId4VcCredentialDisplay, receiveCredentialFromOpenId4VciOffer, @@ -25,9 +26,13 @@ import { import { useAppAgent } from '@easypid/agent' import { SlideWizard, usePushToWallet } from '@package/app' +import { useToastController } from '@package/ui' import { useCallback, useEffect, useState } from 'react' import { createParam } from 'solito' +import { setWalletServiceProviderPin } from '../../crypto/WalletServiceProviderClient' +import { useShouldUsePinForSubmission } from '../../hooks/useShouldUsePinForPresentation' import { addReceivedActivity, useActivities } from '../activity/activityRecord' +import { PinSlide } from '../share/slides/PinSlide' import { ShareCredentialsSlide } from '../share/slides/ShareCredentialsSlide' import { AuthCodeFlowSlide } from './slides/AuthCodeFlowSlide' import { CredentialCardSlide } from './slides/CredentialCardSlide' @@ -50,6 +55,7 @@ const { useParams } = createParam() export function FunkeCredentialNotificationScreen() { const { agent } = useAppAgent() const { params } = useParams() + const toast = useToastController() const pushToWallet = usePushToWallet() @@ -85,6 +91,7 @@ export function FunkeCredentialNotificationScreen() { : {} ) + const shouldUsePinForPresentation = useShouldUsePinForSubmission(credentialsForRequest) const preAuthGrant = resolvedCredentialOffer?.credentialOfferPayload.grants?.['urn:ietf:params:oauth:grant-type:pre-authorized_code'] const txCode = preAuthGrant?.tx_code @@ -132,6 +139,12 @@ export function FunkeCredentialNotificationScreen() { [agent] ) + // TODO: Should we add this to the activitiy? We also don't do it for issuance + const onProofDecline = async () => { + toast.show('Information request has been declined.', { customData: { preset: 'danger' } }) + pushToWallet('back') + } + const onCompleteCredentialRetrieval = async () => { if (!receivedRecord) return @@ -141,9 +154,9 @@ export function FunkeCredentialNotificationScreen() { entityId: resolvedCredentialOffer?.metadata.credentialIssuer.credential_issuer as string, host: credentialDisplay.issuer.domain, name: credentialDisplay.issuer.name, - logo: credentialDisplay.issuer.logo ? credentialDisplay.issuer.logo : undefined, + logo: credentialDisplay.issuer.logo, backgroundColor: '#ffffff', // Default to a white background for now - credentialIds: [receivedRecord.id], + credentialIds: [getCredentialForDisplayId(receivedRecord)], }) setIsCompleted(true) @@ -234,51 +247,70 @@ export function FunkeCredentialNotificationScreen() { [acquireCredentialsPreAuth] ) - const onPresentationAccept = useCallback(async () => { - if ( - !credentialsForRequest || - !resolvedCredentialOffer || - !resolvedAuthorizationRequest || - resolvedAuthorizationRequest.authorizationFlow !== OpenId4VciAuthorizationFlow.PresentationDuringIssuance - ) { - setErrorReason('Presentation information could not be extracted.') - return - } + const onPresentationAccept = useCallback( + async (pin?: string) => { + if ( + !credentialsForRequest || + !resolvedCredentialOffer || + !resolvedAuthorizationRequest || + resolvedAuthorizationRequest.authorizationFlow !== OpenId4VciAuthorizationFlow.PresentationDuringIssuance + ) { + setErrorReason('Presentation information could not be extracted.') + return + } - setIsSharingPresentation(true) + setIsSharingPresentation(true) - try { - const { presentationDuringIssuanceSession } = await shareProof({ - agent, - authorizationRequest: credentialsForRequest.authorizationRequest, - credentialsForRequest: credentialsForRequest.credentialsForRequest, - selectedCredentials: {}, - allowUntrustedCertificate: true, - }) + if (shouldUsePinForPresentation) { + // TODO: we should handle invalid pin + if (!pin) { + setErrorReason('Presentation information could not be extracted.') + return + } + // TODO: maybe provide to shareProof method? + setWalletServiceProviderPin(pin.split('').map(Number)) + } - const { authorizationCode } = await acquireAuthorizationCodeUsingPresentation({ - resolvedCredentialOffer, - authSession: resolvedAuthorizationRequest.authSession, - presentationDuringIssuanceSession, - agent, - }) + try { + const { presentationDuringIssuanceSession } = await shareProof({ + agent, + resolvedRequest: credentialsForRequest, + selectedCredentials: {}, + allowUntrustedCertificate: true, + }) - await acquireCredentialsAuth(authorizationCode) + const { authorizationCode } = await acquireAuthorizationCodeUsingPresentation({ + resolvedCredentialOffer, + authSession: resolvedAuthorizationRequest.authSession, + presentationDuringIssuanceSession, + agent, + }) - setIsSharingPresentation(false) - } catch (error) { - setIsSharingPresentation(false) - if (error instanceof BiometricAuthenticationCancelledError) { - setErrorReason('Biometric authentication cancelled') - return - } + await acquireCredentialsAuth(authorizationCode) - agent.config.logger.error('Error accepting presentation', { - error, - }) - setErrorReason('Presentation could not be shared.') - } - }, [credentialsForRequest, agent, acquireCredentialsAuth, resolvedAuthorizationRequest, resolvedCredentialOffer]) + setIsSharingPresentation(false) + } catch (error) { + setIsSharingPresentation(false) + if (error instanceof BiometricAuthenticationCancelledError) { + setErrorReason('Biometric authentication cancelled') + return + } + + agent.config.logger.error('Error accepting presentation', { + error, + }) + setErrorReason('Presentation could not be shared.') + } + }, + [ + credentialsForRequest, + agent, + acquireCredentialsAuth, + resolvedAuthorizationRequest, + resolvedCredentialOffer, + shouldUsePinForPresentation, + ] + ) const onCancel = () => pushToWallet('back') const onGoToWallet = () => pushToWallet('replace') @@ -364,8 +396,8 @@ export function FunkeCredentialNotificationScreen() { screen: ( + ), + } + : undefined, isPreAuthWithTxFlow ? { step: 'tx-code', diff --git a/apps/easypid/src/features/scan/FunkeQrScannerScreen.tsx b/apps/easypid/src/features/scan/FunkeQrScannerScreen.tsx index 317df46c..8b09e81b 100644 --- a/apps/easypid/src/features/scan/FunkeQrScannerScreen.tsx +++ b/apps/easypid/src/features/scan/FunkeQrScannerScreen.tsx @@ -21,7 +21,6 @@ import { Alert, Linking, Platform, useWindowDimensions } from 'react-native' import { FadeIn, FadeOut, LinearTransition, useAnimatedStyle, withTiming } from 'react-native-reanimated' import { useSafeAreaInsets } from 'react-native-safe-area-context' -import { pidSchemes } from '@easypid/constants' import easypidLogo from '../../../assets/easypid.png' import { checkMdocPermissions, getMdocQrCode, requestMdocPermissions, waitForDeviceRequest } from '../proximity' @@ -225,16 +224,9 @@ function FunkeQrOverlay({ qrCodeData }: { qrCodeData?: string }) { if (qrCodeData) { void waitForDeviceRequest().then((data) => { if (data) { - // Take the Doc item that matches with the mdoc pid type - // Only support one doc item for now - - const requestedNamespace = data.requestedItems[0][pidSchemes.msoMdocDoctypes[0]] - if (!requestedNamespace) throw new Error('Unsupported credential requested.') - pushToOfflinePresentation({ sessionTranscript: Buffer.from(data.sessionTranscript).toString('base64'), deviceRequest: Buffer.from(data.deviceRequest).toString('base64'), - requestedAttributes: Object.entries(requestedNamespace).map(([key]) => key), }) return } @@ -243,15 +235,11 @@ function FunkeQrOverlay({ qrCodeData }: { qrCodeData?: string }) { }, [qrCodeData]) // Navigate to offline presentation route - const pushToOfflinePresentation = withHaptics( - (data: { sessionTranscript: string; deviceRequest: string; requestedAttributes: string[] }) => - replace({ - pathname: '/notifications/offlinePresentation', - params: { - ...data, - requestedAttributes: JSON.stringify(data.requestedAttributes), // Add this change - }, - }) + const pushToOfflinePresentation = withHaptics((data: { sessionTranscript: string; deviceRequest: string }) => + replace({ + pathname: '/notifications/offlinePresentation', + params: data, + }) ) return ( diff --git a/apps/easypid/src/features/share/FunkeMdocOfflineSharingScreen.tsx b/apps/easypid/src/features/share/FunkeMdocOfflineSharingScreen.tsx index 5f854513..68d4dcda 100644 --- a/apps/easypid/src/features/share/FunkeMdocOfflineSharingScreen.tsx +++ b/apps/easypid/src/features/share/FunkeMdocOfflineSharingScreen.tsx @@ -1,10 +1,14 @@ -import { ClaimFormat, utils } from '@credo-ts/core' +import { utils } from '@credo-ts/core' import { useAppAgent } from '@easypid/agent' -import { usePidCredential } from '@easypid/hooks' +import { type FormattedSubmission, getSubmissionForMdocDocumentRequest } from '@package/agent' import { usePushToWallet } from '@package/app/src/hooks/usePushToWallet' import { useToastController } from '@package/ui' -import { useMemo, useState } from 'react' -import { type ActivityStatus, addSharedActivity } from '../activity/activityRecord' +import { useEffect, useState } from 'react' +import { + type ActivityStatus, + addSharedActivity, + addSharedActivityForCredentialsForRequest, +} from '../activity/activityRecord' import { shareDeviceResponse } from '../proximity' import { FunkeOfflineSharingScreen } from './FunkeOfflineSharingScreen' import type { PresentationRequestResult } from './components/utils' @@ -12,67 +16,45 @@ import type { PresentationRequestResult } from './components/utils' type FunkeMdocOfflineSharingScreenProps = { sessionTranscript: Uint8Array deviceRequest: Uint8Array - requestedAttributes: string[] } // Entry point for offline sharing with Mdoc export function FunkeMdocOfflineSharingScreen({ sessionTranscript, deviceRequest, - requestedAttributes, }: FunkeMdocOfflineSharingScreenProps) { const toast = useToastController() const pushToWallet = usePushToWallet() const { agent } = useAppAgent() - const { credentials } = usePidCredential() - const mdocPidCredential = credentials?.find((cred) => cred.claimFormat === ClaimFormat.MsoMdoc) + const [submission, setSubmission] = useState() const [isProcessing, setIsProcessing] = useState(false) - const disclosedPayloadForDisplay = useMemo( - () => - requestedAttributes - ? requestedAttributes?.reduce( - (acc, attr) => ({ - ...acc, - [attr]: mdocPidCredential?.attributes[attr], - }), - {} - ) - : {}, - [mdocPidCredential, requestedAttributes] - ) - - const submission = useMemo(() => { - if (!mdocPidCredential || !requestedAttributes || !disclosedPayloadForDisplay) return - - return { - name: 'PID Request', - areAllSatisfied: true, - entries: [ - { - inputDescriptorId: '123', - isSatisfied: true, - name: 'PID Request', - credentials: [ - { - id: mdocPidCredential?.id, - credentialName: mdocPidCredential?.display.name, - issuerName: mdocPidCredential?.display.issuer.name, - issuerImage: mdocPidCredential?.display.issuer.logo, - requestedAttributes: requestedAttributes, - disclosedPayload: disclosedPayloadForDisplay, - claimFormat: ClaimFormat.MsoMdoc, - metadata: mdocPidCredential?.metadata, - backgroundColor: mdocPidCredential?.display.backgroundColor, - textColor: mdocPidCredential?.display.textColor, - backgroundImage: mdocPidCredential?.display.backgroundImage, - }, - ], - }, - ], - } - }, [mdocPidCredential, requestedAttributes, disclosedPayloadForDisplay]) + useEffect(() => { + getSubmissionForMdocDocumentRequest(agent, deviceRequest) + .then((submission) => { + // We can't hare multiple documents at the moment + if (submission.entries.length > 1) { + toast.show('Presentation could not be shared.', { + message: 'Multiple cards requested, but only one card can be shared in-person', + customData: { preset: 'danger' }, + }) + pushToWallet() + } else { + setSubmission(submission) + } + }) + .catch((error) => { + toast.show('Presentation information could not be extracted.', { + customData: { preset: 'danger' }, + }) + agent.config.logger.error('Error getting credentials for mdoc device request', { + error, + }) + + pushToWallet() + }) + }) const onProofAccept = async (): Promise => { if (!submission) { @@ -92,6 +74,7 @@ export function FunkeMdocOfflineSharingScreen({ agent, deviceRequest, sessionTranscript, + submission, }) } catch (error) { await addActivity('failed') @@ -127,25 +110,20 @@ export function FunkeMdocOfflineSharingScreen({ } const addActivity = async (status: ActivityStatus) => { - await addSharedActivity(agent, { - status, - entity: { - id: utils.uuid(), - name: 'Unknown party', - host: 'https://example.com', - }, - request: { - name: submission?.name as string, - credentials: [ - { - id: mdocPidCredential?.id as string, - disclosedAttributes: requestedAttributes, - disclosedPayload: disclosedPayloadForDisplay, - }, - ], - failureReason: status === 'failed' ? 'unknown' : undefined, + if (!submission) return + await addSharedActivityForCredentialsForRequest( + agent, + { + formattedSubmission: submission, + verifier: { + entityId: '6df3d57e-4c9c-41c3-bb9f-936d88c0968d', + hostName: undefined, + logo: undefined, + name: 'Unknown party', + }, }, - }) + status + ) } // FIXME: Consider re-using the regular flow with an isOffline flag diff --git a/apps/easypid/src/features/share/FunkeOfflineSharingScreen.tsx b/apps/easypid/src/features/share/FunkeOfflineSharingScreen.tsx index c7ddc12e..cc2fd5cd 100644 --- a/apps/easypid/src/features/share/FunkeOfflineSharingScreen.tsx +++ b/apps/easypid/src/features/share/FunkeOfflineSharingScreen.tsx @@ -7,9 +7,8 @@ import { PresentationSuccessSlide } from './slides/PresentationSuccessSlide' import { ShareCredentialsSlide } from './slides/ShareCredentialsSlide' // UI Slides for offline sharing (ideally should be used for both Mdoc and SdJwt) - interface FunkeOfflineSharingScreenProps { - submission?: Record + submission?: FormattedSubmission isAccepting: boolean onAccept: () => Promise onDecline: () => void @@ -40,7 +39,7 @@ export function FunkeOfflineSharingScreen({ key="share-credentials" onAccept={undefined} // onAccept is handled in the next slide onDecline={onDecline} - submission={submission as unknown as FormattedSubmission} + submission={submission as FormattedSubmission} isAccepting={isAccepting} isOffline /> diff --git a/apps/easypid/src/features/share/FunkeOpenIdPresentationNotificationScreen.tsx b/apps/easypid/src/features/share/FunkeOpenIdPresentationNotificationScreen.tsx index 10139a08..b9c74100 100644 --- a/apps/easypid/src/features/share/FunkeOpenIdPresentationNotificationScreen.tsx +++ b/apps/easypid/src/features/share/FunkeOpenIdPresentationNotificationScreen.tsx @@ -1,4 +1,9 @@ -import { BiometricAuthenticationCancelledError, getCredentialsForProofRequest, shareProof } from '@package/agent' +import { + BiometricAuthenticationCancelledError, + type CredentialsForProofRequest, + getCredentialsForProofRequest, + shareProof, +} from '@package/agent' import { useToastController } from '@package/ui' import { useLocalSearchParams } from 'expo-router' import React, { useEffect, useState, useMemo, useCallback } from 'react' @@ -6,8 +11,9 @@ import React, { useEffect, useState, useMemo, useCallback } from 'react' import { useAppAgent } from '@easypid/agent' import { getOpenIdFedIssuerMetadata } from '@easypid/utils/issuer' import { usePushToWallet } from '@package/app/src/hooks/usePushToWallet' -import { isPidCredential } from '../../hooks' -import { addSharedActivity, useActivities } from '../activity/activityRecord' +import { setWalletServiceProviderPin } from '../../crypto/WalletServiceProviderClient' +import { useShouldUsePinForSubmission } from '../../hooks/useShouldUsePinForPresentation' +import { addSharedActivityForCredentialsForRequest, useActivities } from '../activity/activityRecord' import { FunkePresentationNotificationScreen } from './FunkePresentationNotificationScreen' import type { PresentationRequestResult } from './components/utils' @@ -19,29 +25,21 @@ export function FunkeOpenIdPresentationNotificationScreen() { const pushToWallet = usePushToWallet() const { agent } = useAppAgent() - const [credentialsForRequest, setCredentialsForRequest] = - useState>>() + const [credentialsForRequest, setCredentialsForRequest] = useState() const [isSharing, setIsSharing] = useState(false) const { activities } = useActivities({ filters: { entityId: credentialsForRequest?.verifier.entityId ?? 'NO MATCH' }, }) + const shouldUsePin = useShouldUsePinForSubmission(credentialsForRequest) // TODO: this should be returnd by getCredentialsForProofRequest + // TODO: addSharedActivityForCredentialsForRequest should take into account fed display metadata const fedDisplayData = useMemo( () => credentialsForRequest && getOpenIdFedIssuerMetadata(credentialsForRequest.verifier.entityId), [credentialsForRequest] ) const lastInteractionDate = activities?.[0]?.date - const usePin = useMemo(() => { - const isPidInSubmission = - credentialsForRequest?.formattedSubmission?.entries.some((entry) => - entry.credentials.some((credential) => isPidCredential(credential.metadata?.type)) - ) ?? false - // TODO: usePin when HSM or no PID - return !isPidInSubmission - }, [credentialsForRequest]) - useEffect(() => { if (credentialsForRequest) return @@ -64,122 +62,84 @@ export function FunkeOpenIdPresentationNotificationScreen() { }) }, [credentialsForRequest, params.data, params.uri, toast.show, agent, pushToWallet, toast]) - const onProofAccept = useCallback(async (): Promise => { - if (!credentialsForRequest) - return { - status: 'error', - result: { - title: 'No credentials selected', - }, - } - - setIsSharing(true) + const onProofAccept = useCallback( + async (pin?: string): Promise => { + if (!credentialsForRequest) + return { + status: 'error', + result: { + title: 'No credentials selected', + }, + } - try { - await shareProof({ - agent, - authorizationRequest: credentialsForRequest.authorizationRequest, - credentialsForRequest: credentialsForRequest.credentialsForRequest, - selectedCredentials: {}, - allowUntrustedCertificate: true, - }) + setIsSharing(true) - // TODO: only add first one to activity? - const credentialsWithDisclosedPayload = credentialsForRequest.formattedSubmission.entries.flatMap((entry) => { - return entry.credentials.map((credential) => { + if (shouldUsePin) { + // TODO: we should handle invalid pin + if (!pin) { return { - id: credential.id, - disclosedAttributes: credential.requestedAttributes ?? [], - disclosedPayload: credential.disclosedPayload ?? {}, + status: 'error', + result: { + title: 'Authentication failed', + }, } + } + // TODO: maybe provide to shareProof method? + setWalletServiceProviderPin(pin.split('').map(Number)) + } + + try { + await shareProof({ + agent, + resolvedRequest: credentialsForRequest, + selectedCredentials: {}, + allowUntrustedCertificate: true, }) - }) - await addSharedActivity(agent, { - status: 'success', - entity: { - id: credentialsForRequest.verifier.entityId, - name: fedDisplayData - ? fedDisplayData.display.name - : credentialsForRequest.verifier.name ?? credentialsForRequest.verifier.hostName, - logo: fedDisplayData ? fedDisplayData.display.logo : undefined, - host: credentialsForRequest.verifier.hostName as string, - }, - request: { - name: credentialsForRequest.formattedSubmission.name, - purpose: credentialsForRequest.formattedSubmission.purpose, - credentials: credentialsWithDisclosedPayload ?? [], - }, - }) + await addSharedActivityForCredentialsForRequest(agent, credentialsForRequest, 'success') + return { + status: 'success', + result: { + title: 'Presentation shared', + }, + } + } catch (error) { + setIsSharing(false) + if (error instanceof BiometricAuthenticationCancelledError) { + return { + status: 'error', + result: { + title: 'Biometric authentication cancelled', + }, + } + } - return { - status: 'success', - result: { - title: 'Presentation shared', - }, - } - } catch (error) { - setIsSharing(false) - if (error instanceof BiometricAuthenticationCancelledError) { + if (credentialsForRequest) { + await addSharedActivityForCredentialsForRequest(agent, credentialsForRequest, 'failed') + } + + agent.config.logger.error('Error accepting presentation', { + error, + }) return { status: 'error', + redirectToWallet: true, result: { - title: 'Biometric authentication cancelled', + title: 'Presentation could not be shared.', }, } } - agent.config.logger.error('Error accepting presentation', { - error, - }) - return { - status: 'error', - redirectToWallet: true, - result: { - title: 'Presentation could not be shared.', - }, - } - } - }, [credentialsForRequest, agent, fedDisplayData]) + }, + [credentialsForRequest, agent, shouldUsePin] + ) const onProofDecline = async () => { - // TODO: only add first one to activity? - const credentialsWithDisclosedPayload = credentialsForRequest?.formattedSubmission.entries.flatMap((entry) => { - return entry.credentials.map((credential) => { - return { - id: credential.id, - disclosedAttributes: credential.requestedAttributes ?? [], - disclosedPayload: credential.disclosedPayload ?? {}, - } - }) - }) - - const activityData = { - entity: { - id: credentialsForRequest?.verifier.entityId as string, - host: credentialsForRequest?.verifier.hostName as string, - name: fedDisplayData - ? fedDisplayData.display.name - : credentialsForRequest?.verifier.name ?? credentialsForRequest?.verifier.hostName, - logo: fedDisplayData ? fedDisplayData.display.logo : undefined, - }, - request: { - name: credentialsForRequest?.formattedSubmission?.name, - purpose: credentialsForRequest?.formattedSubmission?.purpose, - credentials: credentialsWithDisclosedPayload ?? [], - }, - } - - if (credentialsForRequest?.formattedSubmission?.areAllSatisfied) { - await addSharedActivity(agent, { ...activityData, status: 'stopped' }) - } else { - await addSharedActivity(agent, { - ...activityData, - status: 'failed', - request: { - ...activityData.request, - failureReason: credentialsForRequest?.formattedSubmission ? 'missing_credentials' : 'unknown', - }, - }) + if (credentialsForRequest) { + await addSharedActivityForCredentialsForRequest( + agent, + credentialsForRequest, + credentialsForRequest.formattedSubmission.areAllSatisfied ? 'stopped' : 'failed' + ) } pushToWallet() @@ -188,17 +148,14 @@ export function FunkeOpenIdPresentationNotificationScreen() { return ( pushToWallet('replace')} diff --git a/apps/easypid/src/features/share/FunkePresentationNotificationScreen.tsx b/apps/easypid/src/features/share/FunkePresentationNotificationScreen.tsx index 8631f97f..0e6010e8 100644 --- a/apps/easypid/src/features/share/FunkePresentationNotificationScreen.tsx +++ b/apps/easypid/src/features/share/FunkePresentationNotificationScreen.tsx @@ -18,8 +18,7 @@ interface FunkePresentationNotificationScreenProps { submission?: FormattedSubmission usePin: boolean isAccepting: boolean - onAccept: () => Promise - onAcceptWithPin: (pin: string) => Promise + onAccept: (pin?: string) => Promise onDecline: () => void onComplete: () => void } @@ -32,7 +31,6 @@ export function FunkePresentationNotificationScreen({ approvalsCount, usePin, onAccept, - onAcceptWithPin, onDecline, isAccepting, submission, @@ -80,7 +78,7 @@ export function FunkePresentationNotificationScreen({ usePin && { step: 'pin-enter', progress: 82.5, - screen: , + screen: , }, { step: 'success', diff --git a/apps/easypid/src/features/share/FunkeRequestedAttributesDetailScreen.tsx b/apps/easypid/src/features/share/FunkeRequestedAttributesDetailScreen.tsx index 126878d9..7d3d215e 100644 --- a/apps/easypid/src/features/share/FunkeRequestedAttributesDetailScreen.tsx +++ b/apps/easypid/src/features/share/FunkeRequestedAttributesDetailScreen.tsx @@ -21,8 +21,7 @@ import { useRouter } from 'solito/router' import { CredentialAttributes, TextBackButton } from '@package/app/src/components' import { useHaptics, useHasInternetConnection, useScrollViewPosition } from '@package/app/src/hooks' -import { useCredentialsWithCustomDisplayById } from '@easypid/hooks/useCredentialsWithCustomDisplay' -import type { CredentialForDisplayId } from '@package/agent' +import { type CredentialForDisplayId, metadataForDisplay, useCredentialForDisplayById } from '@package/agent' import { useNavigation } from 'expo-router' import { FadeInUp, FadeOutUp } from 'react-native-reanimated' import { useSafeAreaInsets } from 'react-native-safe-area-context' @@ -42,7 +41,7 @@ export function FunkeRequestedAttributesDetailScreen({ const toast = useToastController() const { handleScroll, isScrolledByOffset, scrollEventThrottle } = useScrollViewPosition() const { bottom } = useSafeAreaInsets() - const { credential: activeCredential, isLoading } = useCredentialsWithCustomDisplayById(id) + const { credential: activeCredential, isLoading } = useCredentialForDisplayById(id) const router = useRouter() const [scrollViewHeight, setScrollViewHeight] = useState(0) const { withHaptics } = useHaptics() @@ -111,10 +110,10 @@ export function FunkeRequestedAttributesDetailScreen({ {disclosedAttributeLength} attribute{disclosedAttributeLength > 1 ? 's' : ''} from{' '} - {activeCredential?.display.name} + {activeCredential.display.name} - {activeCredential?.display.issuer && ( - Issued by {activeCredential?.display.issuer.name}. + {activeCredential.display.issuer && ( + Issued by {activeCredential.display.issuer.name}. )} diff --git a/apps/easypid/src/features/share/components/RequestedAttributesSection.tsx b/apps/easypid/src/features/share/components/RequestedAttributesSection.tsx index 7926d4da..8c48d354 100644 --- a/apps/easypid/src/features/share/components/RequestedAttributesSection.tsx +++ b/apps/easypid/src/features/share/components/RequestedAttributesSection.tsx @@ -1,11 +1,10 @@ -import type { ClaimFormat } from '@credo-ts/core' import { - getPidAttributesForDisplay, - getPidDisclosedAttributeNames, - isPidCredential, - usePidCredential, -} from '@easypid/hooks' -import type { FormattedSubmission } from '@package/agent/src' + type FormattedSubmission, + type FormattedSubmissionEntryNotSatisfied, + type FormattedSubmissionEntrySatisfied, + getDisclosedAttributeNamesForDisplay, + getUnsatisfiedAttributePathsForDisplay, +} from '@package/agent' import { Heading, Paragraph, YStack } from '@package/ui' import { CardWithAttributes } from 'packages/app/src' @@ -14,71 +13,70 @@ export type RequestedAttributesSectionProps = { } export function RequestedAttributesSection({ submission }: RequestedAttributesSectionProps) { - const { pidCredentialForDisplay } = usePidCredential() + const satisfiedEntries = submission.entries.filter((e): e is FormattedSubmissionEntrySatisfied => e.isSatisfied) + const unsatisfiedEntries = submission.entries.filter((e): e is FormattedSubmissionEntryNotSatisfied => !e.isSatisfied) return ( - - REQUESTED ATTRIBUTES - + + + {satisfiedEntries.length > 0 ? 'REQUESTED CARDS' : 'UNAVAILABLE CARDS'} - {submission.areAllSatisfied - ? 'Only the following attributes will be shared. Nothing more.' - : `You don't have the requested credential(s).`} + {unsatisfiedEntries.length === 0 + ? 'Only the following attributes from your cards will be shared. Nothing more.' + : satisfiedEntries.length === 0 + ? `You don't have the requested card(s).` + : `You don't have all of the requested cards.`} - {submission.entries.map((entry) => ( - - {entry.credentials.map((credential) => { - if (isPidCredential(credential.metadata?.type)) { - return ( - new Date() : false - } - /> - ) - } - return ( - new Date() : false - } - /> - ) - })} - - ))} + {/* We always take the first one for now (no selection) */} + {satisfiedEntries.map(({ credentials: [credential], ...entry }) => { + return ( + new Date() + : false + } + /> + ) + })} + {unsatisfiedEntries.length > 0 && ( + <> + {satisfiedEntries.length !== 0 && ( + + UNAVAILABLE CARDS + + )} + {unsatisfiedEntries.map((entry) => ( + + ))} + + )} ) diff --git a/apps/easypid/src/features/share/slides/PinSlide.tsx b/apps/easypid/src/features/share/slides/PinSlide.tsx index 891b98dd..de64cb06 100644 --- a/apps/easypid/src/features/share/slides/PinSlide.tsx +++ b/apps/easypid/src/features/share/slides/PinSlide.tsx @@ -4,7 +4,7 @@ import { useRef, useState } from 'react' import type { PresentationRequestResult } from '../components/utils' interface PinSlideProps { - onPinComplete: (pin: string) => Promise + onPinComplete: (pin: string) => Promise | Promise isLoading: boolean } @@ -20,7 +20,7 @@ export const PinSlide = ({ onPinComplete, isLoading }: PinSlideProps) => { onPinComplete(pin) .then((r) => { - if (r.status === 'success') return onNext() + if (!r || r.status === 'success') return onNext() toast.show(r.result.title, { message: r.result.message, diff --git a/apps/easypid/src/features/share/slides/ShareCredentialsSlide.tsx b/apps/easypid/src/features/share/slides/ShareCredentialsSlide.tsx index c04b0cf7..70fb545a 100644 --- a/apps/easypid/src/features/share/slides/ShareCredentialsSlide.tsx +++ b/apps/easypid/src/features/share/slides/ShareCredentialsSlide.tsx @@ -106,8 +106,8 @@ export const ShareCredentialsSlide = ({ /> ) : ( - - You don't have the required credentials + + You don't have the required cards Close diff --git a/apps/easypid/src/features/wallet/FunkeCredentialDetailAttributesScreen.tsx b/apps/easypid/src/features/wallet/FunkeCredentialDetailAttributesScreen.tsx index e4f89fbd..9607118a 100644 --- a/apps/easypid/src/features/wallet/FunkeCredentialDetailAttributesScreen.tsx +++ b/apps/easypid/src/features/wallet/FunkeCredentialDetailAttributesScreen.tsx @@ -18,14 +18,16 @@ import { CredentialAttributes } from '@package/app/src/components' import { useHaptics, useHeaderRightAction, useScrollViewPosition } from '@package/app/src/hooks' import { TextBackButton } from 'packages/app' +import { type CredentialMetadata, metadataForDisplay } from '@package/agent' import { useRouter } from 'expo-router' import { FadeOutUp } from 'react-native-reanimated' import { FadeInUp } from 'react-native-reanimated' import { useSafeAreaInsets } from 'react-native-safe-area-context' +// TODO: we should pass the credential for display here interface FunkeCredentialDetailAttributesScreenProps { attributes: Record - metadata: Record + metadata: CredentialMetadata } export function FunkeCredentialDetailAttributesScreen({ @@ -104,7 +106,7 @@ export function FunkeCredentialDetailAttributesScreen({ headerTitle="Metadata" borderStyle="large" attributeWeight="medium" - subject={metadata} + subject={metadataForDisplay(metadata)} headerStyle="small" showDevProps /> diff --git a/apps/easypid/src/features/wallet/FunkeCredentialDetailScreen.tsx b/apps/easypid/src/features/wallet/FunkeCredentialDetailScreen.tsx index 4f385701..a43beaed 100644 --- a/apps/easypid/src/features/wallet/FunkeCredentialDetailScreen.tsx +++ b/apps/easypid/src/features/wallet/FunkeCredentialDetailScreen.tsx @@ -15,14 +15,12 @@ import React, { useState } from 'react' import { useHeaderRightAction, useScrollViewPosition } from '@package/app/src/hooks' import { DeleteCredentialSheet, TextBackButton } from 'packages/app' -import { useCredentialsWithCustomDisplayById } from '@easypid/hooks/useCredentialsWithCustomDisplay' -import type { CredentialForDisplayId } from '@package/agent' +import { type CredentialForDisplayId, useCredentialForDisplayById } from '@package/agent' import { useRouter } from 'expo-router' import { useHaptics } from 'packages/app' import { CardInfoLifecycle, FunkeCredentialCard } from 'packages/app/src/components' import { useSafeAreaInsets } from 'react-native-safe-area-context' import { createParam } from 'solito' -import { isPidCredential } from '../../hooks' const { useParams } = createParam<{ id: CredentialForDisplayId }>() @@ -34,13 +32,13 @@ export function FunkeCredentialDetailScreen() { const { bottom } = useSafeAreaInsets() const { withHaptics } = useHaptics() - const { credential } = useCredentialsWithCustomDisplayById(params.id) + const { credential } = useCredentialForDisplayById(params.id) const [isSheetOpen, setIsSheetOpen] = useState(false) useHeaderRightAction({ icon: , onPress: withHaptics(() => setIsSheetOpen(true)), - renderCondition: !isPidCredential(credential?.metadata.type), + renderCondition: credential?.category?.canDeleteCredential ?? true, }) if (!credential) { @@ -57,8 +55,8 @@ export function FunkeCredentialDetailScreen() { router.push({ pathname: '/credentials/[id]/attributes', params: { - attributes: JSON.stringify(credential.attributesForDisplay ?? credential.attributes), - metadata: JSON.stringify(credential.metadataForDisplay ?? credential.metadata), + attributes: JSON.stringify(credential.attributes), + metadata: JSON.stringify(credential.metadata), }, }) }) @@ -99,7 +97,10 @@ export function FunkeCredentialDetailScreen() { - + { diff --git a/apps/easypid/src/features/wallet/FunkeWalletScreen.tsx b/apps/easypid/src/features/wallet/FunkeWalletScreen.tsx index a545fc6c..4d781728 100644 --- a/apps/easypid/src/features/wallet/FunkeWalletScreen.tsx +++ b/apps/easypid/src/features/wallet/FunkeWalletScreen.tsx @@ -15,7 +15,7 @@ import { } from '@package/ui' import { useRouter } from 'solito/router' -import { useCredentialsWithCustomDisplay } from '@easypid/hooks/useCredentialsWithCustomDisplay' +import { useCredentialsForDisplay } from '@package/agent' import { useHaptics, useNetworkCallback, useScrollViewPosition } from '@package/app/src/hooks' import { FunkeCredentialCard } from 'packages/app' import { FadeIn, FadeInDown, ZoomIn } from 'react-native-reanimated' @@ -24,7 +24,7 @@ import { LatestActivityCard } from './components/LatestActivityCard' export function FunkeWalletScreen() { const { push } = useRouter() - const { isLoading, credentials } = useCredentialsWithCustomDisplay() + const { isLoading, credentials } = useCredentialsForDisplay() const { withHaptics } = useHaptics() const pushToMenu = withHaptics(() => push('/menu')) diff --git a/apps/easypid/src/features/wallet/components/LatestActivityCard.tsx b/apps/easypid/src/features/wallet/components/LatestActivityCard.tsx index 1e107566..1aa92b33 100644 --- a/apps/easypid/src/features/wallet/components/LatestActivityCard.tsx +++ b/apps/easypid/src/features/wallet/components/LatestActivityCard.tsx @@ -1,5 +1,5 @@ import { useActivities } from '@easypid/features/activity/activityRecord' -import { useCredentialsWithCustomDisplay } from '@easypid/hooks/useCredentialsWithCustomDisplay' +import { useCredentialsForDisplay } from '@package/agent' import { InfoButton } from '@package/ui/src' import { useRouter } from 'expo-router' import { useHaptics } from 'packages/app/src/hooks' @@ -11,7 +11,7 @@ export function LatestActivityCard() { const { withHaptics } = useHaptics() const { activities } = useActivities() const latestActivity = activities[0] - const { credentials } = useCredentialsWithCustomDisplay() + const { credentials } = useCredentialsForDisplay() const pushToActivity = withHaptics(() => push('/activity')) @@ -25,7 +25,7 @@ export function LatestActivityCard() { } } if (latestActivity.type === 'received') { - const credential = credentials.find((c) => c.id.includes(latestActivity.credentialIds[0])) + const credential = credentials.find((c) => c.id === latestActivity.credentialIds[0]) return { title: formatRelativeDate(new Date(latestActivity.date)), description: `Added ${credential?.display.name ?? '1 card'}`, diff --git a/apps/easypid/src/hooks/useBackgroundPidRefresh.ts b/apps/easypid/src/hooks/useBackgroundPidRefresh.ts index 388695ce..5b8725d6 100644 --- a/apps/easypid/src/hooks/useBackgroundPidRefresh.ts +++ b/apps/easypid/src/hooks/useBackgroundPidRefresh.ts @@ -31,7 +31,7 @@ export function useBackgroundPidRefresh(batchThreshold: number) { let shouldRefreshSdJwt = false if (sdJwt) { - const sdJwtBatch = getBatchCredentialMetadata(sdJwt) + const sdJwtBatch = getBatchCredentialMetadata(sdJwt.record) if (sdJwtBatch) { shouldRefreshSdJwt = sdJwtBatch.additionalCredentials.length <= batchThreshold } @@ -39,7 +39,7 @@ export function useBackgroundPidRefresh(batchThreshold: number) { let shouldRefreshMdoc = false if (mdoc) { - const mdocBatch = getBatchCredentialMetadata(mdoc) + const mdocBatch = getBatchCredentialMetadata(mdoc.record) if (mdocBatch) { shouldRefreshMdoc = mdocBatch.additionalCredentials.length <= batchThreshold } @@ -59,8 +59,8 @@ export function useBackgroundPidRefresh(batchThreshold: number) { refreshPid({ agent, - sdJwt: shouldRefreshSdJwt ? sdJwt : undefined, - mdoc: shouldRefreshMdoc ? mdoc : undefined, + sdJwt: shouldRefreshSdJwt ? sdJwt?.record : undefined, + mdoc: shouldRefreshMdoc ? mdoc?.record : undefined, }).finally(() => setIsRefreshing(false)) } }, [shouldRefreshMdoc, shouldRefreshSdJwt, hasInternet, agent, isRefreshing, mdoc, sdJwt, shouldUseCloudHsm]) diff --git a/apps/easypid/src/hooks/useCanUseSecureEnclave.ts b/apps/easypid/src/hooks/useCanUseSecureEnclave.ts new file mode 100644 index 00000000..edb971b6 --- /dev/null +++ b/apps/easypid/src/hooks/useCanUseSecureEnclave.ts @@ -0,0 +1,17 @@ +import { generateKeypair } from '@animo-id/expo-secure-environment' +import { useEffect, useState } from 'react' +import { Platform } from 'react-native' + +export function useCanUseSecureEnclave() { + if (Platform.OS === 'ios') return true + + const [canUseSecureEnclave, setCanUseSecureEnclave] = useState() + + useEffect(() => { + generateKeypair('123', false) + .then(() => setCanUseSecureEnclave(true)) + .catch(() => setCanUseSecureEnclave(false)) + }, []) + + return canUseSecureEnclave +} diff --git a/apps/easypid/src/hooks/useCredentialsWithCustomDisplay.ts b/apps/easypid/src/hooks/useCredentialsWithCustomDisplay.ts deleted file mode 100644 index 82c070ba..00000000 --- a/apps/easypid/src/hooks/useCredentialsWithCustomDisplay.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { type CredentialForDisplay, type CredentialForDisplayId, useCredentialsForDisplay } from '@package/agent' -import { useMemo } from 'react' -import { type PidSdJwtVcAttributes, usePidCredential } from './usePidCredential' - -type CustomCredentialForDisplay = CredentialForDisplay & { - attributesForDisplay?: PidSdJwtVcAttributes - metadataForDisplay?: Record -} - -export const useCredentialsWithCustomDisplayById = (id: CredentialForDisplayId) => { - const { credentials, isLoading } = useCredentialsWithCustomDisplay(true) - - return { - // NOTE: we support both the prefixed id and non-prefixed. We should fix the input id - // but for now this is the easiest approach - credential: useMemo(() => credentials.find((c) => c.id === id || c.id.endsWith(id)), [id, credentials]), - isLoading, - } -} - -export const useCredentialsWithCustomDisplay = (includeHiddenCredentials = false) => { - const { credentials, isLoading: isLoadingCredentialsForDisplay } = useCredentialsForDisplay() - const { - pidCredentialForDisplay: pidCredential, - credentialIds: pidCredentialIds, - credentials: pidCredentials, - isLoading: isLoadingPidCredential, - } = usePidCredential() - - const filteredCredentials = useMemo(() => { - const pidIndex = credentials.findIndex((c) => c.id === pidCredential?.id) - const withoutPids = credentials - .filter((c) => !pidCredentialIds?.includes(c.id)) - .map((c) => ({ ...c, isPid: false })) - - // No pids, just return - if (pidIndex === -1 || !pidCredential) return withoutPids - - // Insert only one of the pids - return [ - ...withoutPids.slice(0, pidIndex), - ...(includeHiddenCredentials - ? pidCredentials.map((p) => ({ ...p, isPid: true })) - : [{ ...pidCredential, isPid: true }]), - ...withoutPids.slice(pidIndex), - ] - }, [credentials, pidCredential, pidCredentials, pidCredentialIds, includeHiddenCredentials]) - - return { - credentials: filteredCredentials as CustomCredentialForDisplay[], - isLoading: isLoadingCredentialsForDisplay || isLoadingPidCredential, - } -} diff --git a/apps/easypid/src/hooks/usePidCredential.tsx b/apps/easypid/src/hooks/usePidCredential.tsx index 38856031..82ba095f 100644 --- a/apps/easypid/src/hooks/usePidCredential.tsx +++ b/apps/easypid/src/hooks/usePidCredential.tsx @@ -1,10 +1,6 @@ import { ClaimFormat, MdocRecord, SdJwtVcRecord } from '@credo-ts/core' -import { type CredentialForDisplayId, type CredentialMetadata, useCredentialsForDisplay } from '@package/agent' -import { capitalizeFirstLetter, sanitizeString } from '@package/utils' -import { useMemo } from 'react' -import germanIssuerImage from '../../assets/german-issuer-image.png' -import pidBackgroundImage from '../../assets/pid-background.png' -import { pidSchemes } from '../constants' +import { type CredentialForDisplay, type CredentialMetadata, useCredentialsForDisplay } from '@package/agent' +import { sanitizeString } from '@package/utils' type Attributes = { given_name: string @@ -359,37 +355,11 @@ export function getSdJwtPidDisclosedAttributeNames(attributes: Partial { - const pidCredentials = credentials.filter( - (cred) => - pidSchemes.sdJwtVcVcts.includes(cred.metadata.type) || pidSchemes.msoMdocDoctypes.includes(cred.metadata.type) - ) - - if (pidCredentials.length === 0) return [] - - return pidCredentials.map((pidCredential) => { - const attributes = pidCredential.attributes as PidSdJwtVcAttributes | PidMdocAttributes - const claimFormat = pidCredential.claimFormat as ClaimFormat.SdJwtVc | ClaimFormat.MsoMdoc - return { - id: pidCredential.id as CredentialForDisplayId, - type: pidCredential.metadata.type, - claimFormat: pidCredential.claimFormat, - createdAt: pidCredential.createdAt, - attributes: pidCredential.attributes, - display: usePidDisplay(), - userName: `${capitalizeFirstLetter(attributes.given_name.toLowerCase())}`, - attributesForDisplay: getPidAttributesForDisplay(attributes, claimFormat), - metadata: pidCredential.metadata, - metadataForDisplay: getPidMetadataAttributesForDisplay(attributes, pidCredential.metadata, ClaimFormat.SdJwtVc), - record: pidCredential.record, - } - }) - }, [credentials]) + const { isLoading, credentials } = useCredentialsForDisplay({ + removeCanonicalRecords: false, + credentialCategory: 'DE-PID', + }) if (isLoading) { return { @@ -398,41 +368,19 @@ export function usePidCredential() { } as const } + const credential = + credentials.find((c) => c.category?.displayPriority) ?? (credentials[0] as CredentialForDisplay | undefined) + return { isLoading: false, - pidCredentialForDisplay: pidCredentials[0] as (typeof pidCredentials)[number] | undefined, - credentialIds: pidCredentials.map((p) => p.id), - credentials: pidCredentials, - mdoc: pidCredentials.find((c): c is typeof c & { record: MdocRecord } => c.record instanceof MdocRecord)?.record, - sdJwt: pidCredentials.find((c): c is typeof c & { record: SdJwtVcRecord } => c.record instanceof SdJwtVcRecord) - ?.record, + credential, + credentials, + mdoc: credentials.find( + (c): c is typeof c & { record: MdocRecord; claimFormat: ClaimFormat.MsoMdoc } => c.record instanceof MdocRecord + ), + sdJwt: credentials.find( + (c): c is typeof c & { record: SdJwtVcRecord; claimFormat: ClaimFormat.SdJwtVc } => + c.record instanceof SdJwtVcRecord + ), } as const } - -export function isPidCredential(credentialType?: string) { - return credentialType - ? pidSchemes.sdJwtVcVcts.includes(credentialType) || pidSchemes.msoMdocDoctypes.includes(credentialType) - : false -} - -export const usePidDisplay = () => { - return { - issuer: { - name: 'Bundesdruckerei', - locale: 'de', - logo: { - url: germanIssuerImage, - altText: 'Logo of German Government', - }, - }, - name: 'Personalausweis', - description: 'This is a personal ID', - locale: 'de', - textColor: '#2F3544', - backgroundColor: '#F1F2F0', - backgroundImage: { - url: pidBackgroundImage, - altText: 'Background Image', - }, - } -} diff --git a/apps/easypid/src/hooks/useShouldUsePinForPresentation.tsx b/apps/easypid/src/hooks/useShouldUsePinForPresentation.tsx new file mode 100644 index 00000000..7eab2de0 --- /dev/null +++ b/apps/easypid/src/hooks/useShouldUsePinForPresentation.tsx @@ -0,0 +1,20 @@ +import type { CredentialsForProofRequest } from '@package/agent' +import { useMemo } from 'react' +import { useShouldUseCloudHsm } from '../features/onboarding/useShouldUseCloudHsm' + +export const useShouldUsePinForSubmission = (credentialsForRequest?: CredentialsForProofRequest) => { + const [shouldUseCloudHsm] = useShouldUseCloudHsm() + + const shouldUsePin = useMemo(() => { + if (shouldUseCloudHsm) return true + const isPidInSubmission = + credentialsForRequest?.formattedSubmission?.entries.some((entry) => + // TODO: should store this on the category as well so we can easily detect auth + entry.isSatisfied ? entry.credentials[0].credential.category?.credentialCategory === 'DE-PID' : false + ) ?? false + + return !isPidInSubmission + }, [credentialsForRequest, shouldUseCloudHsm]) + + return credentialsForRequest === undefined ? undefined : shouldUsePin +} diff --git a/apps/easypid/src/use-cases/ReceivePidUseCaseCFlow.ts b/apps/easypid/src/use-cases/ReceivePidUseCaseCFlow.ts index 3d0fc251..bd1b9269 100644 --- a/apps/easypid/src/use-cases/ReceivePidUseCaseCFlow.ts +++ b/apps/easypid/src/use-cases/ReceivePidUseCaseCFlow.ts @@ -4,14 +4,23 @@ import { BiometricAuthenticationError, OpenId4VciAuthorizationFlow, type SdJwtVcRecord, + getCredentialCategoryMetadata, receiveCredentialFromOpenId4VciOffer, resolveOpenId4VciOffer, + setCredentialCategoryMetadata, + setOpenId4VcCredentialMetadata, setRefreshCredentialMetadata, storeCredential, } from '@package/agent' import { getShouldUseCloudHsm } from '../features/onboarding/useShouldUseCloudHsm' import { ReceivePidUseCaseFlow, type ReceivePidUseCaseFlowOptions } from './ReceivePidUseCaseFlow' import { C_PRIME_SD_JWT_MDOC_OFFER } from './bdrPidIssuerOffers' +import { + bdrPidCredentialDisplay, + bdrPidIssuerDisplay, + bdrPidOpenId4VcMetadata, + bdrPidSdJwtTypeMetadata, +} from './bdrPidMetadata' export class ReceivePidUseCaseCFlow extends ReceivePidUseCaseFlow { public static async initialize(options: ReceivePidUseCaseFlowOptions) { @@ -67,7 +76,7 @@ export class ReceivePidUseCaseCFlow extends ReceivePidUseCaseFlow { resolvedCredentialOffer: this.resolvedCredentialOffer, credentialConfigurationIdsToRequest, clientId: ReceivePidUseCaseCFlow.CLIENT_ID, - requestBatch: getShouldUseCloudHsm() ? 10 : false, + requestBatch: getShouldUseCloudHsm() ? 2 : false, pidSchemes, }) @@ -79,6 +88,26 @@ export class ReceivePidUseCaseCFlow extends ReceivePidUseCaseFlow { throw new Error(`Unexpected record type ${credentialRecord.type}`) } + // NOTE: temp override to use hardcoded type metadata. + // it uses parts of our branding (as the type metadata doesn't contain + // rendering and a very weird long name) + if (credentialRecord.type === 'SdJwtVcRecord') { + credentialRecord.typeMetadata = bdrPidSdJwtTypeMetadata + } + + setCredentialCategoryMetadata(credentialRecord, { + credentialCategory: 'DE-PID', + // prioritize sd-jwt for PID + displayPriority: credentialRecord.type === 'SdJwtVcRecord', + canDeleteCredential: false, + }) + + // Override openid4vc metadata + setOpenId4VcCredentialMetadata( + credentialRecord, + bdrPidOpenId4VcMetadata(this.resolvedCredentialOffer.credentialOfferPayload.credential_issuer) + ) + // It seems the refresh token can be re-used, so we store it on all the records if (this.accessToken.accessTokenResponse.refresh_token) { setRefreshCredentialMetadata(credentialRecord, { diff --git a/apps/easypid/src/use-cases/RefreshPidUseCase.ts.ts b/apps/easypid/src/use-cases/RefreshPidUseCase.ts.ts index f0e6c024..46f545f0 100644 --- a/apps/easypid/src/use-cases/RefreshPidUseCase.ts.ts +++ b/apps/easypid/src/use-cases/RefreshPidUseCase.ts.ts @@ -9,8 +9,9 @@ import { receiveCredentialFromOpenId4VciOffer, resolveOpenId4VciOffer, setRefreshCredentialMetadata, - storeCredential, + updateCredential, } from '@package/agent' +import { getBatchCredentialMetadata, setBatchCredentialMetadata } from '@package/agent/src/openid4vc/batchMetadata' import { pidSchemes } from '../constants' import { ReceivePidUseCaseFlow } from './ReceivePidUseCaseFlow' import { C_PRIME_SD_JWT_MDOC_OFFER } from './bdrPidIssuerOffers' @@ -93,7 +94,7 @@ export class RefreshPidUseCase { resolvedCredentialOffer: this.resolvedCredentialOffer, credentialConfigurationIdsToRequest, clientId: RefreshPidUseCase.CLIENT_ID, - requestBatch: 10, + requestBatch: 2, pidSchemes, }) @@ -109,13 +110,24 @@ export class RefreshPidUseCase { setRefreshCredentialMetadata(credentialRecord, existingRefreshMetadata) if (credentialRecord instanceof SdJwtVcRecord && sdJwt) { - credentialRecords.push(credentialRecord) - await storeCredential(this.options.agent, credentialRecord) - await this.options.agent.sdJwtVc.deleteById(sdJwt.id) + credentialRecords.push(sdJwt) + + // Update existing record based on new credentials + const batchMetadata = getBatchCredentialMetadata(credentialRecord) + if (batchMetadata) setBatchCredentialMetadata(sdJwt, batchMetadata) + sdJwt.compactSdJwtVc = credentialRecord.compactSdJwtVc + + // Should we update the type metadata as well? For now we use hardcoded anyway + await updateCredential(this.options.agent, sdJwt) } else if (credentialRecord instanceof MdocRecord && mdoc) { - credentialRecords.push(credentialRecord) - await storeCredential(this.options.agent, credentialRecord) - await this.options.agent.mdoc.deleteById(mdoc.id) + credentialRecords.push(mdoc) + + // Update existing record based on new credentials + const batchMetadata = getBatchCredentialMetadata(credentialRecord) + if (batchMetadata) setBatchCredentialMetadata(mdoc, batchMetadata) + mdoc.base64Url = credentialRecord.base64Url + + await updateCredential(this.options.agent, mdoc) } } diff --git a/packages/agent/src/format/pidBdrSdJwtTypeMetadata.ts b/apps/easypid/src/use-cases/bdrPidMetadata.ts similarity index 83% rename from packages/agent/src/format/pidBdrSdJwtTypeMetadata.ts rename to apps/easypid/src/use-cases/bdrPidMetadata.ts index e16c8904..6c4ee45b 100644 --- a/packages/agent/src/format/pidBdrSdJwtTypeMetadata.ts +++ b/apps/easypid/src/use-cases/bdrPidMetadata.ts @@ -1,6 +1,53 @@ import type { SdJwtVcTypeMetadata } from '@credo-ts/core' +import type { OpenId4VcCredentialMetadata } from '@package/agent' +import germanIssuerImage from '../../assets/german-issuer-image.png' +import pidBackgroundImage from '../../assets/pid-background.png' -export const pidBdrSdJwtTypeMetadata: SdJwtVcTypeMetadata = { +export const bdrPidCredentialDisplay = { + name: 'Personalausweis', + backgroundImage: pidBackgroundImage, + backgroundColor: '#F1F2F0', + textColor: '#2F3544', +} + +export const bdrPidIssuerDisplay = { + logo: germanIssuerImage, + name: 'Bundesdruckerei', +} + +export const bdrPidOpenId4VcMetadata = (credentialIssuer: string): OpenId4VcCredentialMetadata => { + return { + issuer: { + id: credentialIssuer, + display: [ + { + locale: 'en-US', + name: bdrPidIssuerDisplay.name, + logo: { + // FIXME + uri: bdrPidIssuerDisplay.logo as unknown as string, + }, + }, + ], + }, + credential: { + display: [ + { + name: bdrPidCredentialDisplay.name, + background_color: bdrPidCredentialDisplay.backgroundColor, + text_color: bdrPidCredentialDisplay.textColor, + background_image: { + // FIXME + uri: bdrPidCredentialDisplay.backgroundImage as unknown as string, + }, + locale: 'en-US', + }, + ], + }, + } +} + +export const bdrPidSdJwtTypeMetadata: SdJwtVcTypeMetadata = { // TODO: add vct to type interface in Credo // vct: 'https://metadata-8c062a.usercontent.opencode.de/pid.json', name: 'German Person Identification Data Credential - First Version', @@ -9,8 +56,22 @@ export const pidBdrSdJwtTypeMetadata: SdJwtVcTypeMetadata = { display: [ { lang: 'en-US', - name: 'German Person Identification Data Credential', - description: 'The core identification credential for all natural persons in Germany', + // Name from pid metadata is very long?!? + // name: 'German Person Identification Data Credential', + // description: 'The core identification credential for all natural persons in Germany', + name: bdrPidCredentialDisplay.name, + rendering: { + simple: { + background_color: bdrPidCredentialDisplay.backgroundColor, + text_color: bdrPidCredentialDisplay.textColor, + logo: { + // TODO: can we store local file path in a record? I think we might have to + // add an identifier and replace it before rendering.. + // FIXME: + uri: bdrPidCredentialDisplay.backgroundImage as unknown as string, + }, + }, + }, }, { lang: 'de-DE', diff --git a/apps/paradym/eas.json b/apps/paradym/eas.json index 67210b20..7404d950 100644 --- a/apps/paradym/eas.json +++ b/apps/paradym/eas.json @@ -1,6 +1,10 @@ { "build": { + "base": { + "node": "20.11.1" + }, "development": { + "extends": "base", "developmentClient": true, "distribution": "internal", "android": { @@ -15,12 +19,14 @@ } }, "preview": { + "extends": "base", "distribution": "internal", "env": { "APP_VARIANT": "preview" } }, "production": { + "extends": "base", "autoIncrement": true, "distribution": "store", "android": { diff --git a/package.json b/package.json index 9586d438..52d7fbb0 100644 --- a/package.json +++ b/package.json @@ -25,15 +25,18 @@ "@unimodules/react-native-adapter": "catalog:", "@unimodules/core": "catalog:", "react-docgen-typescript": "catalog:", + "@sphereon/did-auth-siop": "catalog:", + "@sphereon/jarm": "catalog:", + "@sphereon/oid4vc-common": "catalog:", "@animo-id/oid4vci": "catalog:", "@animo-id/oauth2": "catalog:", "@animo-id/oauth2-utils": "catalog:" }, "patchedDependencies": { "@hyperledger/indy-vdr-react-native@0.2.2": "patches/@hyperledger__indy-vdr-react-native@0.2.2.patch", - "@credo-ts/askar@0.6.0-alpha-20241120153226": "patches/@credo-ts__askar@0.6.0-alpha-20241120153226.patch", - "@animo-id/mdoc@0.2.38": "patches/@animo-id__mdoc@0.2.38.patch" + "@credo-ts/askar@0.6.0-pr-2100-20241124170219": "patches/@credo-ts__askar@0.6.0-pr-2100-20241124170219.patch", + "@sphereon/kmp-mdl-mdoc": "patches/@sphereon__kmp-mdl-mdoc.patch" } }, - "packageManager": "pnpm@9.12.3+sha256.24235772cc4ac82a62627cd47f834c72667a2ce87799a846ec4e8e555e2d4b8b" + "packageManager": "pnpm@9.14.2+sha256.06e65a4965baff6d6097f9c8f75c35f6d420974dbc03d775009056a69edfd271" } diff --git a/packages/agent/package.json b/packages/agent/package.json index e76e7c8f..2eda00e5 100644 --- a/packages/agent/package.json +++ b/packages/agent/package.json @@ -5,6 +5,7 @@ "main": "src/index.ts", "dependencies": { "@animo-id/oid4vci": "catalog:", + "@astronautlabs/jsonpath": "^1.1.2", "@animo-id/oauth2": "catalog:", "@credo-ts/anoncreds": "catalog:", "@credo-ts/askar": "catalog:", diff --git a/packages/agent/src/credentialCategoryMetadata.ts b/packages/agent/src/credentialCategoryMetadata.ts new file mode 100644 index 00000000..1a10b61a --- /dev/null +++ b/packages/agent/src/credentialCategoryMetadata.ts @@ -0,0 +1,44 @@ +import type { MdocRecord, SdJwtVcRecord, W3cCredentialRecord } from '@credo-ts/core' + +export interface CredentialCategoryMetadata { + /** + * + */ + credentialCategory: 'DE-PID' | (string & {}) + + /** + * Whether this instance of the canoncical records should be displayed by default + */ + displayPriority?: boolean + + /** + * @default true + */ + canDeleteCredential?: boolean + + // TODO: we can also store here the key binding requirements, and whether we need to sign + // locally or remotely (so we can show PIN) +} + +const credentialCategoryMetadataKey = '_paradym/credentialCategoryMetadata' + +/** + * Gets the credential type metadata from the given credential record. + */ +export function getCredentialCategoryMetadata( + credentialRecord: W3cCredentialRecord | SdJwtVcRecord | MdocRecord +): CredentialCategoryMetadata | null { + return credentialRecord.metadata.get(credentialCategoryMetadataKey) +} + +/** + * Sets the credential type metadata on the given credential record + * + * NOTE: this does not save the record. + */ +export function setCredentialCategoryMetadata( + credentialRecord: W3cCredentialRecord | SdJwtVcRecord | MdocRecord, + metadata: CredentialCategoryMetadata +) { + credentialRecord.metadata.set(credentialCategoryMetadataKey, metadata) +} diff --git a/packages/agent/src/didcomm/metadata.ts b/packages/agent/src/didcomm/metadata.ts index 2888fa46..ee91a235 100644 --- a/packages/agent/src/didcomm/metadata.ts +++ b/packages/agent/src/didcomm/metadata.ts @@ -1,6 +1,7 @@ import type { CredentialExchangeRecord, ProofExchangeRecord } from '@credo-ts/core' import type { OpenId4VcCredentialMetadata } from '../openid4vc/displayMetadata' +// TODO: store this on the credential record export interface DidCommCredentialExchangeDisplayMetadata { issuerName?: string credentialName?: string diff --git a/packages/agent/src/display.ts b/packages/agent/src/display.ts index 09f4a4dd..186d03a7 100644 --- a/packages/agent/src/display.ts +++ b/packages/agent/src/display.ts @@ -1,21 +1,75 @@ -import type { JwkJson, SdJwtVcTypeMetadata, W3cCredentialRecord } from '@credo-ts/core' +import { + type JwkJson, + type MdocNameSpaces, + type SdJwtVcTypeMetadata, + W3cCredentialRecord, + getJwkFromKey, +} from '@credo-ts/core' import { ClaimFormat, Hasher, JsonTransformer, - Mdoc, + type Mdoc, MdocRecord, SdJwtVcRecord, TypedArrayEncoder, } from '@credo-ts/core' import { detectImageMimeType, formatDate, getHostNameFromUrl, isDateString, sanitizeString } from '@package/utils' -import { decodeSdJwtSync, getClaimsSync } from '@sd-jwt/decode' import type { CredentialForDisplayId } from './hooks' import type { OpenId4VcCredentialMetadata } from './openid4vc/displayMetadata' import type { W3cCredentialJson, W3cIssuerJson } from './types' +import { type CredentialCategoryMetadata, getCredentialCategoryMetadata } from './credentialCategoryMetadata' +import type { FormattedSubmissionEntrySatisfiedCredential } from './format/formatPresentation' import { getOpenId4VcCredentialMetadata } from './openid4vc/displayMetadata' +/** + * Paths that were requested but couldn't be satisfied. + * Maybe belongs in agent, but adding here because the `nonRenderedPaths` is + * very intertwined with our rendering logic + */ +export function getUnsatisfiedAttributePathsForDisplay(paths: Array[]) { + const nonRenderedPaths = ['iss', 'vct'] + return Array.from( + new Set( + paths + .filter( + (path): path is [string] => + typeof path[0] === 'string' && !path.some((p) => nonRenderedPaths.includes(p as string)) + ) + .map((path) => sanitizeString(path[0])) + ) + ) +} + +/** + * Paths that were requested and we have a matching credential for. + * This list is used for two purposes: + * - rendering attribute names in card preview + * - rendering how many attributes (count) will be shared + */ +export function getDisclosedAttributeNamesForDisplay(credential: FormattedSubmissionEntrySatisfiedCredential) { + // FIXME: this implementation in still too naive + // TODO: use the credential claim metadata (sd-jwt / oid4vc) to get labels for attribute paths + // TODO: we miss e.g. showing age_equal_or_over.21 as Age Over 21, but with the display metadata + // from bdr we can at least show it as: Age verification. If there is a key for a nested path we can + // also decide to include it + + // For mdoc we remove the namespaces + if (credential.credential.claimFormat === ClaimFormat.MsoMdoc) { + return Array.from(new Set(credential.disclosed.paths.map((path) => sanitizeString(path[1])))) + } + + // Otherwise we take the top-level keys + return Array.from( + new Set( + credential.disclosed.paths + .filter((path): path is [string] => typeof path[0] === 'string') + .map((path) => sanitizeString(path[0])) + ) + ) +} + type JffW3cCredentialJson = W3cCredentialJson & { name?: string description?: string @@ -56,6 +110,55 @@ export interface CredentialIssuerDisplay { logo?: DisplayImage } +export interface CredentialMetadata { + /** + * vct (sd-jwt) or doctype (mdoc) or last type entry (w3c) + */ + type: string + + /** + * issuer identifier. did or https url + */ + issuer?: string + + /** + * Holder identifier. did or jwk thubmprint + */ + holder?: string + + validUntil?: string + validFrom?: string + issuedAt?: string + + // TODO: define and render + status?: unknown +} + +export function metadataForDisplay(metadata: CredentialMetadata) { + const { type, holder, issuedAt, issuer, validFrom, validUntil } = metadata + + return { + type, + issuer, + holder, + issuedAt: issuedAt ? formatDate(new Date(issuedAt)) : undefined, + validFrom: validFrom ? formatDate(new Date(validFrom)) : undefined, + validUntil: validUntil ? formatDate(new Date(validUntil)) : undefined, + } +} + +export interface CredentialForDisplay { + id: CredentialForDisplayId + createdAt: Date + display: CredentialDisplay + attributes: Record + metadata: CredentialMetadata + claimFormat: ClaimFormat.SdJwtVc | ClaimFormat.MsoMdoc | ClaimFormat.JwtVc | ClaimFormat.LdpVc + record: W3cCredentialRecord | MdocRecord | SdJwtVcRecord + + category: CredentialCategoryMetadata | null +} + function findDisplay(display?: Display[]): Display | undefined { if (!display) return undefined @@ -270,28 +373,17 @@ function getW3cCredentialDisplay( } } -function getMdocCredentialDisplay( - credentialPayload: Record, - openId4VcMetadata?: OpenId4VcCredentialMetadata | null -) { +function getMdocCredentialDisplay(mdoc: Mdoc, openId4VcMetadata?: OpenId4VcCredentialMetadata | null) { let credentialDisplay: Partial = {} if (openId4VcMetadata) { credentialDisplay = getOpenId4VcCredentialDisplay(openId4VcMetadata) } - // TODO: mdoc - // If there's no name for the credential, we extract it from the last type - // and sanitize it. This is not optimal. But provides at least something. - // if (!credentialDisplay.name && typeof credentialPayload.vct === 'string') { - // credentialDisplay.name = sanitizeString(credentialPayload.vct) - // } - return { ...credentialDisplay, - // Last fallback, if there's really no name for the credential, we use a generic name - // TODO: use on-device AI to determine a name for the credential based on the credential data - name: credentialDisplay.name ?? 'Credential', + // If there's no name for the credential, we extract it from the doctype + name: credentialDisplay.name ?? mdoc.docType, } } @@ -324,15 +416,6 @@ function getSdJwtCredentialDisplay( } } -export interface CredentialMetadata { - type: string - issuer: string - holder?: string - validUntil?: string - validFrom?: string - issuedAt?: string -} - function safeCalculateJwkThumbprint(jwk: JwkJson): string | undefined { try { const thumbprint = TypedArrayEncoder.toBase64URL( @@ -346,8 +429,32 @@ function safeCalculateJwkThumbprint(jwk: JwkJson): string | undefined { return undefined } } +export function getAttributesAndMetadataForMdocPayload(namespaces: MdocNameSpaces, mdocInstance: Mdoc) { + const attributes: CredentialForDisplay['attributes'] = Object.fromEntries( + Object.values(namespaces).flatMap((v) => + Object.entries(v).map(([key, value]) => [key, recursivelyMapAttribues(value)]) + ) + ) + + const mdocMetadata: CredentialMetadata = { + type: mdocInstance.docType, + holder: mdocInstance.deviceKey + ? safeCalculateJwkThumbprint(getJwkFromKey(mdocInstance.deviceKey).toJson()) + : undefined, + issuedAt: mdocInstance.validityInfo.signed.toISOString(), + validFrom: mdocInstance.validityInfo.validFrom.toISOString(), + validUntil: mdocInstance.validityInfo.validUntil.toISOString(), + // TODO: extract issuer from certificate? + // issuer: undefined + } + + return { + attributes, + metadata: mdocMetadata, + } +} -export function filterAndMapSdJwtKeys(sdJwtVcPayload: Record) { +export function getAttributesAndMetadataForSdJwtPayload(sdJwtVcPayload: Record) { type SdJwtVcPayload = { iss: string cnf: Record @@ -357,168 +464,168 @@ export function filterAndMapSdJwtKeys(sdJwtVcPayload: Record) { exp?: number [key: string]: unknown } - // TODO: We should map these claims to nice format and names - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const { _sd_alg, _sd_hash, iss, vct, cnf, iat, exp, nbf, ...visibleProperties } = sdJwtVcPayload as SdJwtVcPayload + const { _sd_alg, _sd_hash, iss, vct, cnf, iat, exp, nbf, status, ...visibleProperties } = + sdJwtVcPayload as SdJwtVcPayload - const holder = cnf.kid ?? cnf.jwk ? safeCalculateJwkThumbprint(cnf.jwk as JwkJson) : undefined + const holder = cnf ? (cnf.kid ?? cnf.jwk ? safeCalculateJwkThumbprint(cnf.jwk as JwkJson) : undefined) : undefined const credentialMetadata: CredentialMetadata = { type: vct, issuer: iss, holder, - } - - if (iat) { - credentialMetadata.issuedAt = formatDate(new Date(iat * 1000)) - } - if (exp) { - credentialMetadata.validUntil = formatDate(new Date(exp * 1000)) - } - if (nbf) { - credentialMetadata.validFrom = formatDate(new Date(nbf * 1000)) + issuedAt: iat ? new Date(iat * 1000).toISOString() : undefined, + validUntil: exp ? new Date(exp * 1000).toISOString() : undefined, + validFrom: nbf ? new Date(nbf * 1000).toISOString() : undefined, + status, } return { - visibleProperties: Object.fromEntries( + attributes: Object.fromEntries( Object.entries(visibleProperties).map(([key, value]) => [key, recursivelyMapAttribues(value)]) ), metadata: credentialMetadata, - raw: { - issuedAt: iat ? new Date(iat * 1000) : undefined, - validUntil: exp ? new Date(exp * 1000) : undefined, - validFrom: nbf ? new Date(nbf * 1000) : undefined, - }, } } -export function getDisclosedAttributePaths(payload: object, prefix = ''): Array { - let attributes: Array = [] +export function getDisclosedAttributePathArrays( + payload: object, + maxDepth: number | undefined = undefined, + prefix: string[] = [] +): string[][] { + let attributePaths: string[][] = [] for (const [key, value] of Object.entries(payload)) { - const newKey = prefix ? `${prefix}.${key}` : key - if (!value) continue - if (value && typeof value === 'object') { + // TODO: handle arrays + const newPath = [...prefix, key] + if (value && typeof value === 'object' && maxDepth !== 0) { // If the value is a nested object, recurse - attributes = attributes.concat(getDisclosedAttributePaths(value, newKey)) + attributePaths = [ + ...attributePaths, + ...getDisclosedAttributePathArrays(value, maxDepth !== undefined ? maxDepth - 1 : undefined, newPath), + ] } else { - // If the value is a primitive, add the key to the list - attributes.push(newKey) + // If the value is a primitive or maxDepth is reached, add the key to the list + attributePaths.push(newPath) } } - return attributes + return attributePaths } -export function getCredentialForDisplay(credentialRecord: W3cCredentialRecord | SdJwtVcRecord | MdocRecord) { +export function getCredentialForDisplayId( + credentialRecord: W3cCredentialRecord | SdJwtVcRecord | MdocRecord +): CredentialForDisplayId { if (credentialRecord instanceof SdJwtVcRecord) { - // FIXME: we should probably add a decode method on the SdJwtVcRecord - // as you now need the agent context to decode the sd-jwt vc, while that's - // not really needed - const { disclosures, jwt } = decodeSdJwtSync(credentialRecord.compactSdJwtVc, (data, alg) => Hasher.hash(data, alg)) - const decodedPayload: Record = getClaimsSync(jwt.payload, disclosures, (data, alg) => - Hasher.hash(data, alg) - ) + return `sd-jwt-vc-${credentialRecord.id}` + } + if (credentialRecord instanceof W3cCredentialRecord) { + return `w3c-credential-${credentialRecord.id}` + } + if (credentialRecord instanceof MdocRecord) { + return `mdoc-${credentialRecord.id}` + } + + throw new Error('Unsupported credential record type') +} + +export function getCredentialForDisplay( + credentialRecord: W3cCredentialRecord | SdJwtVcRecord | MdocRecord +): CredentialForDisplay { + const credentialCategoryMetadata = getCredentialCategoryMetadata(credentialRecord) + const credentialForDisplayId = getCredentialForDisplayId(credentialRecord) + + if (credentialRecord instanceof SdJwtVcRecord) { + const sdJwtVc = credentialRecord.credential const openId4VcMetadata = getOpenId4VcCredentialMetadata(credentialRecord) const sdJwtTypeMetadata = credentialRecord.typeMetadata const issuerDisplay = getOpenId4VcIssuerDisplay(openId4VcMetadata) - const credentialDisplay = getSdJwtCredentialDisplay(decodedPayload, openId4VcMetadata, sdJwtTypeMetadata) - const mapped = filterAndMapSdJwtKeys(decodedPayload) + const credentialDisplay = getSdJwtCredentialDisplay(sdJwtVc.prettyClaims, openId4VcMetadata, sdJwtTypeMetadata) + const { attributes, metadata } = getAttributesAndMetadataForSdJwtPayload(sdJwtVc.prettyClaims) + // TODO: handle claim / display mapping here return { - id: `sd-jwt-vc-${credentialRecord.id}` satisfies CredentialForDisplayId, + id: credentialForDisplayId, createdAt: credentialRecord.createdAt, display: { ...credentialDisplay, issuer: issuerDisplay, }, - attributes: mapped.visibleProperties, - metadata: mapped.metadata, + attributes, + metadata, claimFormat: ClaimFormat.SdJwtVc, - validUntil: mapped.raw.validUntil, - validFrom: mapped.raw.validFrom, record: credentialRecord, + category: credentialCategoryMetadata, } } if (credentialRecord instanceof MdocRecord) { + const mdocInstance = credentialRecord.credential + const openId4VcMetadata = getOpenId4VcCredentialMetadata(credentialRecord) - const credentialDisplay = getMdocCredentialDisplay({}, openId4VcMetadata) + const credentialDisplay = getMdocCredentialDisplay(mdocInstance, openId4VcMetadata) const issuerDisplay = getOpenId4VcIssuerDisplay(openId4VcMetadata) - - const mdocInstance = Mdoc.fromBase64Url(credentialRecord.base64Url) - const attributes = Object.fromEntries( - Object.values(mdocInstance.issuerSignedNamespaces).flatMap((v) => - Object.entries(v).map(([key, value]) => [key, recursivelyMapAttribues(value)]) - ) + const { attributes, metadata } = getAttributesAndMetadataForMdocPayload( + mdocInstance.issuerSignedNamespaces, + mdocInstance ) return { - id: `mdoc-${credentialRecord.id}` satisfies CredentialForDisplayId, + id: credentialForDisplayId, createdAt: credentialRecord.createdAt, display: { ...credentialDisplay, issuer: issuerDisplay, }, attributes, - // TODO: - metadata: { - // holder: 'Unknown', - issuer: 'Unknown', - type: mdocInstance.docType, - } satisfies CredentialMetadata, + metadata, claimFormat: ClaimFormat.MsoMdoc, - validUntil: mdocInstance.validityInfo.validUntil, - validFrom: mdocInstance.validityInfo.validFrom, record: credentialRecord, + category: credentialCategoryMetadata, } } + if (credentialRecord instanceof W3cCredentialRecord) { + const credential = JsonTransformer.toJSON( + credentialRecord.credential.claimFormat === ClaimFormat.JwtVc + ? credentialRecord.credential.credential + : credentialRecord.credential.toJson() + ) as W3cCredentialJson - const credential = JsonTransformer.toJSON( - credentialRecord.credential.claimFormat === ClaimFormat.JwtVc - ? credentialRecord.credential.credential - : credentialRecord.credential - ) as W3cCredentialJson - - const openId4VcMetadata = getOpenId4VcCredentialMetadata(credentialRecord) - const issuerDisplay = getW3cIssuerDisplay(credential, openId4VcMetadata) - const credentialDisplay = getW3cCredentialDisplay(credential, openId4VcMetadata) + const openId4VcMetadata = getOpenId4VcCredentialMetadata(credentialRecord) + const issuerDisplay = getW3cIssuerDisplay(credential, openId4VcMetadata) + const credentialDisplay = getW3cCredentialDisplay(credential, openId4VcMetadata) - // FIXME: support credential with multiple subjects - const credentialAttributes = Array.isArray(credential.credentialSubject) - ? credential.credentialSubject[0] ?? {} - : credential.credentialSubject + // FIXME: support credential with multiple subjects + const credentialAttributes = Array.isArray(credential.credentialSubject) + ? credential.credentialSubject[0] ?? {} + : credential.credentialSubject - return { - id: `w3c-credential-${credentialRecord.id}` satisfies CredentialForDisplayId, - createdAt: credentialRecord.createdAt, - display: { - ...credentialDisplay, - issuer: issuerDisplay, - }, - credential, - attributes: credentialAttributes, - metadata: { - holder: credentialRecord.credential.credentialSubjectIds[0], - issuer: credentialRecord.credential.issuerId, - type: credentialRecord.credential.type[credentialRecord.credential.type.length - 1], - issuedAt: formatDate(new Date(credentialRecord.credential.issuanceDate)), - validUntil: credentialRecord.credential.expirationDate - ? formatDate(new Date(credentialRecord.credential.expirationDate)) - : undefined, - validFrom: undefined, - } satisfies CredentialMetadata, - claimFormat: credentialRecord.credential.claimFormat, - validUntil: credentialRecord.credential.expirationDate - ? new Date(credentialRecord.credential.expirationDate) - : undefined, - validFrom: credentialRecord.credential.issuanceDate - ? new Date(credentialRecord.credential.issuanceDate) - : undefined, - record: credentialRecord, + return { + id: credentialForDisplayId, + createdAt: credentialRecord.createdAt, + display: { + ...credentialDisplay, + issuer: issuerDisplay, + }, + attributes: credentialAttributes, + metadata: { + holder: credentialRecord.credential.credentialSubjectIds[0], + issuer: credentialRecord.credential.issuerId, + type: credentialRecord.credential.type[credentialRecord.credential.type.length - 1], + issuedAt: new Date(credentialRecord.credential.issuanceDate).toISOString(), + validUntil: credentialRecord.credential.expirationDate + ? new Date(credentialRecord.credential.expirationDate).toISOString() + : undefined, + validFrom: new Date(credentialRecord.credential.issuanceDate).toISOString(), + }, + claimFormat: credentialRecord.credential.claimFormat, + record: credentialRecord, + category: credentialCategoryMetadata, + } } + + throw new Error('Unsupported format') } type MappedAttributesReturnType = @@ -542,7 +649,6 @@ export function recursivelyMapAttribues(value: unknown): MappedAttributesReturnT if (value === null || value === undefined || typeof value === 'number' || typeof value === 'boolean') return value if (value instanceof Date || (typeof value === 'string' && isDateString(value))) { - // TODO: handle DateOnly (should be handled as time is 0 then) return formatDate(value) } if (typeof value === 'string') return value diff --git a/packages/agent/src/format/credentialEncoding.ts b/packages/agent/src/format/credentialEncoding.ts index 36ae7af8..58bcfbe9 100644 --- a/packages/agent/src/format/credentialEncoding.ts +++ b/packages/agent/src/format/credentialEncoding.ts @@ -1,6 +1,5 @@ import { ClaimFormat, - Mdoc, MdocRecord, SdJwtVcRecord, type VerifiableCredential, @@ -9,7 +8,6 @@ import { W3cJwtVerifiableCredential, type W3cVerifiableCredential, } from '@credo-ts/core' -import { pidBdrSdJwtTypeMetadata } from './pidBdrSdJwtTypeMetadata' export function decodeW3cCredential(credential: Record | string): W3cVerifiableCredential { return typeof credential === 'string' @@ -18,66 +16,26 @@ export function decodeW3cCredential(credential: Record | string } export function encodeCredential(credential: VerifiableCredential): Record | string { - const credentialResult = credentialWithClaimFormat(credential) - - if (credentialResult.claimFormat === ClaimFormat.SdJwtVc) { - return credentialResult.credential.compact - } - - if (credentialResult.claimFormat === ClaimFormat.MsoMdoc) { - return credentialResult.credential.base64Url - } - - return credentialResult.credential.encoded + return credential.encoded } export function credentialRecordFromCredential(credential: VerifiableCredential) { - const credentialResult = credentialWithClaimFormat(credential) - - if (credentialResult.claimFormat === ClaimFormat.SdJwtVc) { - // NOTE: temp override to use sd-jwt type metadata even if vct is old url - const typeMetadata = - credentialResult.credential.payload.vct === 'https://example.bmi.bund.de/credential/pid/1.0' - ? pidBdrSdJwtTypeMetadata - : credentialResult.credential.typeMetadata - + if (credential.claimFormat === ClaimFormat.SdJwtVc) { return new SdJwtVcRecord({ - compactSdJwtVc: credentialResult.credential.compact, - typeMetadata, + compactSdJwtVc: credential.compact, + typeMetadata: credential.typeMetadata, }) } - if (credentialResult.claimFormat === ClaimFormat.MsoMdoc) { + if (credential.claimFormat === ClaimFormat.MsoMdoc) { return new MdocRecord({ - mdoc: credentialResult.credential, + mdoc: credential, }) } return new W3cCredentialRecord({ - credential: credentialResult.credential, + credential, // We don't support expanded types right now, but would become problem when we support JSON-LD tags: {}, }) } - -export function credentialWithClaimFormat(credential: VerifiableCredential) { - // TODO: Add claim format in credo - if ('compact' in credential) { - return { - claimFormat: ClaimFormat.SdJwtVc, - credential, - } as const - } - - if (credential instanceof Mdoc) { - return { - claimFormat: ClaimFormat.MsoMdoc, - credential, - } as const - } - - return { - credential, - claimFormat: credential.claimFormat, - } as const -} diff --git a/packages/agent/src/format/disclosureFrame.ts b/packages/agent/src/format/disclosureFrame.ts new file mode 100644 index 00000000..01384d54 --- /dev/null +++ b/packages/agent/src/format/disclosureFrame.ts @@ -0,0 +1,65 @@ +import { Hasher } from '@credo-ts/core' +import { decodeSdJwtVc } from '@credo-ts/core/build/modules/sd-jwt-vc/decodeSdJwtVc' +import { decodeSdJwtSync } from '@sd-jwt/decode' +import { selectDisclosures } from '@sd-jwt/present' + +// TODO: remove once available in Credo +export function applyLimitdisclosureForSdJwtRequestedPayload( + compactSdJwtVc: string, + requestedPayload: Record +) { + const decoded = decodeSdJwtSync(compactSdJwtVc, Hasher.hash) + const presentationFrame = buildDisclosureFrameFromPayload(requestedPayload) + + const requiredDisclosures = selectDisclosures( + decoded.jwt.payload, + // Map to sd-jwt disclosure format + decoded.disclosures.map((d) => ({ + digest: d.digestSync({ alg: 'sha-256', hasher: Hasher.hash }), + encoded: d.encode(), + key: d.key, + salt: d.salt, + value: d.value, + })), + presentationFrame as { + [x: string]: boolean | undefined + } + ) + const [jwt] = compactSdJwtVc.split('~') + const sdJwt = `${jwt}~${requiredDisclosures.map((d) => d.encoded).join('~')}~` + const disclosedDecoded = decodeSdJwtVc(sdJwt) + return disclosedDecoded +} + +type DisclosureFrame = { + [key: string]: boolean | DisclosureFrame +} + +export function buildDisclosureFrameFromPayload(input: Record): DisclosureFrame { + // Handle objects recursively + const result: DisclosureFrame = {} + + // Base case: input is null or undefined + if (input === null || input === undefined) { + return result + } + + for (const [key, value] of Object.entries(input)) { + // Ignore non-value values + if (value === null || value === undefined) continue + + if (typeof value === 'object') { + if (Array.isArray(value)) { + // TODO: Array disclosure frames are not yet supported - treating entire array as disclosed + result[key] = true + } else { + result[key] = buildDisclosureFrameFromPayload(value as Record) + } + } else { + // Handle primitive values + result[key] = true + } + } + + return result +} diff --git a/packages/agent/src/format/formatPresentation.ts b/packages/agent/src/format/formatPresentation.ts index 4a1607b5..c7955bc1 100644 --- a/packages/agent/src/format/formatPresentation.ts +++ b/packages/agent/src/format/formatPresentation.ts @@ -1,94 +1,349 @@ -import { ClaimFormat, type DifPexCredentialsForRequest } from '@credo-ts/core' +import { + ClaimFormat, + type DcqlQueryResult, + type DifPexCredentialsForRequest, + type DifPresentationExchangeDefinitionV2, +} from '@credo-ts/core' +import { JSONPath } from '@astronautlabs/jsonpath' +import type { NonEmptyArray } from '@package/utils' import { - type CredentialMetadata, - type DisplayImage, - filterAndMapSdJwtKeys, + type CredentialForDisplay, + getAttributesAndMetadataForMdocPayload, + getAttributesAndMetadataForSdJwtPayload, getCredentialForDisplay, - recursivelyMapAttribues, + getDisclosedAttributePathArrays, } from '../display' +import { applyLimitdisclosureForSdJwtRequestedPayload } from './disclosureFrame' export interface FormattedSubmission { - name: string + name?: string purpose?: string areAllSatisfied: boolean entries: FormattedSubmissionEntry[] } -export interface FormattedSubmissionEntry { - /** can be either AnonCreds groupName or PEX inputDescriptorId */ +export interface FormattedSubmissionEntrySatisfiedCredential { + credential: CredentialForDisplay + + /** + * If not present the whole credential will be disclosed + */ + disclosed: { + attributes: CredentialForDisplay['attributes'] + metadata: CredentialForDisplay['metadata'] + + paths: string[][] + } +} + +export interface FormattedSubmissionEntrySatisfied { + /** + * can be either: + * - AnonCreds groupName + * - PEX inputDescriptorId + * - DCQL credential query id + */ + inputDescriptorId: string + + name?: string + description?: string + + /** + * Whether the entry is satisfied + */ + isSatisfied: true + + /** + * Credentials that match the request entry. Wallet always needs to pick one. + */ + credentials: [FormattedSubmissionEntrySatisfiedCredential, ...FormattedSubmissionEntrySatisfiedCredential[]] +} + +export interface FormattedSubmissionEntryNotSatisfied { + /** + * can be either: + * - AnonCreds groupName + * - PEX inputDescriptorId + * - DCQL credential query id + */ inputDescriptorId: string - isSatisfied: boolean - name: string + name?: string description?: string - credentials: Array<{ - id: string - credentialName: string - issuerName?: string - issuerImage?: DisplayImage - requestedAttributes?: string[] - disclosedPayload?: Record - metadata?: CredentialMetadata - backgroundColor?: string - backgroundImage?: DisplayImage - textColor?: string - claimFormat: ClaimFormat | 'AnonCreds' - }> + /** + * Whether the entry is satisfied + */ + isSatisfied: false + + requestedAttributePaths: Array> } +export type FormattedSubmissionEntry = FormattedSubmissionEntryNotSatisfied | FormattedSubmissionEntrySatisfied + export function formatDifPexCredentialsForRequest( - credentialsForRequest: DifPexCredentialsForRequest + credentialsForRequest: DifPexCredentialsForRequest, + definition: DifPresentationExchangeDefinitionV2 ): FormattedSubmission { const entries = credentialsForRequest.requirements.flatMap((requirement) => { - return requirement.submissionEntry.map((submission): FormattedSubmissionEntry => { - return { - inputDescriptorId: submission.inputDescriptorId, - name: submission.name ?? 'Unknown', - description: submission.purpose, - isSatisfied: submission.verifiableCredentials.length >= 1, - - credentials: submission.verifiableCredentials.map((verifiableCredential) => { - // FIXME: this should also just return the correct branding for the PID already. - // Will solve a lot of complexity - const { display, attributes, metadata, claimFormat } = getCredentialForDisplay( - verifiableCredential.credentialRecord - ) + // We take the first needsCount entries. Even if not satisfied we will just show these first entries as missing (otherwise it becomes too complex) + // If selection is possible they can choose alternatives within that (otherwise it becomes too complex) + const submissionEntries = requirement.submissionEntry.slice(0, requirement.needsCount) - let disclosedPayload = attributes - if (verifiableCredential.type === ClaimFormat.SdJwtVc) { - disclosedPayload = filterAndMapSdJwtKeys(verifiableCredential.disclosedPayload).visibleProperties - } else if (verifiableCredential.type === ClaimFormat.MsoMdoc) { - disclosedPayload = Object.fromEntries( - Object.values(verifiableCredential.disclosedPayload).flatMap((entry) => - Object.entries(entry).map(([key, value]) => [key, recursivelyMapAttribues(value)]) - ) + return submissionEntries.map((submission): FormattedSubmissionEntry => { + if (submission.verifiableCredentials.length >= 1) { + return { + inputDescriptorId: submission.inputDescriptorId, + name: submission.name, + description: submission.purpose, + isSatisfied: true, + credentials: submission.verifiableCredentials.map( + (verifiableCredential): FormattedSubmissionEntrySatisfiedCredential => { + const credentialForDisplay = getCredentialForDisplay(verifiableCredential.credentialRecord) + + // By default the whole credential is disclosed + let disclosed: FormattedSubmissionEntrySatisfiedCredential['disclosed'] + if (verifiableCredential.type === ClaimFormat.SdJwtVc) { + const { attributes, metadata } = getAttributesAndMetadataForSdJwtPayload( + verifiableCredential.disclosedPayload + ) + disclosed = { + attributes, + metadata, + paths: getDisclosedAttributePathArrays(attributes, 2), + } + } else if (verifiableCredential.type === ClaimFormat.MsoMdoc) { + disclosed = { + ...getAttributesAndMetadataForMdocPayload( + verifiableCredential.disclosedPayload, + verifiableCredential.credentialRecord.credential + ), + paths: getDisclosedAttributePathArrays(verifiableCredential.disclosedPayload, 2), + } + } else { + disclosed = { + attributes: credentialForDisplay.attributes, + metadata: credentialForDisplay.metadata, + paths: getDisclosedAttributePathArrays(credentialForDisplay.attributes, 2), + } + } + + return { + credential: credentialForDisplay, + disclosed, + } + } + ) as NonEmptyArray, + } + } + + // Try to determine requested attributes for credential + const inputDescriptor = definition.input_descriptors.find(({ id }) => id === submission.inputDescriptorId) + const requestedAttributePaths = + inputDescriptor?.constraints?.fields + ?.map((a) => + simplifyJsonPath(a.path[0], inputDescriptor.format?.mso_mdoc ? ClaimFormat.MsoMdoc : undefined)?.filter( + (entry): entry is string => entry !== null ) - } - - return { - id: verifiableCredential.credentialRecord.id, - credentialName: display.name, - issuerName: display.issuer.name, - issuerImage: display.issuer.logo, - requestedAttributes: [...Object.keys(disclosedPayload)], - disclosedPayload, - metadata, - backgroundColor: display.backgroundColor, - textColor: display.textColor, - backgroundImage: display.backgroundImage, - claimFormat, - } - }), + ) + .filter((path): path is string[] => path !== undefined) ?? [] + + const docType = inputDescriptor?.format?.mso_mdoc ? inputDescriptor.id : undefined + const vctField = inputDescriptor?.format?.['vc+sd-jwt'] + ? inputDescriptor.constraints.fields?.find((field) => field.path.includes('$.vct')) + : undefined + const vct = (vctField?.filter?.const ?? vctField?.filter?.enum?.[0]) as string | undefined + + return { + inputDescriptorId: submission.inputDescriptorId, + name: requirement.name ?? docType ?? vct?.replace('https://', ''), + description: requirement.purpose, + isSatisfied: false, + requestedAttributePaths: requestedAttributePaths, } }) }) return { areAllSatisfied: entries.every((entry) => entry.isSatisfied), - name: credentialsForRequest.name ?? 'Unknown', + name: credentialsForRequest.name, purpose: credentialsForRequest.purpose, entries, } } + +export function formatDcqlCredentialsForRequest(dcqlQueryResult: DcqlQueryResult): FormattedSubmission { + const credentialSets: NonNullable = dcqlQueryResult.credential_sets ?? [ + // If no credential sets are defined we create a default one with just all the credential options + { + required: true, + options: [dcqlQueryResult.credentials.map((c) => c.id)], + matching_options: dcqlQueryResult.canBeSatisfied ? [dcqlQueryResult.credentials.map((c) => c.id)] : undefined, + }, + ] + + const entries: FormattedSubmissionEntry[] = [] + for (const credentialSet of credentialSets) { + // Take first matching option, otherwise take first option + for (const credentialId of credentialSet.matching_options?.[0] ?? credentialSet.options[0]) { + const match = dcqlQueryResult.credential_matches[credentialId] + const queryCredential = dcqlQueryResult.credentials.find((c) => c.id === credentialId) + if (!queryCredential) { + throw new Error(`Credential '${credentialId}' not found in dcql query`) + } + + if (!match || !match.success) { + const placeholderCredential = extractCredentialPlaceholderFromQueryCredential(queryCredential) + entries.push({ + isSatisfied: false, + inputDescriptorId: credentialId, + name: placeholderCredential.credentialName, + requestedAttributePaths: placeholderCredential.requestedAttributePaths ?? [], + }) + continue + } + + const credentialForDisplay = getCredentialForDisplay(match.record) + + let disclosed: FormattedSubmissionEntrySatisfiedCredential['disclosed'] + if (match.output.credentialFormat === 'vc+sd-jwt') { + if (match.record.type !== 'SdJwtVcRecord') throw new Error('Expected SdJwtRecord') + + if (queryCredential.format !== 'vc+sd-jwt') { + throw new Error(`Expected queryr credential format ${queryCredential.format} to be vc+sd-jwt`) + } + + const disclosedDecoded = applyLimitdisclosureForSdJwtRequestedPayload( + match.record.compactSdJwtVc, + match.output.claims + ) + + const { attributes, metadata } = getAttributesAndMetadataForSdJwtPayload(disclosedDecoded.prettyClaims) + disclosed = { + attributes, + metadata, + paths: getDisclosedAttributePathArrays(attributes, 2), + } + } else if (match.output.credentialFormat === 'mso_mdoc') { + if (match.record.type !== 'MdocRecord') throw new Error('Expected MdocRecord') + + // FIXME: the disclosed payload here doesn't have the correct encoding anymore + // once we serialize input?? + disclosed = { + ...getAttributesAndMetadataForMdocPayload(match.output.namespaces, match.record.credential), + paths: getDisclosedAttributePathArrays(match.output.namespaces, 2), + } + } else { + if (match.record.type !== 'W3cCredentialRecord') throw new Error('Expected W3cCredentialRecord') + + // All paths disclosed for W3C + disclosed = { + attributes: credentialForDisplay.attributes, + metadata: credentialForDisplay.metadata, + paths: getDisclosedAttributePathArrays(credentialForDisplay.attributes, 2), + } + } + + entries.push({ + inputDescriptorId: credentialId, + credentials: [ + { + credential: credentialForDisplay, + disclosed, + }, + ], + isSatisfied: true, + name: credentialForDisplay.display.name, + }) + } + } + + return { + areAllSatisfied: entries.every((entry) => entry.isSatisfied), + purpose: credentialSets.map((s) => s.purpose).find((purpose): purpose is string => typeof purpose === 'string'), + entries, + } +} + +function extractCredentialPlaceholderFromQueryCredential(credential: DcqlQueryResult['credentials'][number]) { + if (credential.format === 'mso_mdoc') { + return { + claimFormat: ClaimFormat.MsoMdoc, + credentialName: credential.meta?.doctype_value ?? 'Unknown', + requestedAttributePaths: credential.claims?.map((c) => [c.claim_name]), + } + } + + if (credential.format === 'vc+sd-jwt') { + return { + claimFormat: ClaimFormat.SdJwtVc, + credentialName: credential.meta?.vct_values?.[0].replace('https://', ''), + requestedAttributePaths: credential.claims?.map((c) => c.path), + } + } + + return { + claimFormat: ClaimFormat.JwtVc, + requestedAttributePaths: credential.claims?.map((c) => c.path), + } +} + +/** + * null means the query should not be rendered + */ +function simplifyJsonPath(path: string, format?: ClaimFormat, filterKeys: string[] = []) { + try { + const parsedPath: Array<{ + scope: string + operation: string + expression: { type: string; value: string; [key: string]: unknown } + }> = JSONPath.parse(path) + + if (!Array.isArray(parsedPath)) { + return null + } + + const simplified: Array = [] + + if (format === ClaimFormat.MsoMdoc) { + if (parsedPath.length === 3) { + simplified.push(parsedPath[2].expression.value) + } + } else { + for (const entry of parsedPath) { + // Skip entries we want to remove + const value = entry.expression.value + if (['vc', 'vp', 'credentialSubject'].includes(value)) { + continue + } + + // Remove root + if (entry.expression.type === 'root') { + continue + } + + if ( + entry.expression.type === 'wildcard' || + (entry.expression.type === 'numeric_literal' && !Number.isNaN(value)) + ) { + // Replace wildcards and numeric indices with null + simplified.push(null) + } + + if (entry.expression.type === 'identifier') { + // Return the identifier value for normal entries + simplified.push(value) + } + } + } + + if (filterKeys.some((key) => simplified.includes(key))) { + return null + } + + return simplified + } catch (error) { + return null + } +} diff --git a/packages/agent/src/format/mdocRequest.ts b/packages/agent/src/format/mdocRequest.ts new file mode 100644 index 00000000..9c269add --- /dev/null +++ b/packages/agent/src/format/mdocRequest.ts @@ -0,0 +1,179 @@ +import { + DeviceRequest, + type IssuerSignedDocument, + type IssuerSignedItem, + MDoc, + parseIssuerSigned, +} from '@animo-id/mdoc' +import { TypedArrayEncoder } from '@credo-ts/core' +import type { EitherAgent } from '../agent' +import { getAttributesAndMetadataForMdocPayload, getCredentialForDisplay } from '../display' +import type { + FormattedSubmission, + FormattedSubmissionEntry, + FormattedSubmissionEntrySatisfiedCredential, +} from './formatPresentation' + +type DeviceRequestNameSpaces = DeviceRequest['docRequests'][number]['itemsRequest']['data']['nameSpaces'] + +// FIXME: needs to be exported from mdoc +export const limitDisclosureToDeviceRequestNameSpaces = ( + mdoc: IssuerSignedDocument, + deviceRequestNameSpaces: DeviceRequestNameSpaces +): Map => { + const nameSpaces: Map = new Map() + + for (const [nameSpace, nameSpaceFields] of deviceRequestNameSpaces.entries()) { + const nsAttrs = mdoc.issuerSigned.nameSpaces.get(nameSpace) ?? [] + const digests = Array.from(nameSpaceFields.entries()).map(([elementIdentifier, _]) => { + const digest = prepareDigest(elementIdentifier, nsAttrs) + if (!digest) { + throw new Error(`No matching field found for '${elementIdentifier}'`) + } + return digest + }) + + nameSpaces.set(nameSpace, digests) + } + return nameSpaces +} + +const prepareDigest = (elementIdentifier: string, nsAttrs: IssuerSignedItem[]): IssuerSignedItem | null => { + if (elementIdentifier.startsWith('age_over_')) { + const digest = handleAgeOverNN(elementIdentifier, nsAttrs) + return digest + } + + const digest = nsAttrs.find((d) => d.elementIdentifier === elementIdentifier) + return digest ?? null +} + +const handleAgeOverNN = (request: string, attributes: IssuerSignedItem[]): IssuerSignedItem | null => { + const ageOverList = attributes + .map((a, i) => { + const { elementIdentifier: key, elementValue: value } = a + return { key, value, index: i } + }) + .filter((i) => i.key.startsWith('age_over_')) + .map((i) => ({ + nn: Number.parseInt(i.key.replace('age_over_', ''), 10), + ...i, + })) + .sort((a, b) => a.nn - b.nn) + + const reqNN = Number.parseInt(request.replace('age_over_', ''), 10) + + let item: (typeof ageOverList)[number] | undefined + // Find nearest TRUE + item = ageOverList.find((i) => i.value === true && i.nn >= reqNN) + + if (!item) { + // Find the nearest False + item = ageOverList.sort((a, b) => b.nn - a.nn).find((i) => i.value === false && i.nn <= reqNN) + } + + if (!item) { + return null + } + + return attributes[item.index] +} + +export async function getSubmissionForMdocDocumentRequest( + agent: EitherAgent, + encodedDeviceRequest: Uint8Array +): Promise { + const deviceRequest = DeviceRequest.parse(encodedDeviceRequest) + + const matchingDocTypeRecords = await agent.mdoc.findAllByQuery({ + $or: deviceRequest.docRequests.map((request) => ({ + docType: request.itemsRequest.data.docType, + })), + }) + + const mdocs = matchingDocTypeRecords.map((record) => { + const mdoc = record.credential + + return { + credential: getCredentialForDisplay(record), + mdoc, + issuerSignedDocument: parseIssuerSigned(TypedArrayEncoder.fromBase64(mdoc.base64Url), mdoc.docType), + } + }) + + const entries: FormattedSubmissionEntry[] = deviceRequest.docRequests.map((docRequest): FormattedSubmissionEntry => { + const matchingMdocs = mdocs + .map((mdoc) => { + if (mdoc.mdoc.docType !== docRequest.itemsRequest.data.docType) return undefined + + try { + const disclosedNameSpaces = limitDisclosureToDeviceRequestNameSpaces( + mdoc.issuerSignedDocument, + docRequest.itemsRequest.data.nameSpaces + ) + return { + ...mdoc, + disclosedNameSpaces, + } + } catch (error) { + return undefined + } + }) + .filter((m): m is NonNullable => m !== undefined) + + if (matchingMdocs.length === 0) { + const requestedAttributePaths = Array.from(docRequest.itemsRequest.data.nameSpaces.entries()) + .flatMap(([namespace, value]) => + Array.from(value.entries()).map(([key, isDisclosed]) => (isDisclosed ? [namespace, key] : undefined)) + ) + .filter((path): path is [string, string] => path !== undefined) + + return { + inputDescriptorId: docRequest.itemsRequest.data.docType, + isSatisfied: false, + name: docRequest.itemsRequest.data.docType, + requestedAttributePaths, + } + } + + return { + // input descriptor id is doctype + inputDescriptorId: docRequest.itemsRequest.data.docType, + isSatisfied: true, + credentials: matchingMdocs.map((matchingMdoc): FormattedSubmissionEntrySatisfiedCredential => { + const disclosedAttributePaths = Array.from(matchingMdoc.disclosedNameSpaces.entries()).flatMap( + ([namespace, value]) => + Array.from(value.values()).map((issuerSignedItem) => [namespace, issuerSignedItem.elementIdentifier]) + ) + + const disclosedNamespaces = Object.fromEntries( + Array.from(matchingMdoc.disclosedNameSpaces.entries()).map(([namespace, value]) => [ + namespace, + Object.fromEntries( + Array.from(value.values()).map((issuerSignedItem) => [ + issuerSignedItem.elementIdentifier, + // TODO: what is element value here? + issuerSignedItem.elementValue, + ]) + ), + ]) + ) + const { attributes, metadata } = getAttributesAndMetadataForMdocPayload(disclosedNamespaces, matchingMdoc.mdoc) + + return { + credential: matchingMdoc.credential, + disclosed: { + attributes, + metadata, + paths: disclosedAttributePaths, + }, + } + }) as [FormattedSubmissionEntrySatisfiedCredential, ...FormattedSubmissionEntrySatisfiedCredential[]], + } + }) + + return { + areAllSatisfied: entries.every((entry) => entry.isSatisfied), + entries, + } +} diff --git a/packages/agent/src/hooks/useCredentialForDisplayById.ts b/packages/agent/src/hooks/useCredentialForDisplayById.ts index df85e23d..0eb4ec33 100644 --- a/packages/agent/src/hooks/useCredentialForDisplayById.ts +++ b/packages/agent/src/hooks/useCredentialForDisplayById.ts @@ -1,27 +1,12 @@ -import { getCredentialForDisplay } from '../display' -import { useMdocRecordById, useSdJwtVcRecordById, useW3cCredentialRecordById } from '../providers' - +import { useMemo } from 'react' +import { useCredentialsForDisplay } from './useCredentialsForDisplay' export type CredentialForDisplayId = `w3c-credential-${string}` | `sd-jwt-vc-${string}` | `mdoc-${string}` export const useCredentialForDisplayById = (credentialId: CredentialForDisplayId) => { - if (credentialId.startsWith('w3c-credential-')) { - const c = useW3cCredentialRecordById(credentialId.replace('w3c-credential-', '')) - if (!c) return null - - return getCredentialForDisplay(c) - } - if (credentialId.startsWith('sd-jwt-vc-')) { - const c = useSdJwtVcRecordById(credentialId.replace('sd-jwt-vc-', '')) - if (!c) return null + const { credentials, isLoading } = useCredentialsForDisplay({ removeCanonicalRecords: false }) - return getCredentialForDisplay(c) + return { + isLoading, + credential: useMemo(() => credentials.find((c) => c.id === credentialId), [credentials, credentialId]), } - if (credentialId.startsWith('mdoc-')) { - const c = useMdocRecordById(credentialId.replace('mdoc-', '')) - if (!c) return null - - return getCredentialForDisplay(c) - } - - return null } diff --git a/packages/agent/src/hooks/useCredentialsForDisplay.ts b/packages/agent/src/hooks/useCredentialsForDisplay.ts index 809a7f5e..77c4db32 100644 --- a/packages/agent/src/hooks/useCredentialsForDisplay.ts +++ b/packages/agent/src/hooks/useCredentialsForDisplay.ts @@ -1,11 +1,16 @@ import { useMemo } from 'react' -import { getCredentialForDisplay } from '../display' +import type { CredentialCategoryMetadata } from '../credentialCategoryMetadata' +import { type CredentialForDisplay, getCredentialForDisplay } from '../display' import { useMdocRecords, useSdJwtVcRecords, useW3cCredentialRecords } from '../providers' -export type CredentialForDisplay = ReturnType - -export const useCredentialsForDisplay = () => { +export const useCredentialsForDisplay = ({ + removeCanonicalRecords = true, + credentialCategory, +}: { + removeCanonicalRecords?: boolean + credentialCategory?: CredentialCategoryMetadata['credentialCategory'] +} = {}) => { const { w3cCredentialRecords, isLoading: isLoadingW3c } = useW3cCredentialRecords() const { sdJwtVcRecords, isLoading: isLoadingSdJwt } = useSdJwtVcRecords() const { mdocRecords, isLoading: isLoadingMdoc } = useMdocRecords() @@ -16,14 +21,48 @@ export const useCredentialsForDisplay = () => { const uniformSdJwtVcRecords = sdJwtVcRecords.map(getCredentialForDisplay) const uniformMdocRecords = mdocRecords.map(getCredentialForDisplay) - // TODO: dedupe of MDOC/SD-JWT pid need to happen somewhere + const presentCategories = new Set() + + const allRecords = [...uniformW3cCredentialRecords, ...uniformSdJwtVcRecords, ...uniformMdocRecords] + + // Make sure only one for each category is present + const finalRecords = + removeCanonicalRecords || credentialCategory + ? allRecords.filter((record, index) => { + if (credentialCategory) { + if (!record.category) return false + if (credentialCategory !== record.category.credentialCategory) return false + } + + if (removeCanonicalRecords) { + if (!record.category) return true + if (presentCategories.has(record.category.credentialCategory)) return false + + const shouldAddForCategory = + record.category.displayPriority || + allRecords + .slice(index + 1) + .find( + (r) => + r.category?.credentialCategory === record.category?.credentialCategory && + r.category?.displayPriority + ) === undefined + + if (shouldAddForCategory) { + presentCategories.add(record.category.credentialCategory) + return true + } + } + + return true + }) + : allRecords + // Sort by creation date - const sortedRecords = [...uniformW3cCredentialRecords, ...uniformSdJwtVcRecords, ...uniformMdocRecords].sort( - (a, b) => b.createdAt.getTime() - a.createdAt.getTime() - ) + const sortedRecords = finalRecords.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime()) return sortedRecords - }, [w3cCredentialRecords, sdJwtVcRecords, mdocRecords]) + }, [w3cCredentialRecords, sdJwtVcRecords, mdocRecords, removeCanonicalRecords, credentialCategory]) return { credentials, diff --git a/packages/agent/src/hooks/useDidCommPresentationActions.ts b/packages/agent/src/hooks/useDidCommPresentationActions.ts index 35d9f5c4..12f21a28 100644 --- a/packages/agent/src/hooks/useDidCommPresentationActions.ts +++ b/packages/agent/src/hooks/useDidCommPresentationActions.ts @@ -6,16 +6,22 @@ import type { AnonCredsSelectedCredentials, } from '@credo-ts/anoncreds' import type { ProofStateChangedEvent } from '@credo-ts/core' -import type { FormattedSubmission, FormattedSubmissionEntry } from '../format/formatPresentation' +import type { + FormattedSubmission, + FormattedSubmissionEntry, + FormattedSubmissionEntrySatisfiedCredential, +} from '../format/formatPresentation' -import { ClaimFormat, CredentialRepository, CredoError, ProofEventTypes, ProofState } from '@credo-ts/core' +import { CredentialRepository, CredoError, ProofEventTypes, ProofState } from '@credo-ts/core' import { useConnectionById, useProofById } from '@credo-ts/react-hooks' import { useMutation, useQuery } from '@tanstack/react-query' import { firstValueFrom } from 'rxjs' import { filter, first, timeout } from 'rxjs/operators' +import type { NonEmptyArray } from '@package/utils' import { useAgent } from '../agent' -import { getDidCommCredentialExchangeDisplayMetadata } from '../didcomm/metadata' +import { getCredentialForDisplay } from '../display' +import { getCredential } from '../storage' export function useDidCommPresentationActions(proofExchangeId: string) { const { agent } = useAgent() @@ -129,31 +135,43 @@ export function useDidCommPresentationActions(proofExchangeId: string) { mergeOrSetEntry('predicate', groupName, [formatPredicate(requestedPredicate)], predicateArray) } - const entriesArray = Array.from(entries.entries()).map(([entryHash, entry]): FormattedSubmissionEntry => { - return { - inputDescriptorId: entryHash, - credentials: entry.matches.map((match) => { - const credentialExchange = credentialExchanges.find((c) => - c.credentials.find((cc) => cc.credentialRecordId === match.credentialId) - ) - const credentialDisplayMetadata = credentialExchange - ? getDidCommCredentialExchangeDisplayMetadata(credentialExchange) - : undefined - + const entriesArray = await Promise.all( + Array.from(entries.entries()).map(async ([entryHash, entry]): Promise => { + if (entry.matches.length === 0) { return { - id: match.credentialId, - credentialName: credentialDisplayMetadata?.credentialName ?? 'Credential', - isSatisfied: true, - issuerName: credentialDisplayMetadata?.issuerName ?? 'Unknown', - requestedAttributes: Array.from(entry.requestedAttributes), - claimFormat: 'AnonCreds', + inputDescriptorId: entryHash, + isSatisfied: false, + // TODO: we can fetch the schema name based on requirements + name: 'Credential', + requestedAttributePaths: Array.from(entry.requestedAttributes).map((a) => [a]), } - }), - isSatisfied: entry.matches.length > 0, - // TODO: we can fetch the schema name based on requirements - name: 'Credential', - } - }) + } + + const credentials = (await Promise.all( + entry.matches.map(async (match): Promise => { + const credential = await getCredential(agent, `w3c-credential-${match.credentialId}`) + const credentialForDisplay = getCredentialForDisplay(credential) + + return { + credential: credentialForDisplay, + disclosed: { + // TODO: we don't show this yet on anoncreds screen, but we should add it + attributes: {}, + metadata: credentialForDisplay.metadata, + paths: Array.from(entry.requestedAttributes).map((a) => [a]), + }, + } + }) + )) as NonEmptyArray + + return { + inputDescriptorId: entryHash, + credentials, + isSatisfied: true, + name: credentials[0].credential.display.name, + } + }) + ) const submission: FormattedSubmission = { areAllSatisfied: entriesArray.every((entry) => entry.isSatisfied), diff --git a/packages/agent/src/index.ts b/packages/agent/src/index.ts index 3d695132..a9bc1c07 100644 --- a/packages/agent/src/index.ts +++ b/packages/agent/src/index.ts @@ -26,9 +26,14 @@ export * from './hooks' export { FormattedSubmission, FormattedSubmissionEntry, + FormattedSubmissionEntryNotSatisfied, + FormattedSubmissionEntrySatisfied, + FormattedSubmissionEntrySatisfiedCredential, formatDifPexCredentialsForRequest, } from './format/formatPresentation' +export { getSubmissionForMdocDocumentRequest } from './format/mdocRequest' export * from './mediation' export * from './crypto' export * from './storage' export * from './openid4vc/displayMetadata' +export * from './credentialCategoryMetadata' diff --git a/packages/agent/src/invitation/handler.ts b/packages/agent/src/invitation/handler.ts index a32f534c..bd282b47 100644 --- a/packages/agent/src/invitation/handler.ts +++ b/packages/agent/src/invitation/handler.ts @@ -1,7 +1,7 @@ import type { ConnectionRecord, CredentialStateChangedEvent, - DifPexCredentialsForRequest, + DifPresentationExchangeDefinitionV2, OutOfBandInvitation, OutOfBandRecord, P256Jwk, @@ -9,7 +9,6 @@ import type { } from '@credo-ts/core' import type { PlaintextMessage } from '@credo-ts/core/build/types' import type { - OpenId4VcSiopVerifiedAuthorizationRequest, OpenId4VciCredentialConfigurationSupportedWithFormats, OpenId4VciDpopRequestOptions, OpenId4VciRequestTokenResponse, @@ -24,7 +23,6 @@ import { V1OfferCredentialMessage, V1RequestPresentationMessage } from '@credo-t import { CredentialEventTypes, CredentialState, - Hasher, JwaSignatureAlgorithm, Jwt, OutOfBandRepository, @@ -37,7 +35,6 @@ import { } from '@credo-ts/core' import { supportsIncomingMessageType } from '@credo-ts/core/build/utils/messageType' import { - OpenId4VciHolderService, getOfferedCredentials, getScopesFromCredentialConfigurationsSupported, preAuthorizedCodeGrantIdentifier, @@ -49,7 +46,11 @@ import { Oauth2Client, getAuthorizationServerMetadataFromList } from '@animo-id/ import q from 'query-string' import { handleBatchCredential } from '../batch' import { credentialRecordFromCredential, encodeCredential } from '../format/credentialEncoding' -import { formatDifPexCredentialsForRequest } from '../format/formatPresentation' +import { + type FormattedSubmission, + formatDcqlCredentialsForRequest, + formatDifPexCredentialsForRequest, +} from '../format/formatPresentation' import { setBatchCredentialMetadata } from '../openid4vc/batchMetadata' import { getCredentialBindingResolver } from '../openid4vc/credentialBindingResolver' import { extractOpenId4VcCredentialMetadata, setOpenId4VcCredentialMetadata } from '../openid4vc/displayMetadata' @@ -436,33 +437,16 @@ export const getCredentialsForProofRequest = async ({ agent.modules.openId4VcHolder.resolveSiopAuthorizationRequest(requestUri) ) - if (!resolved.presentationExchange) { - throw new Error('No presentation exchange found in authorization request.') - } - - const formattedSubmission = formatDifPexCredentialsForRequest(resolved.presentationExchange.credentialsForRequest) - - // TODO: why do we filter? It will otherwise also just pick the first one? - // I think because of sharing activity. But that can be solved differently - // Filter to keep only the first credential for each type - const filteredSubmission = { - ...formattedSubmission, - entries: formattedSubmission.entries.map((entry) => { - const uniqueCredentials = new Map() - return { - ...entry, - credentials: entry.credentials - .filter((credential) => credential.metadata?.type) - .filter((credential) => { - const type = credential.metadata?.type - if (!uniqueCredentials.has(type)) { - uniqueCredentials.set(type, credential) - return true - } - return false - }), - } - }), + let formattedSubmission: FormattedSubmission + if (resolved.presentationExchange) { + formattedSubmission = formatDifPexCredentialsForRequest( + resolved.presentationExchange.credentialsForRequest, + resolved.presentationExchange.definition as DifPresentationExchangeDefinitionV2 + ) + } else if (resolved.dcql) { + formattedSubmission = formatDcqlCredentialsForRequest(resolved.dcql.queryResult) + } else { + throw new Error('No presentation exchange or dcql found in authorization request.') } const clientMetadata = resolved.authorizationRequest.payload?.client_metadata as @@ -474,6 +458,7 @@ export const getCredentialsForProofRequest = async ({ return { ...resolved.presentationExchange, + ...resolved.dcql, authorizationRequest: resolved.authorizationRequest, verifier: { hostName: resolved.authorizationRequest.responseURI @@ -481,52 +466,63 @@ export const getCredentialsForProofRequest = async ({ : undefined, entityId: resolved.authorizationRequest.payload?.iss as string, - logo: { - url: clientMetadata?.logo_uri, - }, + logo: clientMetadata?.logo_uri + ? { + url: clientMetadata?.logo_uri, + } + : undefined, name: clientMetadata?.client_name, }, - formattedSubmission: filteredSubmission, + formattedSubmission, } as const } export const shareProof = async ({ agent, - authorizationRequest, - credentialsForRequest, + resolvedRequest, selectedCredentials, allowUntrustedCertificate = false, }: { agent: EitherAgent - authorizationRequest: OpenId4VcSiopVerifiedAuthorizationRequest - credentialsForRequest: DifPexCredentialsForRequest + resolvedRequest: CredentialsForProofRequest selectedCredentials: { [inputDescriptorId: string]: string } allowUntrustedCertificate?: boolean }) => { - if (!credentialsForRequest.areRequirementsSatisfied) { + const { authorizationRequest } = resolvedRequest + if ( + !resolvedRequest.credentialsForRequest?.areRequirementsSatisfied && + !resolvedRequest.queryResult?.canBeSatisfied + ) { throw new Error('Requirements from proof request are not satisfied') } // Map all requirements and entries to a credential record. If a credential record for an // input descriptor has been provided in `selectedCredentials` we will use that. Otherwise // it will pick the first available credential. - const credentials = Object.fromEntries( - await Promise.all( - credentialsForRequest.requirements.flatMap((requirement) => - requirement.submissionEntry.map(async (entry) => { - const credentialId = selectedCredentials[entry.inputDescriptorId] - const credential = - entry.verifiableCredentials.find((vc) => vc.credentialRecord.id === credentialId) ?? - entry.verifiableCredentials[0] - - // Optionally use a batch credential - const credentialRecord = await handleBatchCredential(agent, credential.credentialRecord) - - return [entry.inputDescriptorId, [credentialRecord]] as [string, (typeof credentialRecord)[]] - }) + const presentationExchangeCredentials = resolvedRequest.credentialsForRequest + ? Object.fromEntries( + await Promise.all( + resolvedRequest.credentialsForRequest.requirements.flatMap((requirement) => + requirement.submissionEntry.slice(0, requirement.needsCount).map(async (entry) => { + const credentialId = selectedCredentials[entry.inputDescriptorId] + const credential = + entry.verifiableCredentials.find((vc) => vc.credentialRecord.id === credentialId) ?? + entry.verifiableCredentials[0] + + // Optionally use a batch credential + const credentialRecord = await handleBatchCredential(agent, credential.credentialRecord) + + return [entry.inputDescriptorId, [credentialRecord]] as [string, (typeof credentialRecord)[]] + }) + ) + ) ) - ) - ) + : undefined + + // TODO: support credential selection for DCQL + const dcqlCredentials = resolvedRequest.queryResult + ? agent.modules.openId4VcHolder.selectCredentialsForDcqlRequest(resolvedRequest.queryResult) + : undefined try { // Temp solution to add and remove the trusted certificate @@ -536,9 +532,16 @@ export const shareProof = async ({ const result = await withTrustedCertificate(agent, certificate, () => agent.modules.openId4VcHolder.acceptSiopAuthorizationRequest({ authorizationRequest, - presentationExchange: { - credentials, - }, + presentationExchange: presentationExchangeCredentials + ? { + credentials: presentationExchangeCredentials, + } + : undefined, + dcql: dcqlCredentials + ? { + credentials: dcqlCredentials, + } + : undefined, }) ) diff --git a/packages/agent/src/storage/credential.ts b/packages/agent/src/storage/credential.ts index ef2b8617..d33f55b3 100644 --- a/packages/agent/src/storage/credential.ts +++ b/packages/agent/src/storage/credential.ts @@ -9,10 +9,31 @@ import { import type { EitherAgent } from '../agent' import type { CredentialForDisplayId } from '../hooks' -export async function updateCredential( +type CredentialRecord = W3cCredentialRecord | SdJwtVcRecord | MdocRecord + +export async function getCredential( agent: EitherAgent, - credentialRecord: W3cCredentialRecord | SdJwtVcRecord | MdocRecord -) { + credentialId: CredentialForDisplayId +): Promise { + if (credentialId.startsWith('w3c-credential-')) { + const w3cCredentialId = credentialId.replace('w3c-credential-', '') + return agent.w3cCredentials.getCredentialRecordById(w3cCredentialId) + } + + if (credentialId.startsWith('sd-jwt-vc')) { + const sdJwtVcId = credentialId.replace('sd-jwt-vc-', '') + return agent.sdJwtVc.getById(sdJwtVcId) + } + + if (credentialId.startsWith('mdoc-')) { + const mdocId = credentialId.replace('mdoc-', '') + return agent.mdoc.getById(mdocId) + } + + throw new Error('Unsupported record type') +} + +export async function updateCredential(agent: EitherAgent, credentialRecord: CredentialRecord) { if (credentialRecord instanceof W3cCredentialRecord) { await agent.dependencyManager.resolve(W3cCredentialRepository).update(agent.context, credentialRecord) } else if (credentialRecord instanceof MdocRecord) { @@ -21,10 +42,7 @@ export async function updateCredential( await agent.dependencyManager.resolve(SdJwtVcRepository).update(agent.context, credentialRecord) } } -export async function storeCredential( - agent: EitherAgent, - credentialRecord: W3cCredentialRecord | SdJwtVcRecord | MdocRecord -) { +export async function storeCredential(agent: EitherAgent, credentialRecord: CredentialRecord) { if (credentialRecord instanceof W3cCredentialRecord) { await agent.dependencyManager.resolve(W3cCredentialRepository).save(agent.context, credentialRecord) } else if (credentialRecord instanceof MdocRecord) { diff --git a/packages/app/src/components/ActivityRowItem.tsx b/packages/app/src/components/ActivityRowItem.tsx index 9689f6d3..70316697 100644 --- a/packages/app/src/components/ActivityRowItem.tsx +++ b/packages/app/src/components/ActivityRowItem.tsx @@ -1,5 +1,5 @@ import type { ActivityType } from '@easypid/features/activity/activityRecord' -import type { DisplayImage } from '@package/agent/src' +import type { CredentialForDisplayId, DisplayImage } from '@package/agent/src' import { CustomIcons, Heading, @@ -52,7 +52,7 @@ interface ActivityRowItemProps { subtitle: string date: Date type: ActivityType - credentialId?: string + credentialId?: CredentialForDisplayId } export function ActivityRowItem({ diff --git a/packages/app/src/components/CardWithAttributes.tsx b/packages/app/src/components/CardWithAttributes.tsx index 80f8b57f..53a3817e 100644 --- a/packages/app/src/components/CardWithAttributes.tsx +++ b/packages/app/src/components/CardWithAttributes.tsx @@ -15,19 +15,17 @@ import { sanitizeString } from '@package/utils/src' import { useRouter } from 'expo-router' import { useMemo } from 'react' import { useHasInternetConnection } from '../hooks' -import { OMITTED_CREDENTIAL_ATTRIBUTES } from '../utils' import { BlurBadge } from './BlurBadge' interface CardWithAttributesProps { - id: string + id?: string name: string backgroundColor?: string textColor?: string issuerImage?: DisplayImage backgroundImage?: DisplayImage - disclosedAttributes: string[] + formattedDisclosedAttributes: string[] disclosedPayload?: Record - disableNavigation?: boolean isExpired?: boolean isRevoked?: boolean isNotYetActive?: boolean @@ -40,9 +38,8 @@ export function CardWithAttributes({ issuerImage, textColor, backgroundImage, - disclosedAttributes, + formattedDisclosedAttributes, disclosedPayload, - disableNavigation = false, isNotYetActive = false, isExpired = false, isRevoked = false, @@ -51,28 +48,24 @@ export function CardWithAttributes({ const router = useRouter() const hasInternet = useHasInternetConnection() - const filteredDisclosedAttributes = disclosedAttributes.filter( - (attribute) => !OMITTED_CREDENTIAL_ATTRIBUTES.includes(attribute) - ) - const groupedAttributes = useMemo(() => { const result: Array<[string, string | undefined]> = [] - for (let i = 0; i < filteredDisclosedAttributes.length; i += 2) { - result.push([filteredDisclosedAttributes[i], filteredDisclosedAttributes[i + 1]]) + for (let i = 0; i < formattedDisclosedAttributes.length; i += 2) { + result.push([formattedDisclosedAttributes[i], formattedDisclosedAttributes[i + 1]]) } return result - }, [filteredDisclosedAttributes]) + }, [formattedDisclosedAttributes]) const onPress = () => { router.push( `/credentials/requestedAttributes?id=${id}&disclosedPayload=${encodeURIComponent( JSON.stringify(disclosedPayload ?? {}) - )}&disclosedAttributeLength=${filteredDisclosedAttributes?.length}` + )}&disclosedAttributeLength=${formattedDisclosedAttributes?.length}` ) } const isRevokedOrExpired = isRevoked || isExpired - const disabledNav = disableNavigation || !disclosedPayload || isRevokedOrExpired + const disabledNav = !id || !disclosedPayload || isRevokedOrExpired return ( diff --git a/packages/app/src/components/SlideWizard.tsx b/packages/app/src/components/SlideWizard.tsx index 40e55b8a..ebb1315c 100644 --- a/packages/app/src/components/SlideWizard.tsx +++ b/packages/app/src/components/SlideWizard.tsx @@ -1,7 +1,7 @@ import { AnimatedStack, FlexPage, ProgressHeader, ScrollableStack, Stack } from '@package/ui' import * as Haptics from 'expo-haptics' import type React from 'react' -import { useCallback, useRef, useState } from 'react' +import { type ForwardedRef, forwardRef, useCallback, useImperativeHandle, useRef, useState } from 'react' import { Keyboard, type ScrollView } from 'react-native' import { Easing, runOnJS, useAnimatedStyle, useSharedValue, withSequence, withTiming } from 'react-native-reanimated' import { useSafeAreaInsets } from 'react-native-safe-area-context' @@ -27,155 +27,171 @@ type SlideWizardProps = { } } -export function SlideWizard({ steps, onCancel, isError, errorScreen, confirmation }: SlideWizardProps) { - const { handleScroll, isScrolledByOffset, scrollEventThrottle, onContentSizeChange, onLayout } = - useScrollViewPosition(0) - const { bottom } = useSafeAreaInsets() - const direction = useSharedValue<'forward' | 'backward'>('forward') - const opacity = useSharedValue(1) - const translateX = useSharedValue(0) - const scrollViewRef = useRef(null) - - const [currentStepIndex, setCurrentStepIndex] = useState(0) - const [isCompleted, setIsCompleted] = useState(false) - const [isSheetOpen, setIsSheetOpen] = useState(false) - const [isNavigating, setIsNavigating] = useState(false) - - const scrollToTop = useCallback(() => { - scrollViewRef.current?.scrollTo({ y: 0, animated: false }) - }, []) - - const animatedStyles = useAnimatedStyle(() => ({ - opacity: opacity.value, - transform: [{ translateX: translateX.value }], - })) - - const updateStep = useCallback( - (increment: number, slide?: string) => { - if (slide) { - const idx = steps.findIndex((step) => step.step === slide) - if (idx !== -1) { - setCurrentStepIndex(idx) - } - } else { - setCurrentStepIndex((prev) => prev + increment) - } - }, - [steps] - ) - - const animateTransition = useCallback( - (isForward: boolean, slide?: string) => { - 'worklet' - const distance = 50 - const fadeOutDuration = 250 - const delay = 100 - const fadeInDuration = 250 - - const easeOut = Easing.bezier(0.25, 0.1, 0.25, 1) - - // Fade out and translate current screen - opacity.value = withTiming(0, { duration: fadeOutDuration, easing: easeOut }, () => { - runOnJS(scrollToTop)() - runOnJS(updateStep)(isForward ? 1 : -1, slide) - }) - translateX.value = withTiming(isForward ? -distance : distance, { duration: fadeOutDuration, easing: easeOut }) - - // After fadeOutDuration + delay, fade in and translate new screen - setTimeout(() => { - opacity.value = withTiming(1, { duration: fadeInDuration, easing: easeOut }) - translateX.value = withSequence( - withTiming(isForward ? distance : -distance, { duration: 0 }), - withTiming(0, { duration: fadeInDuration, easing: easeOut }, () => { - // Reset navigation state - runOnJS(setIsNavigating)(false) - }) - ) - }, fadeOutDuration + delay) - }, - [opacity, translateX, updateStep, scrollToTop] - ) - - const handleCancel = useCallback(() => { - Keyboard.dismiss() - setIsSheetOpen(true) - }, []) - - const onConfirmCancel = () => { - setIsSheetOpen(false) - onCancel() - } +export interface SlideWizardRef { + goToNextSlide: () => void + goToSlide: (slide: string) => void +} - const onBack = useCallback(() => { - if (isNavigating) return - if (isCompleted || isError || currentStepIndex === 0 || steps[currentStepIndex].backIsCancel) { - handleCancel() - } else { - setIsNavigating(true) - direction.value = 'backward' - animateTransition(false) - void Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light) +export const SlideWizard = forwardRef( + ({ steps, onCancel, isError, errorScreen, confirmation }: SlideWizardProps, ref: ForwardedRef) => { + const { handleScroll, isScrolledByOffset, scrollEventThrottle, onContentSizeChange, onLayout } = + useScrollViewPosition(0) + const { bottom } = useSafeAreaInsets() + const direction = useSharedValue<'forward' | 'backward'>('forward') + const opacity = useSharedValue(1) + const translateX = useSharedValue(0) + const scrollViewRef = useRef(null) + + const [currentStepIndex, setCurrentStepIndex] = useState(0) + const [isCompleted, setIsCompleted] = useState(false) + const [isSheetOpen, setIsSheetOpen] = useState(false) + const [isNavigating, setIsNavigating] = useState(false) + + const scrollToTop = useCallback(() => { + scrollViewRef.current?.scrollTo({ y: 0, animated: false }) + }, []) + + const animatedStyles = useAnimatedStyle(() => ({ + opacity: opacity.value, + transform: [{ translateX: translateX.value }], + })) + + const updateStep = useCallback( + (increment: number, slide?: string) => { + if (slide) { + const idx = steps.findIndex((step) => step.step === slide) + if (idx !== -1) { + setCurrentStepIndex(idx) + } + } else { + setCurrentStepIndex((prev) => prev + increment) + } + }, + [steps] + ) + + const animateTransition = useCallback( + (isForward: boolean, slide?: string) => { + 'worklet' + const distance = 50 + const fadeOutDuration = 250 + const delay = 100 + const fadeInDuration = 250 + + const easeOut = Easing.bezier(0.25, 0.1, 0.25, 1) + + // Fade out and translate current screen + opacity.value = withTiming(0, { duration: fadeOutDuration, easing: easeOut }, () => { + runOnJS(scrollToTop)() + runOnJS(updateStep)(isForward ? 1 : -1, slide) + }) + translateX.value = withTiming(isForward ? -distance : distance, { duration: fadeOutDuration, easing: easeOut }) + + // After fadeOutDuration + delay, fade in and translate new screen + setTimeout(() => { + opacity.value = withTiming(1, { duration: fadeInDuration, easing: easeOut }) + translateX.value = withSequence( + withTiming(isForward ? distance : -distance, { duration: 0 }), + withTiming(0, { duration: fadeInDuration, easing: easeOut }, () => { + // Reset navigation state + runOnJS(setIsNavigating)(false) + }) + ) + }, fadeOutDuration + delay) + }, + [opacity, translateX, updateStep, scrollToTop] + ) + + const handleCancel = useCallback(() => { + Keyboard.dismiss() + setIsSheetOpen(true) + }, []) + + const onConfirmCancel = () => { + setIsSheetOpen(false) + onCancel() } - }, [currentStepIndex, animateTransition, direction, handleCancel, steps, isCompleted, isNavigating, isError]) - const onNext = useCallback( - (slide?: string) => { + const onBack = useCallback(() => { if (isNavigating) return - if (currentStepIndex < steps.length - 1) { + if (isCompleted || isError || currentStepIndex === 0 || steps[currentStepIndex].backIsCancel) { + handleCancel() + } else { setIsNavigating(true) - direction.value = 'forward' - animateTransition(true, slide) + direction.value = 'backward' + animateTransition(false) void Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light) } - }, - [currentStepIndex, steps.length, animateTransition, direction, isNavigating] - ) - - const completeProgressBar = useCallback(() => { - setIsCompleted(true) - void Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success) - }, []) - - const contextValue = { onNext, onBack, onCancel: handleCancel, completeProgressBar } - const Screen = isError && errorScreen ? errorScreen : steps[currentStepIndex].screen - - return ( - - - - - - - - {typeof Screen === 'function' ? : Screen} - - - - - - ) -} + }, [currentStepIndex, animateTransition, direction, handleCancel, steps, isCompleted, isNavigating, isError]) + + const onNext = useCallback( + (slide?: string) => { + if (isNavigating) return + if (currentStepIndex < steps.length - 1) { + setIsNavigating(true) + direction.value = 'forward' + animateTransition(true, slide) + void Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light) + } + }, + [currentStepIndex, steps.length, animateTransition, direction, isNavigating] + ) + + useImperativeHandle( + ref, + () => ({ + goToNextSlide: () => onNext(), + goToSlide: (slide) => onNext(slide), + }), + [onNext] + ) + + const completeProgressBar = useCallback(() => { + setIsCompleted(true) + void Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success) + }, []) + + const contextValue = { onNext, onBack, onCancel: handleCancel, completeProgressBar } + const Screen = isError && errorScreen ? errorScreen : steps[currentStepIndex].screen + + return ( + + + + + + + + {typeof Screen === 'function' ? : Screen} + + + + + + ) + } +) diff --git a/packages/app/src/features/credentials/CredentialDetailScreen.tsx b/packages/app/src/features/credentials/CredentialDetailScreen.tsx index d5d59c64..e98477e7 100644 --- a/packages/app/src/features/credentials/CredentialDetailScreen.tsx +++ b/packages/app/src/features/credentials/CredentialDetailScreen.tsx @@ -53,10 +53,9 @@ export function CredentialDetailScreen() { return null } - const credentialForDisplay = useCredentialForDisplayById(params.id) - if (!credentialForDisplay) return null - - const { attributes, display } = credentialForDisplay + const { credential } = useCredentialForDisplayById(params.id) + if (!credential) return null + const { attributes, display } = credential const onDeleteCredential = async () => { setIsLoading(true) diff --git a/packages/app/src/features/notifications/OpenIdPresentationNotificationScreen.tsx b/packages/app/src/features/notifications/OpenIdPresentationNotificationScreen.tsx index fd79b60a..9bbadede 100644 --- a/packages/app/src/features/notifications/OpenIdPresentationNotificationScreen.tsx +++ b/packages/app/src/features/notifications/OpenIdPresentationNotificationScreen.tsx @@ -68,8 +68,7 @@ export function OpenIdPresentationNotificationScreen() { shareProof({ agent, - authorizationRequest: credentialsForRequest.authorizationRequest, - credentialsForRequest: credentialsForRequest.credentialsForRequest, + resolvedRequest: credentialsForRequest, selectedCredentials, }) .then(() => { diff --git a/packages/app/src/features/notifications/components/PresentationNotificationScreen.tsx b/packages/app/src/features/notifications/components/PresentationNotificationScreen.tsx index 76f0a074..192c79d1 100644 --- a/packages/app/src/features/notifications/components/PresentationNotificationScreen.tsx +++ b/packages/app/src/features/notifications/components/PresentationNotificationScreen.tsx @@ -1,17 +1,6 @@ import type { FormattedSubmission } from '@package/agent' -import { - Button, - Heading, - LucideIcons, - Paragraph, - ScrollView, - Sheet, - Stack, - TableContainer, - XStack, - YStack, -} from '@package/ui' +import { Button, Heading, Paragraph, ScrollView, Sheet, Stack, TableContainer, XStack, YStack } from '@package/ui' import { sanitizeString } from '@package/utils' import React, { useEffect, useState } from 'react' import { useSafeAreaInsets } from 'react-native-safe-area-context' @@ -86,7 +75,9 @@ export function PresentationNotificationScreen({ {submission.entries.map((s, i) => { const selectedCredentialId = selectedCredentials[s.inputDescriptorId] - const selectedCredential = s.credentials.find((c) => c.id === selectedCredentialId) ?? s.credentials[0] + const selectedCredential = s.isSatisfied + ? s.credentials.find((c) => c.credential.id === selectedCredentialId) ?? s.credentials[0] + : undefined return ( @@ -101,10 +92,10 @@ export function PresentationNotificationScreen({ {/* // FIXME: disable credential selection until we have better UX */} @@ -124,21 +115,37 @@ export function PresentationNotificationScreen({ )} - {s.isSatisfied && selectedCredential?.requestedAttributes ? ( + {s.isSatisfied ? ( The following information will be presented: - {selectedCredential.requestedAttributes.map((a) => ( - - • {sanitizeString(a)} - - ))} + {Array.from(new Set(selectedCredential?.disclosed.paths.map((path) => path[0])))?.map( + (a) => ( + + • {sanitizeString(a)} + + ) + )} ) : ( - - This credential is not present in your wallet. - + + + This credential is not present in your wallet.{' '} + {s.requestedAttributePaths.length > 0 ? 'The folloing information is requested:' : ''} + + {s.requestedAttributePaths.length > 0 && ( + + {Array.from(new Set(s.requestedAttributePaths.map((p) => p[0]))) + .filter((a): a is string => typeof a === 'string') + .map((a) => ( + + • {sanitizeString(a)} + + ))} + + )} + )} @@ -170,19 +177,20 @@ export function PresentationNotificationScreen({ Select the credential you want to use - {currentSubmissionEntry?.credentials.map((c, credentialIndex) => ( - { - onSelectCredentialForInputDescriptor(currentSubmissionEntry.inputDescriptorId, c.id) - setChangeSubmissionCredentialIndex(-1) - }} - key={c.id} - issuer={c.issuerName} - name={c.credentialName} - hideBorder={credentialIndex === currentSubmissionEntry.credentials.length - 1} - bgColor={c.backgroundColor} - /> - ))} + {currentSubmissionEntry?.isSatisfied && + currentSubmissionEntry?.credentials.map((c, credentialIndex) => ( + { + onSelectCredentialForInputDescriptor(currentSubmissionEntry.inputDescriptorId, c.credential.id) + setChangeSubmissionCredentialIndex(-1) + }} + key={c.credential.id} + issuer={c.credential.display.issuer.name} + name={c.credential.display.name} + hideBorder={credentialIndex === currentSubmissionEntry.credentials.length - 1} + bgColor={c.credential.display.backgroundColor} + /> + ))} diff --git a/packages/ui/src/content/Icon.tsx b/packages/ui/src/content/Icon.tsx index 3f08dac8..1ecb2764 100644 --- a/packages/ui/src/content/Icon.tsx +++ b/packages/ui/src/content/Icon.tsx @@ -18,7 +18,6 @@ import { ArrowLeftIcon, ArrowPathIcon, ArrowRightIcon, - ArrowTopRightOnSquareIcon, ArrowsRightLeftIcon, BackspaceIcon, Bars3Icon, @@ -28,6 +27,7 @@ import { CheckIcon, ChevronRightIcon, CircleStackIcon, + CloudIcon, Cog8ToothIcon, CreditCardIcon, DevicePhoneMobileIcon, @@ -174,6 +174,7 @@ export const HeroIcons = { CameraFilled: wrapHeroIcon(CameraFilledIcon), MagnifyingGlass: wrapHeroIcon(MagnifyingGlassIcon), Link: wrapHeroIcon(LinkIcon), + Cloud: wrapHeroIcon(CloudIcon), } as const export const CustomIcons = { diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts index 444a5e9b..ef633dc7 100644 --- a/packages/utils/src/index.ts +++ b/packages/utils/src/index.ts @@ -2,3 +2,4 @@ export * from './format' export * from './url' export * from './sleep' export * from './image' +export * from './types' diff --git a/packages/utils/src/types.ts b/packages/utils/src/types.ts new file mode 100644 index 00000000..9590d038 --- /dev/null +++ b/packages/utils/src/types.ts @@ -0,0 +1,3 @@ +export type NonEmptyArray = [T, ...T[]] + +export const excludeUndefined = (value: T): value is NonNullable => value !== undefined && value !== null diff --git a/patches/@animo-id__mdoc@0.2.38.patch b/patches/@animo-id__mdoc@0.2.38.patch deleted file mode 100644 index e947d066..00000000 --- a/patches/@animo-id__mdoc@0.2.38.patch +++ /dev/null @@ -1,86 +0,0 @@ -diff --git a/dist/index.js b/dist/index.js -index e1fd0582c0c7659b1f6159e630d9b06b40a91eb6..31594d4eefd90f1018ec168a2d114939489afe32 100644 ---- a/dist/index.js -+++ b/dist/index.js -@@ -3411,22 +3411,23 @@ var DeviceSignedDocument = class extends IssuerSignedDocument { - const doc = super.prepare(); - const deviceSignature = this.deviceSigned.deviceAuth.deviceSignature?.getContentForEncoding(); - const deviceMac = this.deviceSigned.deviceAuth.deviceMac?.getContentForEncoding(); -- if (deviceMac) { -- deviceMac[2] = void 0; -- } -- if (deviceSignature) { -- deviceSignature[2] = void 0; -- } -+ - doc.set("deviceSigned", { - ...this.deviceSigned, - nameSpaces: DataItem.fromData(this.deviceSigned.nameSpaces), - // TODO: ERRORS MISSING - deviceAuth: { - ...this.deviceSigned.deviceAuth, -- deviceSignature, -+ deviceSignature: [...deviceSignature], - deviceMac - } - }); -+ if (deviceMac) { -+ deviceMac[2] = undefined; -+ } -+ if (deviceSignature) { -+ deviceSignature[2] = undefined; -+ } - return doc; - } - /** -@@ -4039,6 +4040,7 @@ var DeviceResponse = class _DeviceResponse { - jwk: this.devicePrivateKey - }); - sign1.signature = signature; -+ sign1.payload = null; - return { deviceSignature: sign1 }; - } - }; -diff --git a/dist/index.mjs b/dist/index.mjs -index d39f75a60c8169c070f31b95705e18116fc50e7a..2e52066c847afd23deb2f4f18dc6cad0fd5e3512 100644 ---- a/dist/index.mjs -+++ b/dist/index.mjs -@@ -3361,22 +3361,23 @@ var DeviceSignedDocument = class extends IssuerSignedDocument { - const doc = super.prepare(); - const deviceSignature = this.deviceSigned.deviceAuth.deviceSignature?.getContentForEncoding(); - const deviceMac = this.deviceSigned.deviceAuth.deviceMac?.getContentForEncoding(); -- if (deviceMac) { -- deviceMac[2] = void 0; -- } -- if (deviceSignature) { -- deviceSignature[2] = void 0; -- } -+ - doc.set("deviceSigned", { - ...this.deviceSigned, - nameSpaces: DataItem.fromData(this.deviceSigned.nameSpaces), - // TODO: ERRORS MISSING - deviceAuth: { - ...this.deviceSigned.deviceAuth, -- deviceSignature, -+ deviceSignature: [...deviceSignature], - deviceMac - } - }); -+ if (deviceMac) { -+ deviceMac[2] = undefined; -+ } -+ if (deviceSignature) { -+ deviceSignature[2] = undefined; -+ } - return doc; - } - /** -@@ -3989,6 +3990,7 @@ var DeviceResponse = class _DeviceResponse { - jwk: this.devicePrivateKey - }); - sign1.signature = signature; -+ sign1.payload = null; - return { deviceSignature: sign1 }; - } - }; diff --git a/patches/@credo-ts__askar@0.6.0-alpha-20241120153226.patch b/patches/@credo-ts__askar@0.6.0-pr-2100-20241124170219.patch similarity index 100% rename from patches/@credo-ts__askar@0.6.0-alpha-20241120153226.patch rename to patches/@credo-ts__askar@0.6.0-pr-2100-20241124170219.patch diff --git a/patches/@sphereon__kmp-mdl-mdoc.patch b/patches/@sphereon__kmp-mdl-mdoc.patch new file mode 100644 index 00000000..2a4ce2ce --- /dev/null +++ b/patches/@sphereon__kmp-mdl-mdoc.patch @@ -0,0 +1,26 @@ +diff --git a/Kermit-kermit-core.js b/Kermit-kermit-core.js +index 93569e524f6b1242126e7af92704eb8b79b55147..3c3a45cee75f78bee5d0bab2af03fdc037f59c1a 100644 +--- a/Kermit-kermit-core.js ++++ b/Kermit-kermit-core.js +@@ -278,7 +278,7 @@ + console.info(output); + }; + protoOf(ConsoleActual).t2c = function (output) { +- console.log(output); ++ // console.log(output); + }; + var ConsoleActual_instance; + function ConsoleActual_getInstance() { +diff --git a/kotlin-kotlin-stdlib.js b/kotlin-kotlin-stdlib.js +index 790ac68db8a3209bebee844156ca2fd39b20d4f4..e9d838571fc0480bc156eb6568044397a2768be0 100644 +--- a/kotlin-kotlin-stdlib.js ++++ b/kotlin-kotlin-stdlib.js +@@ -5799,7 +5799,7 @@ if (typeof String.prototype.startsWith === 'undefined') { + this.f9_1 = this.f9_1 + s; + }; + protoOf(BufferedOutputToConsoleLog).g9 = function () { +- console.log(this.f9_1); ++ // console.log(this.f9_1); + this.f9_1 = ''; + }; + function BufferedOutput() { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 13314181..70d705db 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -16,35 +16,35 @@ catalogs: specifier: 0.1.0-alpha.11 version: 0.1.0-alpha.11 '@animo-id/mdoc': - specifier: 0.2.38 - version: 0.2.38 + specifier: 0.2.39 + version: 0.2.39 '@credo-ts/anoncreds': - specifier: 0.6.0-alpha-20241120153226 - version: 0.6.0-alpha-20241120153226 + specifier: 0.6.0-pr-2100-20241124170219 + version: 0.6.0-pr-2100-20241124170219 '@credo-ts/askar': - specifier: 0.6.0-alpha-20241120153226 - version: 0.6.0-alpha-20241120153226 + specifier: 0.6.0-pr-2100-20241124170219 + version: 0.6.0-pr-2100-20241124170219 '@credo-ts/cheqd': - specifier: 0.6.0-alpha-20241120153226 - version: 0.6.0-alpha-20241120153226 + specifier: 0.6.0-pr-2100-20241124170219 + version: 0.6.0-pr-2100-20241124170219 '@credo-ts/core': - specifier: 0.6.0-alpha-20241120153226 - version: 0.6.0-alpha-20241120153226 + specifier: 0.6.0-pr-2100-20241124170219 + version: 0.6.0-pr-2100-20241124170219 '@credo-ts/indy-vdr': - specifier: 0.6.0-alpha-20241120153226 - version: 0.6.0-alpha-20241120153226 + specifier: 0.6.0-pr-2100-20241124170219 + version: 0.6.0-pr-2100-20241124170219 '@credo-ts/openid4vc': - specifier: 0.6.0-alpha-20241120153226 - version: 0.6.0-alpha-20241120153226 + specifier: 0.6.0-pr-2100-20241124170219 + version: 0.6.0-pr-2100-20241124170219 '@credo-ts/question-answer': - specifier: 0.6.0-alpha-20241120153226 - version: 0.6.0-alpha-20241120153226 + specifier: 0.6.0-pr-2100-20241124170219 + version: 0.6.0-pr-2100-20241124170219 '@credo-ts/react-hooks': specifier: 0.6.1 version: 0.6.1 '@credo-ts/react-native': - specifier: 0.6.0-alpha-20241120153226 - version: 0.6.0-alpha-20241120153226 + specifier: 0.6.0-pr-2100-20241124170219 + version: 0.6.0-pr-2100-20241124170219 '@hyperledger/anoncreds-react-native': specifier: ^0.2.4 version: 0.2.4 @@ -71,20 +71,23 @@ overrides: '@unimodules/react-native-adapter': ./noop '@unimodules/core': ./noop react-docgen-typescript: 2.2.2 - '@animo-id/oid4vci': 0.1.4-alpha-20241120145259 - '@animo-id/oauth2': 0.1.4-alpha-20241120145259 - '@animo-id/oauth2-utils': 0.1.4-alpha-20241120145259 + '@sphereon/did-auth-siop': https://gitpkg.vercel.app/animo/OID4VC/packages/siop-oid4vp?funke + '@sphereon/jarm': https://gitpkg.vercel.app/animo/OID4VC/packages/jarm?funke + '@sphereon/oid4vc-common': https://gitpkg.vercel.app/animo/OID4VC/packages/common?funke + '@animo-id/oid4vci': 0.1.4 + '@animo-id/oauth2': 0.1.4 + '@animo-id/oauth2-utils': 0.1.4 patchedDependencies: - '@animo-id/mdoc@0.2.38': - hash: zifb323ygrtdb6olnw5okh7czy - path: patches/@animo-id__mdoc@0.2.38.patch - '@credo-ts/askar@0.6.0-alpha-20241120153226': + '@credo-ts/askar@0.6.0-pr-2100-20241124170219': hash: zbu2rcss5evxukkhh5w5venkba - path: patches/@credo-ts__askar@0.6.0-alpha-20241120153226.patch + path: patches/@credo-ts__askar@0.6.0-pr-2100-20241124170219.patch '@hyperledger/indy-vdr-react-native@0.2.2': hash: jtxhiuxe2e3i7qwlurpufqwh5a path: patches/@hyperledger__indy-vdr-react-native@0.2.2.patch + '@sphereon/kmp-mdl-mdoc': + hash: 7x5lo6qr5h5rmsca3oezb2kbdy + path: patches/@sphereon__kmp-mdl-mdoc.patch importers: @@ -107,16 +110,16 @@ importers: version: 0.0.1-alpha.14(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.74.6(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.2.79)(react@18.3.1))(react@18.3.1) '@animo-id/expo-mdoc-data-transfer': specifier: 'catalog:' - version: 0.0.3-alpha.7(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.2.79)(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react@18.3.1) + version: 0.0.3-alpha.7(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react@18.3.1) '@animo-id/expo-secure-environment': specifier: 'catalog:' version: 0.1.0-alpha.11(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.74.6(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.2.79)(react@18.3.1))(react@18.3.1) '@animo-id/mdoc': specifier: 'catalog:' - version: 0.2.38(patch_hash=zifb323ygrtdb6olnw5okh7czy) + version: 0.2.39 '@credo-ts/core': specifier: 'catalog:' - version: 0.6.0-alpha-20241120153226(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.74.6(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.2.79)(react@18.3.1))(web-streams-polyfill@3.3.3) + version: 0.6.0-pr-2100-20241124170219(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.74.6(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.2.79)(react@18.3.1))(typescript@5.3.3)(web-streams-polyfill@3.3.3) '@expo-google-fonts/open-sans': specifier: ^0.2.3 version: 0.2.3 @@ -580,38 +583,41 @@ importers: packages/agent: dependencies: '@animo-id/oauth2': - specifier: 0.1.4-alpha-20241120145259 - version: 0.1.4-alpha-20241120145259(typescript@5.3.3) + specifier: 0.1.4 + version: 0.1.4(typescript@5.3.3) '@animo-id/oid4vci': - specifier: 0.1.4-alpha-20241120145259 - version: 0.1.4-alpha-20241120145259(typescript@5.3.3) + specifier: 0.1.4 + version: 0.1.4(typescript@5.3.3) + '@astronautlabs/jsonpath': + specifier: ^1.1.2 + version: 1.1.2 '@credo-ts/anoncreds': specifier: 'catalog:' - version: 0.6.0-alpha-20241120153226(@hyperledger/anoncreds-shared@0.2.4)(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1))(web-streams-polyfill@3.3.3) + version: 0.6.0-pr-2100-20241124170219(@hyperledger/anoncreds-shared@0.2.4)(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1))(typescript@5.3.3)(web-streams-polyfill@3.3.3) '@credo-ts/askar': specifier: 'catalog:' - version: 0.6.0-alpha-20241120153226(patch_hash=zbu2rcss5evxukkhh5w5venkba)(@hyperledger/aries-askar-shared@0.2.3)(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1))(web-streams-polyfill@3.3.3) + version: 0.6.0-pr-2100-20241124170219(patch_hash=zbu2rcss5evxukkhh5w5venkba)(@hyperledger/aries-askar-shared@0.2.3)(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1))(typescript@5.3.3)(web-streams-polyfill@3.3.3) '@credo-ts/cheqd': specifier: 'catalog:' - version: 0.6.0-alpha-20241120153226(@hyperledger/anoncreds-shared@0.2.4)(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1))(web-streams-polyfill@3.3.3) + version: 0.6.0-pr-2100-20241124170219(@hyperledger/anoncreds-shared@0.2.4)(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1))(typescript@5.3.3)(web-streams-polyfill@3.3.3) '@credo-ts/core': specifier: 'catalog:' - version: 0.6.0-alpha-20241120153226(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1))(web-streams-polyfill@3.3.3) + version: 0.6.0-pr-2100-20241124170219(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1))(typescript@5.3.3)(web-streams-polyfill@3.3.3) '@credo-ts/indy-vdr': specifier: 'catalog:' - version: 0.6.0-alpha-20241120153226(@hyperledger/anoncreds-shared@0.2.4)(@hyperledger/indy-vdr-shared@0.2.2)(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1))(web-streams-polyfill@3.3.3) + version: 0.6.0-pr-2100-20241124170219(@hyperledger/anoncreds-shared@0.2.4)(@hyperledger/indy-vdr-shared@0.2.2)(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1))(typescript@5.3.3)(web-streams-polyfill@3.3.3) '@credo-ts/openid4vc': specifier: 'catalog:' - version: 0.6.0-alpha-20241120153226(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1))(typescript@5.3.3)(web-streams-polyfill@3.3.3) + version: 0.6.0-pr-2100-20241124170219(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1))(typescript@5.3.3)(web-streams-polyfill@3.3.3) '@credo-ts/question-answer': specifier: 'catalog:' - version: 0.6.0-alpha-20241120153226(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1))(web-streams-polyfill@3.3.3) + version: 0.6.0-pr-2100-20241124170219(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1))(typescript@5.3.3)(web-streams-polyfill@3.3.3) '@credo-ts/react-hooks': specifier: 'catalog:' - version: 0.6.1(@credo-ts/core@0.6.0-alpha-20241120153226(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1))(web-streams-polyfill@3.3.3))(@credo-ts/question-answer@0.6.0-alpha-20241120153226(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1))(web-streams-polyfill@3.3.3))(react@18.3.1) + version: 0.6.1(@credo-ts/core@0.6.0-pr-2100-20241124170219(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1))(typescript@5.3.3)(web-streams-polyfill@3.3.3))(@credo-ts/question-answer@0.6.0-pr-2100-20241124170219(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1))(typescript@5.3.3)(web-streams-polyfill@3.3.3))(react@18.3.1) '@credo-ts/react-native': specifier: 'catalog:' - version: 0.6.0-alpha-20241120153226(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native-fs@2.20.0(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1)))(react-native-get-random-values@1.11.0(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1)))(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1))(web-streams-polyfill@3.3.3) + version: 0.6.0-pr-2100-20241124170219(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native-fs@2.20.0(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1)))(react-native-get-random-values@1.11.0(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1)))(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1))(typescript@5.3.3)(web-streams-polyfill@3.3.3) '@hyperledger/anoncreds-react-native': specifier: 'catalog:' version: 0.2.4(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1))(react@18.3.1) @@ -629,7 +635,7 @@ importers: version: 5.59.16(react@18.3.1) credo-ts-didweb-anoncreds: specifier: 0.0.1-alpha.13 - version: 0.0.1-alpha.13(@credo-ts/anoncreds@0.6.0-alpha-20241120153226(@hyperledger/anoncreds-shared@0.2.4)(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1))(web-streams-polyfill@3.3.3))(@credo-ts/core@0.6.0-alpha-20241120153226(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1))(web-streams-polyfill@3.3.3))(@hyperledger/anoncreds-shared@0.2.4) + version: 0.0.1-alpha.13(@credo-ts/anoncreds@0.6.0-pr-2100-20241124170219(@hyperledger/anoncreds-shared@0.2.4)(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1))(typescript@5.3.3)(web-streams-polyfill@3.3.3))(@credo-ts/core@0.6.0-pr-2100-20241124170219(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1))(typescript@5.3.3)(web-streams-polyfill@3.3.3))(@hyperledger/anoncreds-shared@0.2.4) expo: specifier: 'catalog:' version: 51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)) @@ -822,14 +828,14 @@ packages: resolution: {integrity: sha512-LJJyuVvljHqrzEjm0MtVx/SgH4Q+dWilzI1cxb1QqsMUWJgDfB9on3+/hJKSnleeaTR5VcByEudWcgR45424wQ==} peerDependencies: expo: '*' - react: 18.2.0 - react-native: 0.74.5 + react: '*' + react-native: '*' '@animo-id/expo-mdoc-data-transfer@0.0.3-alpha.7': resolution: {integrity: sha512-owHGj02XzGeBsHLi8ZJyN8AiiS4rgO22oFlKuZPyrmylUemz15CzB2tnIa8W1KKM7MnCrWXENFV5a6VC/gLqag==} peerDependencies: expo: '>= 51' - react: 18.3.1 + react: '*' '@animo-id/expo-secure-environment@0.1.0-alpha.11': resolution: {integrity: sha512-cAwsK8QWZc4ywxH6r0sqrH5yGdp5bKkw3fUr41CSs/TDZ42FIMeIK+tEdc78Bp+szykEywnnZpaAKdoTAd3ebw==} @@ -838,17 +844,21 @@ packages: react: '*' react-native: '*' - '@animo-id/mdoc@0.2.38': - resolution: {integrity: sha512-98KQ0jvwTYsFOffTGvvHXBDo23b5xmhYjPiMIX6e807I6iS4fZZ9ypfBySdA5IiGUvXELKqEv27AUaayQa/9bg==} + '@animo-id/mdoc@0.2.39': + resolution: {integrity: sha512-Fn+ltm086U8xentP4aJtGksfRFXa5YMg9/stAfDLgfpoue2gKaitwKUk7/shrl+bV1t1m5qdhKVcJ0uVMk/nLA==} + + '@animo-id/oauth2-utils@0.1.4': + resolution: {integrity: sha512-JUIshkNCiX7myPwdiE+Da/g77OjsxZreezmfXWBSWOgCOZrnQX+t5vkhpe6Jc6DRh40Y8r9Fa1AesV0vtVpUMg==} - '@animo-id/oauth2-utils@0.1.4-alpha-20241120145259': - resolution: {integrity: sha512-gbc2bOpnM101KTmVtZJwbo9IAn3bn5Ah1UMUdQbdxD8M2DPAMuvM1j4JxVsIn46DGoPUWW0uGspGXAjxFv2x5g==} + '@animo-id/oauth2@0.1.4': + resolution: {integrity: sha512-7FgiSJpkuWrMmYfh39VHcqbuQIsY3Xm66IUQiGBgy4g4DvMnRZ2Orj4LNrEnlr8qUnk4GDJ56zW2Bp55T70gSQ==} - '@animo-id/oauth2@0.1.4-alpha-20241120145259': - resolution: {integrity: sha512-w3lCkPh0I15Nbq0RZvQTBreDLcsIicCXmeNRUQx3xrrd25+GSaBoIMQel299I07ozDjDn9VptMCJGXNSSNBMyw==} + '@animo-id/oid4vci@0.1.4': + resolution: {integrity: sha512-0Tc8RFpY5dW/MOVA2Fz8f7giM/eIAk3G3OZUjy5POqg5Tkiv92CcaOxMk84JBNAMOks3LpKjf9PAiNh6pCDzeQ==} - '@animo-id/oid4vci@0.1.4-alpha-20241120145259': - resolution: {integrity: sha512-OkqVn2XSlyMYZV+WyPcjh7Iz9dJx6ZTYlMiIc4/qM3j5cQeVf70wKwVZLzBLMrdiQWBw2l+AC7cPtTjl25F/MA==} + '@animo-id/pex@4.1.1-alpha.0': + resolution: {integrity: sha512-6ieHhH9UE9DLFOJegMCabG3qUFlQk4TLhBefxInpyjx2Ly6kuloVMScJYcnQTs/E6nuHGMd7ebUaKy4+0+ZbOA==} + engines: {node: '>=18'} '@astronautlabs/jsonpath@1.1.2': resolution: {integrity: sha512-FqL/muoreH7iltYC1EB5Tvox5E8NSOOPGkgns4G+qxRKl6k5dxEVljUjB5NcKESzkqwnUqWjSZkL61XGYOuV+A==} @@ -1738,13 +1748,13 @@ packages: '@cosmjs/utils@0.30.1': resolution: {integrity: sha512-KvvX58MGMWh7xA+N+deCfunkA/ZNDvFLw4YbOmX3f/XBIkqrVY7qlotfy2aNb1kgp6h4B6Yc8YawJPDTfvWX7g==} - '@credo-ts/anoncreds@0.6.0-alpha-20241120153226': - resolution: {integrity: sha512-9E1iQGqzdGGoELuoysSymJ9ZBkF4aZkok6HDqs6h3kJB1qHgBPw005SVHXN0+5ABVxJJo9/C7ENAEv5VAZ+2KQ==} + '@credo-ts/anoncreds@0.6.0-pr-2100-20241124170219': + resolution: {integrity: sha512-2b7yX0U1VE6dG3bhzOkz1b5y1JGPQK5XcZ+jvJEcvEdZeqEcaSt6z7636ziEUMzpj5fx6zGSa1xl37kFq7yWtQ==} peerDependencies: '@hyperledger/anoncreds-shared': ^0.2.2 - '@credo-ts/askar@0.6.0-alpha-20241120153226': - resolution: {integrity: sha512-oTIjsSON8uWHnFQueOMTVuv8uXbOo+xJ/QxIs8znmbMRiCTsDPDxHTlMOAmpXPv62yknSKPjRPkjzgeUg8X6JQ==} + '@credo-ts/askar@0.6.0-pr-2100-20241124170219': + resolution: {integrity: sha512-a0HFwnjjOAMcMT2W3GWNhcYHdozSaA9QAcOt0VP/qD1SEnw853nknNy7b+JwYOo2e6NwsD55CnuXb7ZAlY7aTQ==} peerDependencies: '@animo-id/expo-secure-environment': ^0.0.1-alpha.0 '@hyperledger/aries-askar-shared': ^0.2.3 @@ -1752,32 +1762,32 @@ packages: '@animo-id/expo-secure-environment': optional: true - '@credo-ts/cheqd@0.6.0-alpha-20241120153226': - resolution: {integrity: sha512-VVuxM0kutWyQbaimOHVMuiJ4nqEQkQOYyPg7RbWX4LOwSxWnxIOzTzhhm5j6xUJ6yGu7T8lcvI8Hx3zLVDzFiw==} + '@credo-ts/cheqd@0.6.0-pr-2100-20241124170219': + resolution: {integrity: sha512-60/zISZ0+MHuXLAn5Zp44/BazjJhSQI0KgMcZIy4fQiFmamHcGc/Q+xYApn8IFoAgM/dhEU/myY8UlrWCTkvzg==} - '@credo-ts/core@0.6.0-alpha-20241120153226': - resolution: {integrity: sha512-j0my549nfyo+AizUkgvMWLcAbBtd41WhXRLfSHlfr7cZlNc4CmPSV9BUKjmeBoPGW9kWl778GlhWt4sCdxvkhA==} + '@credo-ts/core@0.6.0-pr-2100-20241124170219': + resolution: {integrity: sha512-X5p9F+MlLBJmjrQm2Jdn8V+Iodw2hD1qXb/aWeUqhPIvgB+0IuC0OX18Rxz31TEPNUESgH746tDC5/csLLFOPw==} - '@credo-ts/indy-vdr@0.6.0-alpha-20241120153226': - resolution: {integrity: sha512-rYkXp2754hbKz4UUC5UNy3N6tPfB9rHrZildGo0qXuKCGhJZpJ7Ut96LT3VcoPRPvXw4nmSMniiCusYaeEd2fQ==} + '@credo-ts/indy-vdr@0.6.0-pr-2100-20241124170219': + resolution: {integrity: sha512-sqyH513GNl8RwMvxowYSng69rT3Pgb5KQA3G7fsKwIo1u+A2PeoCyDKjIcMA2jXpe4J8kN2nNNIYfGK6L8rFdw==} peerDependencies: '@hyperledger/indy-vdr-shared': ^0.2.2 - '@credo-ts/openid4vc@0.6.0-alpha-20241120153226': - resolution: {integrity: sha512-GWE1bZqc1TDXCidGnpy+lyo0UVhIgD3xaoytYj4Z8iYF7B+m6BFU0zw1yFtiEFxRn25+vTLeYw+KVVzVLlyOww==} + '@credo-ts/openid4vc@0.6.0-pr-2100-20241124170219': + resolution: {integrity: sha512-xQ0QaPHpf7t1+VF0RkU87GpfVsAvBGhJobDE1QeJ1Qk7VLXvpea7IMHKVzwSsbXXGU9xqs7+bG1L+IM+SxNvZw==} - '@credo-ts/question-answer@0.6.0-alpha-20241120153226': - resolution: {integrity: sha512-ZlGrPYs2sP51IIgMpG6YZ27KHEhDIdBScvMl2HtxjkveRX3zoZmU9nq2W74xL4alHHTPTGT83YnIXVpTdkDJ6w==} + '@credo-ts/question-answer@0.6.0-pr-2100-20241124170219': + resolution: {integrity: sha512-Ezu5jmS+jrui5IkuBd/oxVOuwD5O6ayHZaURAtKYHeffh2xgmRzjfVIi4O/ABoxzO8qlxq2x75NydhxyzdIyOw==} '@credo-ts/react-hooks@0.6.1': resolution: {integrity: sha512-lZt1N5oKzYfh9DMUBauX9Q2irJPxbztfK9zkYU93mhSV7jF5up0X/TdWxj85l9Guu7iL84JDQJY11CpIHquPOQ==} peerDependencies: - '@credo-ts/core': https://gitpkg.vercel.app/animo/aries-framework-javascript/packages/core?funke - '@credo-ts/question-answer': https://gitpkg.vercel.app/animo/aries-framework-javascript/packages/question-answer?funke - react: 18.2.0 + '@credo-ts/core': ^0.5.0 + '@credo-ts/question-answer': ^0.5.0 + react: '>=17.0.0 <19.0.0' - '@credo-ts/react-native@0.6.0-alpha-20241120153226': - resolution: {integrity: sha512-VvSb/SX02w+fQ6d4Uqb8zzLIX4ocDd6YRbOvHEAIoL3tZoaYAkdsNk8E4WmKK2mG83uCY0HBfqqwroPIa3FrYw==} + '@credo-ts/react-native@0.6.0-pr-2100-20241124170219': + resolution: {integrity: sha512-dS7vNpTTHR94GIfDiRC34xrzN4xU2fCEo26U/1gVtkkB74upYnDIwSWrvngzsTz5LVUBCDsNiom+Ihe3gYmZUQ==} peerDependencies: react-native: '>=0.71.4' react-native-fs: ^2.20.0 @@ -1871,7 +1881,7 @@ packages: '@emotion/use-insertion-effect-with-fallbacks@1.1.0': resolution: {integrity: sha512-+wBOcIV5snwGgI2ya3u99D7/FJquOIniQT1IKyDsBmEgwvpxMNeS65Oib7OnE2d2aY+3BU4OiH+0Wchf8yk3Hw==} peerDependencies: - react: 18.2.0 + react: '>=16.8.0' '@esbuild/aix-ppc64@0.19.12': resolution: {integrity: sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==} @@ -2287,45 +2297,6 @@ packages: cpu: [x64] os: [win32] - '@ethersproject/address@5.7.0': - resolution: {integrity: sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA==} - - '@ethersproject/bignumber@5.7.0': - resolution: {integrity: sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw==} - - '@ethersproject/bytes@5.7.0': - resolution: {integrity: sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A==} - - '@ethersproject/constants@5.7.0': - resolution: {integrity: sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA==} - - '@ethersproject/keccak256@5.7.0': - resolution: {integrity: sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg==} - - '@ethersproject/logger@5.7.0': - resolution: {integrity: sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig==} - - '@ethersproject/networks@5.7.1': - resolution: {integrity: sha512-n/MufjFYv3yFcUyfhnXotyDlNdFb7onmkSy8aQERi2PjNcnWQ66xXxa3XlS8nCcA8aJKJjIIMNJTC7tu80GwpQ==} - - '@ethersproject/properties@5.7.0': - resolution: {integrity: sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw==} - - '@ethersproject/random@5.7.0': - resolution: {integrity: sha512-19WjScqRA8IIeWclFme75VMXSBvi4e6InrUNuaR4s5pTF2qNhcGdCUwdxUVGtDDqC00sDLCO93jPQoDUH4HVmQ==} - - '@ethersproject/rlp@5.7.0': - resolution: {integrity: sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w==} - - '@ethersproject/signing-key@5.7.0': - resolution: {integrity: sha512-MZdy2nL3wO0u7gkB4nA/pEf8lu1TlFswPNmy8AiYkfKTdO6eXBJyUdmHO/ehm/htHw9K/qF8ujnTyUAD+Ry54Q==} - - '@ethersproject/strings@5.7.0': - resolution: {integrity: sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg==} - - '@ethersproject/transactions@5.7.0': - resolution: {integrity: sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ==} - '@expo-google-fonts/open-sans@0.2.3': resolution: {integrity: sha512-HjEue5908n2yTtNSo47lAN3UFi2sAp00u6E3tx9nSEr0P2SDFDjYgsA89nPaAYOyxDN0EPGtNTa2K/VUe3jgmA==} @@ -2406,7 +2377,7 @@ packages: '@expo/metro-runtime@3.2.3': resolution: {integrity: sha512-v5ji+fAGi7B9YavrxvekuF8gXEV/5fz0+PhaED5AaFDnbGB4IJIbpaiqK9nqZV1axjGZNQSw6Q8TsnFetCR3bQ==} peerDependencies: - react-native: ~0.75.0 + react-native: '*' '@expo/osascript@2.1.3': resolution: {integrity: sha512-aOEkhPzDsaAfolSswObGiYW0Pf0ROfR9J2NBRLQACdQ6uJlyAMiPF45DVEVknAU9juKh0y8ZyvC9LXqLEJYohA==} @@ -2611,7 +2582,7 @@ packages: '@mdx-js/react@2.3.0': resolution: {integrity: sha512-zQH//gdOmuu7nt2oJR29vFhDv88oGPmVw6BggmrHeMI+xgEkp1B2dX9/bMBSYtK0dyLX/aOmesKS09g222K1/g==} peerDependencies: - react: 18.2.0 + react: '>=16' '@multiformats/base-x@4.0.1': resolution: {integrity: sha512-eMk0b9ReBbV23xXU693TAIrLyeO5iTgBZGSJfpqriG8UkYvr/hC9u9pyMlAakDNHWmbhMZCDs6KQO0jzKD8OTw==} @@ -2619,9 +2590,6 @@ packages: '@ndelangen/get-tarball@3.0.9': resolution: {integrity: sha512-9JKTEik4vq+yGosHYhZ1tiH/3WpUS0Nh0kej4Agndhox8pAdWhEx5knFVRcb/ya9knCRCs1rPxNrSXTDdfVqpA==} - '@noble/ciphers@0.4.1': - resolution: {integrity: sha512-QCOA9cgf3Rc33owG0AYBB9wszz+Ul2kramWN8tXG44Gyciud/tbkEqvxRF/IpqQaBpRBNi9f4jdNxqB2CQCIXg==} - '@noble/ciphers@0.5.3': resolution: {integrity: sha512-B0+6IIHiqEs3BPMT0hcRmHvEj2QHOLu+uwt+tqDDeVd0oyVzh7BPrDcPjRnV1PV/5LaknXJJQvOuRGR0zQJz+w==} @@ -2824,8 +2792,8 @@ packages: '@radix-ui/react-context@1.0.1': resolution: {integrity: sha512-ebbrdFoYTcuZ0v4wG5tedGnp9tzcV8awzsxYph7gXUyvnNLuTIcCk1q17JEbnVhXAKG9oX3KtchwiMIAYp9NLg==} peerDependencies: - '@types/react': ~18.2.79 - react: 18.2.0 + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 peerDependenciesMeta: '@types/react': optional: true @@ -2833,8 +2801,8 @@ packages: '@radix-ui/react-context@1.1.0': resolution: {integrity: sha512-OKrckBy+sMEgYM/sMmqmErVn0kZqrHPJze+Ql3DzYsDDp0hl0L62nx/2122/Bvps1qz645jlcu2tD9lrRSdf8A==} peerDependencies: - '@types/react': ~18.2.79 - react: 18.2.0 + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true @@ -3004,7 +2972,7 @@ packages: '@radix-ui/react-slot@1.0.1': resolution: {integrity: sha512-avutXAFL1ehGvAXtPquu0YK5oz6ctS474iM3vNGQIkswrVhdrS52e3uoMQBzZhNRAIE0jBnUyXWNmSjGHhCFcw==} peerDependencies: - react: 18.2.0 + react: ^16.8 || ^17.0 || ^18.0 '@radix-ui/react-slot@1.0.2': resolution: {integrity: sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg==} @@ -3172,7 +3140,7 @@ packages: '@react-native-async-storage/async-storage@1.23.1': resolution: {integrity: sha512-Qd2kQ3yi6Y3+AcUlrHxSLlnBvpdCEMVGFlVBneVOjaFaPU61g1huc38g339ysXspwY1QZA2aNhrk/KlHGO+ewA==} peerDependencies: - react-native: 0.74.5 + react-native: ^0.0.0-0 || >=0.60 <1.0 '@react-native-community/blur@4.4.1': resolution: {integrity: sha512-XBSsRiYxE/MOEln2ayunShfJtWztHwUxLFcSL20o+HNNRnuUDv+GXkF6FmM2zE8ZUfrnhQ/zeTqvnuDPGw6O8A==} @@ -3243,7 +3211,7 @@ packages: '@react-native-community/netinfo@11.3.1': resolution: {integrity: sha512-UBnJxyV0b7i9Moa97Av+HKho1ByzX0DtbJXzUQS5E3xhQs6P2D/Os0iw3ouy7joY1TVd6uIhplPbr7l1SJNaNQ==} peerDependencies: - react-native: 0.74.5 + react-native: '>=0.59' '@react-native-community/slider@4.5.5': resolution: {integrity: sha512-x2N415pg4ZxIltArOKczPwn7JEYh+1OxQ4+hTnafomnMsqs65HZuEWcX+Ch8c5r8V83DiunuQUf5hWGWlw8hQQ==} @@ -3251,8 +3219,8 @@ packages: '@react-native-masked-view/masked-view@0.3.1': resolution: {integrity: sha512-uVm8U6nwFIlUd1iDIB5cS+lDadApKR+l8k4k84d9hn+GN4lzAIJhUZ9syYX7c022MxNgAlbxoFLt0pqKoyaAGg==} peerDependencies: - react: 18.2.0 - react-native: 0.74.5 + react: '>=16' + react-native: '>=0.57' '@react-native/assets-registry@0.74.88': resolution: {integrity: sha512-tOvA+ikxa0Yxk3gLWR4+Pp4Y6Se+JEs6XXabX4/jgxIDnDfhT/czFNhqH/hdk4uOT8uVJGnilvevsia2TCFMiw==} @@ -3413,8 +3381,8 @@ packages: resolution: {integrity: sha512-ow6Z06iS4VqBO8d7FP+HsGjJLWt2xTWIvuWjpoCvsM/uQXzCRDIjBv9HaKcXbF0yTW7IMir0oDAbU5PFzEDdgA==} peerDependencies: '@react-navigation/native': ^6.0.0 - react: 18.3.1 - react-native: ~0.75.0 + react: '*' + react-native: '*' react-native-safe-area-context: '>= 3.0.0' react-native-screens: '>= 3.0.0' @@ -3427,8 +3395,8 @@ packages: resolution: {integrity: sha512-bUzP4Awlljx5RKEExw8WYtif8EuQni2glDaieYROKTnaxsu9kEIA515sXQgUDZU4Ob12VoL7+z70uO3qrlfXcQ==} peerDependencies: '@react-navigation/native': ^6.0.0 - react: 18.3.1 - react-native: ~0.75.0 + react: '*' + react-native: '*' react-native-safe-area-context: '>= 3.0.0' '@react-navigation/native-stack@6.9.26': @@ -3453,7 +3421,7 @@ packages: resolution: {integrity: sha512-2ly7bENj2n2FNBdEN60ZEbNCs5dAOex/QJoo6EZ8RNFfUQxVKAZkMwfQ4ETV2SLWDgkRLj3Jo5n/dx7O2ZGhGw==} engines: {node: '>=18.0.0'} peerDependencies: - typescript: ~5.3.3 + typescript: ^5.1.0 peerDependenciesMeta: typescript: optional: true @@ -3498,10 +3466,6 @@ packages: resolution: {integrity: sha512-vix1GplUFc1A9H42r/yXkg7cKYthggyqZEwlFdsBbn4xdZNE+AHVF4N7kPa1pPxipwN3UIHd4XnQ5MJV15mhsQ==} engines: {node: '>=18'} - '@sd-jwt/decode@0.6.1': - resolution: {integrity: sha512-QgTIoYd5zyKKLgXB4xEYJTrvumVwtsj5Dog0v0L9UH9ZvHekDaeexS247X7A4iSdzTvmZzUpGskgABOa4D8NmQ==} - engines: {node: '>=16'} - '@sd-jwt/decode@0.7.2': resolution: {integrity: sha512-dan2LSvK63SKwb62031G4r7TE4TaiI0EK1KbPXqS+LCXNkNDUHqhtYp9uOpj+grXceCsMtMa2f8VnUfsjmwHHg==} engines: {node: '>=18'} @@ -3518,18 +3482,10 @@ packages: resolution: {integrity: sha512-rryYmnoJHRSNqHcrs0Atta+bfJzU2yT7mYumR2D4lTfxJKWZd0OHHFq57uZSEm/wXPI6uytUJXYbEboCqLUAtw==} engines: {node: '>=18'} - '@sd-jwt/types@0.6.1': - resolution: {integrity: sha512-LKpABZJGT77jNhOLvAHIkNNmGqXzyfwBT+6r+DN9zNzMx1CzuNR0qXk1GMUbast9iCfPkGbnEpUv/jHTBvlIvg==} - engines: {node: '>=16'} - '@sd-jwt/types@0.7.2': resolution: {integrity: sha512-1NRKowiW0ZiB9SGLApLPBH4Xk8gDQJ+nA9NdZ+uy6MmJKLEwjuJxO7yTvRIv/jX/0/Ebh339S7Kq4RD2AiFuRg==} engines: {node: '>=18'} - '@sd-jwt/utils@0.6.1': - resolution: {integrity: sha512-1NHZ//+GecGQJb+gSdDicnrHG0DvACUk9jTnXA5yLZhlRjgkjyfJLNsCZesYeCyVp/SiyvIC9B+JwoY4kI0TwQ==} - engines: {node: '>=16'} - '@sd-jwt/utils@0.7.2': resolution: {integrity: sha512-aMPY7uHRMgyI5PlDvEiIc+eBFGC1EM8OCQRiEjJ8HGN0pajWMYj0qwSw7pS90A49/DsYU1a5Zpvb7nyjgGH0Yg==} engines: {node: '>=18'} @@ -3559,22 +3515,22 @@ packages: resolution: {integrity: sha512-kQpk267uxB19X3X2T1mvNMjyvIEonpNSHrMlK5ZaBU6aZxw7wPbpgKJOjHN3+/GPVpXgAV9soVT2oyHpLkLtyw==} engines: {node: '>= 8'} - '@sphereon/did-auth-siop@0.16.1-fix.173': - resolution: {integrity: sha512-BurhxcEfd91y2o2zy0VAZ9STHRuWRNx/FwhR0jRSG8D7gJPspqiR2cJtdvAvLrKNaznpQSANQHniCgCiDRtjfA==} + '@sphereon/did-auth-siop@https://gitpkg.vercel.app/animo/OID4VC/packages/siop-oid4vp?funke': + resolution: {tarball: https://gitpkg.vercel.app/animo/OID4VC/packages/siop-oid4vp?funke} + version: 0.16.0 engines: {node: '>=18'} - '@sphereon/did-uni-client@0.6.3': - resolution: {integrity: sha512-g7LD7ofbE36slHN7Bhr5dwUrj6t0BuZeXBYJMaVY/pOeL1vJxW1cZHbZqu0NSfOmzyBg4nsYVlgTjyi/Aua2ew==} - - '@sphereon/jarm@0.16.1-fix.173': - resolution: {integrity: sha512-VYNuNLV+x7hKKcynC8yOJymkXPrtBRQA/Gqj50Wfhl6kx6IoRsx39s/i6xGGYPwyrNTaVGFssKzg0IDcQfxToA==} + '@sphereon/jarm@https://gitpkg.vercel.app/animo/OID4VC/packages/jarm?funke': + resolution: {tarball: https://gitpkg.vercel.app/animo/OID4VC/packages/jarm?funke} + version: 0.16.0 engines: {node: '>=18'} '@sphereon/kmp-mdl-mdoc@0.2.0-SNAPSHOT.22': resolution: {integrity: sha512-uAZZExVy+ug9JLircejWa5eLtAZ7bnBP6xb7DO2+86LRsHNLh2k2jMWJYxp+iWtGHTsh6RYsZl14ScQLvjiQ/A==} - '@sphereon/oid4vc-common@0.16.1-fix.173': - resolution: {integrity: sha512-+AAUvEEFs0vzz1mrgjSgvDkcBtr18d2XEVgJex7QlAqxCKVGfjzZlqL2Q2vOLKYVaXsazhD5LnYiY6B5WMTC3Q==} + '@sphereon/oid4vc-common@https://gitpkg.vercel.app/animo/OID4VC/packages/common?funke': + resolution: {tarball: https://gitpkg.vercel.app/animo/OID4VC/packages/common?funke} + version: 0.16.0 engines: {node: '>=18'} '@sphereon/pex-models@2.3.1': @@ -3584,67 +3540,18 @@ packages: resolution: {integrity: sha512-CZc+kr8cJqPsFSpg4kHyamr5oB5xLVP2E5eJ0pbetOfOE2uSxqk0/A8zGazcPhU1zZILrO51hD4vW/hJRgtKJQ==} engines: {node: '>=18'} - '@sphereon/pex@5.0.0-unstable.25': - resolution: {integrity: sha512-EUWfGa6t20PPkYf+zbfWXhc1sSWiFNywbRah8R6grJPU738pfwWpZPunSEY3x0CoxAVaSVXn91wZ/sxmgPCFkA==} - engines: {node: '>=18'} - - '@sphereon/ssi-sdk-ext.did-utils@0.24.1-unstable.130': - resolution: {integrity: sha512-I+0VjitRjisABWm8RtTPQG57tFwfUS13Wud30OvBoADRxnaA0guUrkS82AYtV6YD0TBHdrd0D6a0RCJwK9SvDg==} - - '@sphereon/ssi-sdk-ext.identifier-resolution@0.24.1-unstable.130': - resolution: {integrity: sha512-9mY+qgXmbZCC8aic99R7B3vKBHBakDiC6Sktgd7Q9AknR8cCmvdrmTgnOETrLng9L43uNOJnNTMG/4T6LqmtsA==} - - '@sphereon/ssi-sdk-ext.jwt-service@0.24.1-unstable.130': - resolution: {integrity: sha512-MHLGRmJODEYJyFoXKwlKMYzf48vS5JcUkGk0W4sqmrY1wwcw+ro3l8adIprG37mNuknXBs9Mv0x/tvibE9wwCQ==} - - '@sphereon/ssi-sdk-ext.key-manager@0.24.1-unstable.130': - resolution: {integrity: sha512-O/6NlKmlYRnEyP/mAI2Diu0qptMSqZfVwqog8KAOG/G8JUmktfSQmclBW8RoJ6AD9uY65BGzNk1oAVuuMv4Dog==} - - '@sphereon/ssi-sdk-ext.key-utils@0.24.1-unstable.130': - resolution: {integrity: sha512-DCyXW18g1OAuZ+aFHzQGrbZSx793DX94LSFnrWlOTMnYeILmrizuFksUlWSb3lTqQGAqWBC48NoR3I1H6lSMEQ==} - - '@sphereon/ssi-sdk-ext.x509-utils@0.24.1-unstable.130': - resolution: {integrity: sha512-JDX8i0WrwONaOivZXB+OxJQGkln7vuSLS61tOYl7M1RyPGixdBYuEuACsdvWf6egYOpaWmhmXZzaAOj18eDddw==} - - '@sphereon/ssi-sdk.agent-config@0.29.1-unstable.161': - resolution: {integrity: sha512-ZP/TjapF/Gv/AwnNr9e1U3rjyRwdLtAj4un9j1csnKcgYe9ff2fhYbe06y9mU4tfQilH69mAW4Tz1t6N5U7XbA==} - - '@sphereon/ssi-sdk.core@0.29.1-unstable.161': - resolution: {integrity: sha512-3E/KsjTywT9BzP5bMi41JVTu9nTiu2ekwNSPobF9tAJnHJv+LkjCJ59xA8jtbq/Xe4iq3xRMU17yBvpZXN2W4A==} - - '@sphereon/ssi-types@0.29.1-unstable.161': - resolution: {integrity: sha512-ifMADjk6k0f97/isK/4Qw/PX6n4k+qS5k6mmmH47MTD3KMDddVghoXycsvNw7wObJdLUalHBX630ghr+u21oMg==} - - '@sphereon/ssi-types@0.30.1': - resolution: {integrity: sha512-vbYaxQXb71sOPwDj7TRDlUGfIHKVVs8PiHfImPBgSBshrD7VpEHOrB+EwwavMm5MAQvWK/yblGmzk7FHds7SHA==} - '@sphereon/ssi-types@0.30.2-next.129': resolution: {integrity: sha512-F1TDy9S5ajDJDp21cINXseGSux9kGA+x0KScAS+5+B/RdMGRp7bLOM+3YpQw1QGPqKxVc7JAd2gAn7AI0pAkZA==} '@sphereon/ssi-types@0.30.2-next.135': resolution: {integrity: sha512-YLQfFMPUlOJUxHbOS9v01nG3cgLwTk3d95/rTnOmEQx9kXgXjoXdvt7D0uGcMRL3RHeQ9biT/jWY//mDvCirVQ==} - '@sqltools/formatter@1.2.5': - resolution: {integrity: sha512-Uy0+khmZqUrUGm5dmMqVlnvufZRSK0FbYzVgp0UMstm+F5+W2/jnEEQyc9vo1ZR/E5ZI/B1WjjoTqBqwJL6Krw==} - - '@stablelib/aead@1.0.1': - resolution: {integrity: sha512-q39ik6sxGHewqtO0nP4BuSe3db5G1fEJE8ukvngS2gLkBXyy6E7pLubhbYgnkDFv6V8cWaxcE4Xn0t6LWcJkyg==} + '@sphereon/ssi-types@0.30.2-next.279': + resolution: {integrity: sha512-8I+wlZIKICKqwTJ0lObJWao2KKYHA3hoRzB4mDapPAIPKUbojJCIh9ei37DnEf5AEDAtUS1gOlEDmC/cKJrtpA==} '@stablelib/binary@1.0.1': resolution: {integrity: sha512-ClJWvmL6UBM/wjkvv/7m5VP3GMr9t0osr4yVgLZsLCOz4hGN9gIAFEqnJ0TsSMAN+n840nf2cHZnA5/KFqHC7Q==} - '@stablelib/bytes@1.0.1': - resolution: {integrity: sha512-Kre4Y4kdwuqL8BR2E9hV/R5sOrUj6NanZaZis0V6lX5yzqC3hBuVSDXUIBqQv/sCpmuWRiHLwqiT1pqqjuBXoQ==} - - '@stablelib/chacha20poly1305@1.0.1': - resolution: {integrity: sha512-MmViqnqHd1ymwjOQfghRKw2R/jMIGT3wySN7cthjXCBdO+qErNPUBnRzqNpnvIwg7JBCg3LdeCZZO4de/yEhVA==} - - '@stablelib/chacha@1.0.1': - resolution: {integrity: sha512-Pmlrswzr0pBzDofdFuVe1q7KdsHKhhU24e8gkEwnTGOmlC7PADzLVxGdn2PoNVBBabdg0l/IfLKg6sHAbTQugg==} - - '@stablelib/constant-time@1.0.1': - resolution: {integrity: sha512-tNOs3uD0vSJcK6z1fvef4Y+buN7DXhzHDPqRLSXUel1UfqMB1PWNsnnAezrKfEwTLpN0cGH2p9NNjs6IqeD0eg==} - '@stablelib/ed25519@1.0.3': resolution: {integrity: sha512-puIMWaX9QlRsbhxfDc5i+mNPMY+0TmQEskunY1rZEBPi1acBCVQAhnsk/1Hk50DGPtVsZtAWQg4NHGlVaO9Hqg==} @@ -3654,33 +3561,15 @@ packages: '@stablelib/int@1.0.1': resolution: {integrity: sha512-byr69X/sDtDiIjIV6m4roLVWnNNlRGzsvxw+agj8CIEazqWGOQp2dTYgQhtyVXV9wpO6WyXRQUzLV/JRNumT2w==} - '@stablelib/keyagreement@1.0.1': - resolution: {integrity: sha512-VKL6xBwgJnI6l1jKrBAfn265cspaWBPAPEc62VBQrWHLqVgNRE09gQ/AnOEyKUWrrqfD+xSQ3u42gJjLDdMDQg==} - - '@stablelib/poly1305@1.0.1': - resolution: {integrity: sha512-1HlG3oTSuQDOhSnLwJRKeTRSAdFNVB/1djy2ZbS35rBSJ/PFqx9cf9qatinWghC2UbfOYD8AcrtbUQl8WoxabA==} - '@stablelib/random@1.0.2': resolution: {integrity: sha512-rIsE83Xpb7clHPVRlBj8qNe5L8ISQOzjghYQm/dZ7VaM2KHYwMW5adjQjrzTZCchFnNCNhkwtnOBa9HTMJCI8w==} - '@stablelib/sha256@1.0.1': - resolution: {integrity: sha512-GIIH3e6KH+91FqGV42Kcj71Uefd/QEe7Dy42sBTeqppXV95ggCcxLTk39bEr+lZfJmp+ghsR07J++ORkRELsBQ==} - '@stablelib/sha512@1.0.1': resolution: {integrity: sha512-13gl/iawHV9zvDKciLo1fQ8Bgn2Pvf7OV6amaRVKiq3pjQ3UmEpXxWiAfV8tYjUpeZroBxtyrwtdooQT/i3hzw==} '@stablelib/wipe@1.0.1': resolution: {integrity: sha512-WfqfX/eXGiAd3RJe4VU2snh/ZPwtSjLG4ynQ/vYzvghTh7dHFcI1wl+nrkWG6lGhukOxOsUHfv8dUXr58D0ayg==} - '@stablelib/x25519@1.0.3': - resolution: {integrity: sha512-KnTbKmUhPhHavzobclVJQG5kuivH+qDLpe84iRqX3CLrKp881cF160JvXJ+hjn1aMyCwYOKeIZefIH/P5cJoRw==} - - '@stablelib/xchacha20@1.0.1': - resolution: {integrity: sha512-1YkiZnFF4veUwBVhDnDYwo6EHeKzQK4FnLiO7ezCl/zu64uG0bCCAUROJaBkaLH+5BEsO3W7BTXTguMbSLlWSw==} - - '@stablelib/xchacha20poly1305@1.0.1': - resolution: {integrity: sha512-B1Abj0sMJ8h3HNmGnJ7vHBrAvxuNka6cJJoZ1ILN7iuacXp7sUYcgOVEOTLWj+rtQMpspY9tXSCRLPmN1mQNWg==} - '@storybook/addon-actions@7.6.20': resolution: {integrity: sha512-c/GkEQ2U9BC/Ew/IMdh+zvsh4N6y6n7Zsn2GIhJgcu9YEAa5aF2a9/pNgEGBMOABH959XE8DAOMERw/5qiLR8g==} @@ -3910,8 +3799,8 @@ packages: '@storybook/react-native-theming@7.6.20': resolution: {integrity: sha512-vwMmR2xUAu4f1BSqJIIy/CbmhOyTCu385RZO8+5nf0ym73NDtwLks6Crp71xcy9fR/NDOHHADO2c4YPSpYyifA==} peerDependencies: - react: 18.2.0 - react-native: 0.74.5 + react: '*' + react-native: '>=0.57.0' '@storybook/react-native@7.6.20': resolution: {integrity: sha512-zDhTzLFJg1iNwVLcUWL4ieU5gM8+DSql6+XS14ARaaHNEAUSOo4j59VY2XUWIKUW8znhIxdDMOGGZYfc6PvFlg==} @@ -4084,7 +3973,7 @@ packages: '@tamagui/aria-hidden@1.109.5': resolution: {integrity: sha512-5g//FF6darlcFOdMPSTKTKb3xNUEx1Q4SLXdxAGFXnkoLvym4tACltOzQcGUIR0U2joMy1nFEecuqHpLT09IIw==} peerDependencies: - react: 18.2.0 + react: '*' '@tamagui/avatar@1.109.5': resolution: {integrity: sha512-dPGsl6S7V0MgsnOS6N2IceXcP6wQibViV+bBhpJe6HI3NWZ3O07vD3bzs2e+Arh1+jey6SrzBxj+Rc1+pCJRNw==} @@ -4148,7 +4037,7 @@ packages: '@tamagui/constants@1.109.5': resolution: {integrity: sha512-EZsHQZfa6LowUD2LG/JN7SkMqjXu5iMVMaL0UWh+2ZqTWAeqA9ZgHwEgXYpB+3FwUFhSUbT48gzW1h5aLykXjw==} peerDependencies: - react: 18.2.0 + react: '*' '@tamagui/core@1.109.5': resolution: {integrity: sha512-/fJ5GwIux7izg41PhDcwnUC+iiWvL3sDEk76H1cmsrezALx/7M93+0TkA/xrI4Y5E5qCBUK8abSwWPJWY+6RbA==} @@ -4185,12 +4074,12 @@ packages: '@tamagui/floating@1.109.5': resolution: {integrity: sha512-D0Gj/vu0Yf4xeohZadTtfdTxT7VGzmwsvq3x/7JbAEwT5N1EQVg7N0d0PKRjHA45xXJXTp4Va3CwouvQcro6PA==} peerDependencies: - react: 18.2.0 + react: '*' '@tamagui/focus-scope@1.109.5': resolution: {integrity: sha512-MI8XZC0UO2A274XNAVXxmFSIAOt19mephQaIyNhT55OhCjvorO0wuyU/n5FOr1h29JUFYnwSdfIRMvGMJO/8gg==} peerDependencies: - react: 18.2.0 + react: '*' '@tamagui/focusable@1.109.5': resolution: {integrity: sha512-PVDLXKhpAwkrJYxe/UtuRRuaEpe1fwJuSiSj43gncM8+7TWKXE8Yo7JPq0KJRKig8CZzO+52TqE8uA+g14P4ow==} @@ -4334,7 +4223,7 @@ packages: '@tamagui/remove-scroll@1.109.5': resolution: {integrity: sha512-8sAJTkODnw7M5KFA3paCZi93fcUvKHDGec0El8m9lStIDcRRyUMAtirXf9PxYgRAG/Z3pcgwwKNDmlbb39PVww==} peerDependencies: - react: 18.2.0 + react: '*' '@tamagui/roving-focus@1.109.5': resolution: {integrity: sha512-0duFXYcZKXKT7Fkri04JxdJ+UNMWqVjmLrl8llLn1a4L4KPiIEEQpv6zwVoEVY2pubMbWiLhsq6c2IKVGAUUkg==} @@ -4405,7 +4294,7 @@ packages: '@tamagui/text@1.109.5': resolution: {integrity: sha512-vUw/GJdacch5ZRl2k3tMd0sv3HyuU9XBpiccqzPX4Ulq8QIlXQ0We7HnhC/nV9P+uHZYOxW/1Ku/kCL2R7Mn1Q==} peerDependencies: - react: 18.2.0 + react: '*' '@tamagui/theme-builder@1.109.5': resolution: {integrity: sha512-XieD/HBDDbsXtivFA2Pjpu1xFa7vXikYSpMoz6lNat+BGi8zyX2sopphuglrn48Ws7k90xHl4u72T8j5F2YgDQ==} @@ -4445,7 +4334,7 @@ packages: '@tamagui/use-constant@1.109.5': resolution: {integrity: sha512-my5inqV0NpgLRQXYgBfkENPab6xlpykfS9gGSZOpvRpgGUm0EJEULp9or9xcTK7t9lnfGVcJqJ/e/WpS2S2ssQ==} peerDependencies: - react: 18.2.0 + react: '*' '@tamagui/use-controllable-state@1.109.5': resolution: {integrity: sha512-vyZXteZ/gbiMldO0qcdlcAA8wyFD8XbmqMKzJJneWX8F3lFPVGlVLAHuJJP+vGyiYCSAGAs0XOvFAqw2Jx1+Og==} @@ -4465,7 +4354,7 @@ packages: '@tamagui/use-direction@1.109.5': resolution: {integrity: sha512-GMKd+buqY/P4qgST8bdqvtdL2pO2DZZe9S40LiFQrh4UaEVHiLtg0SXu9m742Oi61URlXooFK4oJmk9IRosOsQ==} peerDependencies: - react: 18.2.0 + react: '*' '@tamagui/use-escape-keydown@1.109.5': resolution: {integrity: sha512-usuDbo+MAOGi2ltCoE+EOU94fYOukXrdAtRARzEMgzheUWrgkBzH3JdOnk/UmTYgC2Z5qneti4actEIWcrUayg==} @@ -4512,14 +4401,11 @@ packages: '@tanstack/react-query@5.59.16': resolution: {integrity: sha512-MuyWheG47h6ERd4PKQ6V8gDyBu3ThNG22e1fRVwvq6ap3EqsFhyuxCAwhNP/03m/mLg+DAb0upgbPaX6VB+CkQ==} peerDependencies: - react: 18.2.0 + react: ^18 || ^19 '@tokenizer/token@0.3.0': resolution: {integrity: sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==} - '@trust/keyto@1.0.1': - resolution: {integrity: sha512-OXTmKkrnkwktCX86XA7eWs1TQ6u64enm0syzAfNhjigbuGLy5aLhbhRYWtjt4zzdG/irWudluheRZ9Ic9pCwsA==} - '@types/babel__core@7.20.5': resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} @@ -4640,6 +4526,9 @@ packages: '@types/node-forge@1.3.11': resolution: {integrity: sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==} + '@types/node@18.18.8': + resolution: {integrity: sha512-OLGBaaK5V3VRBS1bAkMVP2/W9B+H8meUfl866OrMNQqt7wDgdpWPp5o6gmIc9pB+lIQHSq4ZL8ypeH1vPxcPaQ==} + '@types/node@18.19.63': resolution: {integrity: sha512-hcUB7THvrGmaEcPcvUZCZtQ2Z3C+UR/aOcraBLCvTsFMh916Gc1kCCYcfcMuB76HM2pSerxl1PoP3KnmHzd9Lw==} @@ -4727,15 +4616,6 @@ packages: peerDependencies: '@urql/core': ^5.0.0 - '@veramo/core@4.2.0': - resolution: {integrity: sha512-HIqbXfCbwOAJelR5Ohsm22vr63cy6ND8Ua/+9wfMDAiymUUS7NryaJ/v6NRtnmIrNZqUMDdR9/TWdp4cCq5eBg==} - - '@veramo/key-manager@4.2.0': - resolution: {integrity: sha512-v/swPrxxI155iFxWjcJDmeyfMLOnAu/VRxJJE+cv8Ld9mmPi5xljaoO9/ozt0j4Cz92n6lFKqfVOxs2ECV85UA==} - - '@veramo/utils@4.2.0': - resolution: {integrity: sha512-jHkli0Qz9rFsWzPAdfJP3P2MFxvVMZPDXZvtVBm8x1fjAGrw/Htz/c5drhDAeBXnqPd9011/7cyvp6AOvdbc8Q==} - '@web3-storage/multipart-parser@1.0.0': resolution: {integrity: sha512-BEO6al7BYqcnfX15W2cnGR+Q566ACXAT9UQykORCWW80lmkpWsnEob6zJS1ZVBKsSJC8+7vJkHwlp+lXG1UCdw==} @@ -4947,10 +4827,6 @@ packages: app-root-dir@1.0.2: resolution: {integrity: sha512-jlpIfsOoNoafl92Sz//64uQHGSyMrD2vYG5d8o2a4qGvyNCvXur7bzIsWtAC/6flI2RYAp3kv8rsfBtaLm7w0g==} - app-root-path@3.1.0: - resolution: {integrity: sha512-biN3PwB2gUtjaYy/isrU3aNWI5w+fAfvHkSvCKeQGxhmYpwKFUxudR3Yya+KqVRHBmEDYh+/lTozYCFbmzX4nA==} - engines: {node: '>= 6.0.0'} - appdirsjs@1.2.7: resolution: {integrity: sha512-Quji6+8kLBC3NnBeo14nPDq0+2jUs5s3/xEye+udFHumHhRk4M7aAMXp/PBJqkKYGuuyR9M/6Dq7d2AViiGmhw==} @@ -5002,12 +4878,6 @@ packages: asmcrypto.js@0.22.0: resolution: {integrity: sha512-usgMoyXjMbx/ZPdzTSXExhMPur2FTdz/Vo5PVx2gIaBcdAAJNOFlsdgqveM8Cff7W0v+xrf9BwjOV26JSAF9qA==} - asn1.js-rfc5280@3.0.0: - resolution: {integrity: sha512-Y2LZPOWeZ6qehv698ZgOGGCZXBQShObWnGthTrIFlIQjuV1gg2B8QOhWFRExq/MR1VnPpIIe7P9vX2vElxv+Pg==} - - asn1.js@5.4.1: - resolution: {integrity: sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==} - asn1js@3.0.5: resolution: {integrity: sha512-FVnvrKJwpt9LP2lAMl8qZswRNm3T4q9CON+bxldk2iwk3FFpuwhx2FfinyitizWHsVYyaY+y5JzDR0rCMV5yTQ==} engines: {node: '>=12.0.0'} @@ -5191,9 +5061,6 @@ packages: bech32@1.1.4: resolution: {integrity: sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==} - bech32@2.0.0: - resolution: {integrity: sha512-LcknSilhIGatDAsY1ak2I8VtGaHNhgMSYVxFrGLXv+xLHytaKZKcaUJJUE7qmBr7h33o5YQwP55pMI0xmkpJwg==} - better-opn@3.0.2: resolution: {integrity: sha512-aVNobHnJqLiUelTaHat9DZ1qM2w0C0Eym4LPI/3JxOnSokGVdsl1T1kN7TFvsEAD8G47A6VKQ0TVHqbBnYMJlQ==} engines: {node: '>=12.0.0'} @@ -5215,9 +5082,6 @@ packages: bl@4.1.0: resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} - blakejs@1.2.1: - resolution: {integrity: sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==} - bn.js@4.12.0: resolution: {integrity: sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==} @@ -5316,10 +5180,6 @@ packages: resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} engines: {node: '>= 0.8'} - bytestreamjs@2.0.1: - resolution: {integrity: sha512-U1Z/ob71V/bXfVABvNr/Kumf5VyeQRBEm6Txb0PQ6S7V5GpBM3w4Cbqz/xPDicR5tN0uvDifng8C+5qECeGwyQ==} - engines: {node: '>=6.0.0'} - cacache@18.0.4: resolution: {integrity: sha512-B+L5iIa9mgcjLbliir2th36yEwPftrzteHYujzsx3dFP/31GCHcIeS8f5MGd80odLOjaOvSpU3EEAmRQptkxLQ==} engines: {node: ^16.14.0 || >=18.0.0} @@ -5454,11 +5314,6 @@ packages: resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} engines: {node: '>=8'} - cli-highlight@2.1.11: - resolution: {integrity: sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg==} - engines: {node: '>=8.0.0', npm: '>=5.0.0'} - hasBin: true - cli-spinners@2.9.2: resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==} engines: {node: '>=6'} @@ -5470,9 +5325,6 @@ packages: cliui@6.0.0: resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==} - cliui@7.0.4: - resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} - cliui@8.0.1: resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} engines: {node: '>=12'} @@ -5650,9 +5502,6 @@ packages: cosmjs-types@0.7.2: resolution: {integrity: sha512-vf2uLyktjr/XVAgEq0DjMxeAWh1yYREe7AMHDKd7EiHVqxBPCaBS+qEEQUkXbR9ndnckqr1sUG8BQhazh4X5lA==} - credential-status@2.0.6: - resolution: {integrity: sha512-l5ZwSbX/UXFJ3DQ3dFt4rc2BtfUu/rhlkefR7BL9EZsKPyCe21okJA9mDy4h/nXvMEwpYjSQEa5vzR7KZqhI9g==} - credentials-context@2.0.0: resolution: {integrity: sha512-/mFKax6FK26KjgV2KW2D4YqKgoJ5DVJpNt87X2Jc9IxT2HBMy7nEIlc+n7pEi+YFFe721XqrvZPd+jbyyBjsvQ==} @@ -5767,6 +5616,9 @@ packages: dayjs@1.11.13: resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==} + dcql@0.2.13: + resolution: {integrity: sha512-XfePsSz9ULj9HH3VFNguzK/xlFnliKDX2iUDb1tIrn97S+TfftcFo+jipw16m9jPlWLhhBx48QniF0D8KotIWA==} + debug@2.6.9: resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} peerDependencies: @@ -5878,9 +5730,6 @@ packages: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} engines: {node: '>=6'} - des.js@1.1.0: - resolution: {integrity: sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==} - destroy@1.2.0: resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} @@ -5910,16 +5759,6 @@ packages: engines: {node: '>= 4.0.0'} hasBin: true - did-jwt-vc@3.2.15: - resolution: {integrity: sha512-M/WPiL34CQUiN4bvWnZ0OFHJ3usPtstfQfbNbHAWHvwjeCGi7nAdv62VXHgy2xIhJMc790hH7PsMN3i6SCGEyg==} - engines: {node: '>=18'} - - did-jwt@6.11.6: - resolution: {integrity: sha512-OfbWknRxJuUqH6Lk0x+H1FsuelGugLbBDEwsoJnicFOntIG/A4y19fn0a8RLxaQbWQ5gXg0yDq5E2huSBiiXzw==} - - did-jwt@7.4.7: - resolution: {integrity: sha512-Apz7nIfIHSKWIMaEP5L/K8xkwByvjezjTG0xiqwKdnNj1x8M0+Yasury5Dm/KPltxi2PlGfRPf3IejRKZrT8mQ==} - did-jwt@8.0.4: resolution: {integrity: sha512-KPtG7H+8GgKGMiDqFvOdNy5BBN3hpA+8xV7VygEnpst5oPIqjvcH3rTtnPF55a8bOxIzE2PudKGIXIQhekv7WA==} @@ -6004,12 +5843,6 @@ packages: electron-to-chromium@1.5.50: resolution: {integrity: sha512-eMVObiUQ2LdgeO1F/ySTXsvqvxb6ZH2zPGaMYsWzRDdOddUa77tdmI0ltg+L16UpbWdhPmuF3wIQYyQq65WfZw==} - elliptic@6.5.4: - resolution: {integrity: sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==} - - elliptic@6.5.7: - resolution: {integrity: sha512-ESVCtTwiA+XhY3wyh24QqRGBoP3rEdDUl3EDUUo9tft074fi19IrdpH7hLCMMP3CIj7jb3W96rn8lt/BqIlt5Q==} - elliptic@6.6.0: resolution: {integrity: sha512-dpwoQcLc/2WLQvJvLRHKZ+f9FgOdjnq11rurqwekGQygGPsYSK29OMMD2WalatiqQ+XGFDglTNixpPfI+lpaAA==} @@ -6170,11 +6003,6 @@ packages: esm-resolve@1.0.11: resolution: {integrity: sha512-LxF0wfUQm3ldUDHkkV2MIbvvY0TgzIpJ420jHSV1Dm+IlplBEWiJTKWM61GtxUfvjV6iD4OtTYFGAGM2uuIUWg==} - esprima@1.2.2: - resolution: {integrity: sha512-+JpPZam9w5DuJ3Q67SqsMGtiHKENSMRVoxvArfJZK01/BfLEObtZ6orJa/MtoGNR/rfMgp5837T41PAmTwAv/A==} - engines: {node: '>=0.4.0'} - hasBin: true - esprima@4.0.1: resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} engines: {node: '>=4'} @@ -6382,7 +6210,7 @@ packages: expo-constants: '*' expo-linking: '*' expo-status-bar: '*' - react-native-reanimated: ~3.15.5 + react-native-reanimated: '*' react-native-safe-area-context: '*' react-native-screens: '*' peerDependenciesMeta: @@ -6935,9 +6763,6 @@ packages: resolution: {integrity: sha512-cnN7bQUm65UWOy6cbGcCcZ3rpwW8Q/j4OP5aWRhEry4Z2t2aR1cjrbp0BS+KiBN0smvP1caBgAuxutvyvJILzQ==} engines: {node: '>=8'} - highlight.js@10.7.3: - resolution: {integrity: sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==} - hmac-drbg@1.0.1: resolution: {integrity: sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==} @@ -7027,11 +6852,6 @@ packages: engines: {node: '>=16.x'} hasBin: true - image-size@2.0.0-beta.2: - resolution: {integrity: sha512-1nDNnVxJixMWBynFgQ1q8+aVqK60TiNHpMyFAXt9xpzGZV+2lHI1IXjgdcAjBxPc4nx2ed1NdYs2I+Zfq+Zn7w==} - engines: {node: '>=18.18.0'} - hasBin: true - import-fresh@2.0.0: resolution: {integrity: sha512-eZ5H8rcgYazHbKC3PG4ClHNykCSxtAhxSSEM+2mb+7evD2CKF5V7c0dNum7AdpDh0ZdICwZY9sRSn8f+KH96sg==} engines: {node: '>=4'} @@ -7371,45 +7191,9 @@ packages: js-base64@3.7.7: resolution: {integrity: sha512-7rCnleh0z2CkXhH67J8K1Ytz0b2Y+yxTPL+/KOJoa20hfnVQ/3/T6W/KflYI4bRHRagNeXeU2bkNGI3v1oS/lw==} - js-crypto-aes@1.0.6: - resolution: {integrity: sha512-E2hu9z5+YtpDg9Un/bDfmH+I5dv/8aN+ozxv9L0ybZldcQ9T5iYDbBKdlKGBUKI3IvzoWSBSdnZnhwZaRIN46w==} - - js-crypto-ec@1.0.7: - resolution: {integrity: sha512-vou6cW3wGAQ75RzS++I/rthELPFp0nhHCmaAKQvdhwD480Q3FltLgyNkTMgcLTdN+Ghj8BRU1/+3oIEIOOK/MA==} - - js-crypto-env@1.0.5: - resolution: {integrity: sha512-8/UNN3sG8J+yMzqwSNVaobaWhIz4MqZFoOg5OB0DFXqS8eFjj2YvdmLJqIWXPl57Yw10SvYx0DQOtkfsWIV9Aw==} - - js-crypto-hash@1.0.7: - resolution: {integrity: sha512-GdbcVKjplbXJdR9oF2ks8+sBCLD7BUZ144Bc+Ie8OJuBHSIiHyMzdg2eD+ZYf87awTsKckNn1xIv+31+V2ewcA==} - - js-crypto-hmac@1.0.7: - resolution: {integrity: sha512-OVn2wjAuOV7ToQYvRKY2VoElCHoRW7BepycPPuH73xbLygDczkef41YsXMpKLnVAyS5kdwMJQy9qlMR9touHTg==} - - js-crypto-key-utils@1.0.7: - resolution: {integrity: sha512-8/y/hpKevnAgr5EXz2x4IXMfqjzYZAzzXXc9OnAyI5JNdUtAufJkGfwlmZ+o40lTHv3k1egCiP/6pG/dZiqiEA==} - - js-crypto-pbkdf@1.0.7: - resolution: {integrity: sha512-FGs1PZeqGWM8k8k5JlAhHbBhLYtls+iVmeJEC22DUJ98Q3qo9Ki4cu3i0oxhjA2VpZ8V4MmV1DJHDTFYY4iOwg==} - - js-crypto-random@1.0.5: - resolution: {integrity: sha512-WydEQ5rrWLzgSkX1QNsuGinkv7z57UkYnDGo5f5oGtBe9QeUWUehdmPNNG4a4Sf8xGkjZBOhKaZqT1ACnyYCBA==} - - js-crypto-rsa@1.0.7: - resolution: {integrity: sha512-HLBCWNGzuUZMNbZ3nndrVAqth1m1mvuCO4tW7PpBDn4nsdLSnPnPd+SA7NvjsufWry38DnZdpFrK2gqbsrksGw==} - - js-encoding-utils@0.7.3: - resolution: {integrity: sha512-cfjcyPOzkZ2esMAi6eAjuto7GiT6YpPan5xIeQyN/CFqFHTt1sdqP0PJPgzi3HqAqXKN9j9hduynkgwk+AAJOw==} - - js-sha3@0.8.0: - resolution: {integrity: sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==} - js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - js-x509-utils@1.0.7: - resolution: {integrity: sha512-IDB3CtWyvkNJVbDPZvzM9o3Y6CyzDiMls6R23ZPwfmHHil7nRrpLxtA098SENhqjv1t/6WTeeCKQ5dhIMOGiUw==} - js-yaml@3.14.1: resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} hasBin: true @@ -7495,13 +7279,6 @@ packages: resolution: {integrity: sha512-MwBbq95szLwt8eVQ1Bcfwmgju/Y5P2GdtlHE2ncyfuYjIdEhluUVyj1eudacf1mOkWIoS9GpDBTECqhmq7EOaA==} engines: {node: '>=14'} - jsonpath@1.1.1: - resolution: {integrity: sha512-l6Cg7jRpixfbgoWgkrl77dgEj8RPvND0wMH6TwQmi9Qs4TFfS9u5cUFnbeKTwj5ga5Y3BTGGNI28k117LJ009w==} - - jsonpointer@5.0.1: - resolution: {integrity: sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==} - engines: {node: '>=0.10.0'} - jwt-decode@3.1.2: resolution: {integrity: sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==} @@ -7729,21 +7506,9 @@ packages: resolution: {integrity: sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - lodash.clonedeep@4.5.0: - resolution: {integrity: sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==} - lodash.debounce@4.0.8: resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==} - lodash.get@4.4.2: - resolution: {integrity: sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==} - - lodash.isequal@4.5.0: - resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==} - - lodash.isplainobject@4.0.6: - resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==} - lodash.throttle@4.1.1: resolution: {integrity: sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==} @@ -8110,11 +7875,6 @@ packages: engines: {node: '>=10'} hasBin: true - mkdirp@2.1.6: - resolution: {integrity: sha512-+hEnITedc8LAtIP9u3HJDFIdcLV2vXP33sqLLIzkv1Db1zO/1OxbvYf0Y1OC/S/Qo5dxHXepofhmxL02PsKe+A==} - engines: {node: '>=10'} - hasBin: true - mlly@1.7.2: resolution: {integrity: sha512-tN3dvVHYVz4DhSXinXIk7u9syPYaJvio118uomkovAtWBT+RdbP6Lfh/5Lvo519YMmwBafwlh20IPTXIStscpA==} @@ -8140,9 +7900,6 @@ packages: resolution: {integrity: sha512-eajQ/ZH7qXZQR2AgtfpmSMizQzmyYVmCql7pdhldPuYQi4atACekbJaQplk6dWyIi10jCaFnd6pqvcEFXjbaJw==} engines: {node: '>=16.0.0', npm: '>=7.0.0'} - multiformats@9.7.1: - resolution: {integrity: sha512-TaVmGEBt0fhxiNJMGphBfB+oGvUxFs8KgGvgl8d3C+GWtrFcvXdJ2196eg+dYhmSFClmgFfSfJEklo+SZzdNuw==} - multiformats@9.9.0: resolution: {integrity: sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg==} @@ -8441,15 +8198,6 @@ packages: resolution: {integrity: sha512-Nt/a5SfCLiTnQAjx3fHlqp8hRgTL3z7kTQZzvIMS9uCAepnCyjpdEc6M/sz69WqMBdaDBw9sF1F1UaHROYzGkQ==} engines: {node: '>=10'} - parse5-htmlparser2-tree-adapter@6.0.1: - resolution: {integrity: sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==} - - parse5@5.1.1: - resolution: {integrity: sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==} - - parse5@6.0.1: - resolution: {integrity: sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==} - parseurl@1.3.3: resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} engines: {node: '>= 0.8'} @@ -8563,10 +8311,6 @@ packages: resolution: {integrity: sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==} engines: {node: '>=8'} - pkijs@3.2.4: - resolution: {integrity: sha512-Et9V5QpvBilPFgagJcaKBqXjKrrgF5JL2mSDELk1vvbOTt4fuBhSSsGn9Tcz0TQTfS5GCpXQ31Whrpqeqp0VRg==} - engines: {node: '>=12.0.0'} - plist@3.1.0: resolution: {integrity: sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ==} engines: {node: '>=10.4.0'} @@ -8750,9 +8494,6 @@ packages: engines: {node: '>=0.4.x'} deprecated: The querystring API is considered Legacy. new code should use the URLSearchParams API instead. - querystringify@2.2.0: - resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==} - queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} @@ -8907,15 +8648,15 @@ packages: react-native-qrcode-svg@6.3.12: resolution: {integrity: sha512-7Bx23ZdFNJJdVXyW9BJmFWdI5kccjnpotzmL3exkV0irUKTmj51jesxpn5sqtgVdYFE4IUVoGzdS+8qg6Ua9BA==} peerDependencies: - react: 18.3.1 - react-native: ~0.75.0 + react: '*' + react-native: '>=0.63.4' react-native-svg: '>=13.2.0' react-native-reanimated@3.10.1: resolution: {integrity: sha512-sfxg6vYphrDc/g4jf/7iJ7NRi+26z2+BszPmvmk0Vnrz6FL7HYljJqTf531F1x6tFmsf+FEAmuCtTUIXFLVo9w==} peerDependencies: '@babel/core': ^7.0.0-0 - react: 18.3.1 + react: '*' react-native: '*' react-native-safe-area-context@4.10.5: @@ -8944,8 +8685,8 @@ packages: react-native-svg@15.9.0: resolution: {integrity: sha512-pwo7hteAM0P8jNpPGQtiSd0SnbBhE8tNd94LT8AcZcbnH5AJdXBIcXU4+tWYYeGUjiNAH2E5d0T5XIfnvaz1gA==} peerDependencies: - react: 18.3.1 - react-native: ~0.75.0 + react: '*' + react-native: '*' react-native-swipe-gestures@1.0.5: resolution: {integrity: sha512-Ns7Bn9H/Tyw278+5SQx9oAblDZ7JixyzeOczcBK8dipQk2pD7Djkcfnf1nB/8RErAmMLL9iXgW0QHqiII8AhKw==} @@ -9139,9 +8880,6 @@ packages: resolution: {integrity: sha512-nYzyjnFcPNGR3lx9lwPPPnuQxv6JWEZd2Ci0u9opN7N5zUEPIhY/GbL3vMGOr2UXwEg9WwSyV9X9Y/kLFgPsOg==} engines: {node: '>= 4.0.0'} - requires-port@1.0.0: - resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==} - reselect@4.1.8: resolution: {integrity: sha512-ab9EmR80F/zQTMNeneUr4cv+jSwPJgIlvEmVwLerwrWVbpLlBuls9XHzIeTFy4cegU2NHBp3va0LKOzU5qFEYQ==} @@ -9321,9 +9059,6 @@ packages: resolution: {integrity: sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==} hasBin: true - sha3@2.1.4: - resolution: {integrity: sha512-S8cNxbyb0UGUM2VhRD4Poe5N58gJnJsLJ5vC7FYWGUmGhcsj4++WaIOBFVDxlG0W3To6xBuiRh+i0Qp2oNCOtg==} - shallow-clone@3.0.1: resolution: {integrity: sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==} engines: {node: '>=8'} @@ -9871,64 +9606,6 @@ packages: typedarray@0.0.6: resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==} - typeorm@0.3.20: - resolution: {integrity: sha512-sJ0T08dV5eoZroaq9uPKBoNcGslHBR4E4y+EBHs//SiGbblGe7IeduP/IH4ddCcj0qp3PHwDwGnuvqEAnKlq/Q==} - engines: {node: '>=16.13.0'} - hasBin: true - peerDependencies: - '@google-cloud/spanner': ^5.18.0 - '@sap/hana-client': ^2.12.25 - better-sqlite3: ^7.1.2 || ^8.0.0 || ^9.0.0 - hdb-pool: ^0.1.6 - ioredis: ^5.0.4 - mongodb: ^5.8.0 - mssql: ^9.1.1 || ^10.0.1 - mysql2: ^2.2.5 || ^3.0.1 - oracledb: ^6.3.0 - pg: ^8.5.1 - pg-native: ^3.0.0 - pg-query-stream: ^4.0.0 - redis: ^3.1.1 || ^4.0.0 - sql.js: ^1.4.0 - sqlite3: ^5.0.3 - ts-node: ^10.7.0 - typeorm-aurora-data-api-driver: ^2.0.0 - peerDependenciesMeta: - '@google-cloud/spanner': - optional: true - '@sap/hana-client': - optional: true - better-sqlite3: - optional: true - hdb-pool: - optional: true - ioredis: - optional: true - mongodb: - optional: true - mssql: - optional: true - mysql2: - optional: true - oracledb: - optional: true - pg: - optional: true - pg-native: - optional: true - pg-query-stream: - optional: true - redis: - optional: true - sql.js: - optional: true - sqlite3: - optional: true - ts-node: - optional: true - typeorm-aurora-data-api-driver: - optional: true - typescript@5.3.3: resolution: {integrity: sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==} engines: {node: '>=14.17'} @@ -9955,9 +9632,6 @@ packages: unbox-primitive@1.0.2: resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} - underscore@1.12.1: - resolution: {integrity: sha512-hEQt0+ZLDVUMhebKxL4x1BTtDY7bavVofhZ9KZ4aI26X9SRaE+Y3m83XUL1UP2jn8ynjndwCCpEHdUG+9pP1Tw==} - undici-types@5.26.5: resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} @@ -10054,9 +9728,6 @@ packages: url-join@4.0.0: resolution: {integrity: sha512-EGXjXJZhIHiQMK2pQukuFcL303nskqIRzWvPvV5O8miOfwoUb9G+a/Cld60kUyeaybEI94wvVClT10DtfeAExA==} - url-parse@1.5.10: - resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==} - url@0.11.4: resolution: {integrity: sha512-oCwdVC7mTuWiPyjLUz/COz5TLk6wgp0RCsN+wHZ2Ekneac9w8uuV0njcbbie2ME+Vs+d6duwmYuR3HgQXs1fOg==} engines: {node: '>= 0.4'} @@ -10129,6 +9800,14 @@ packages: resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==} hasBin: true + valibot@0.37.0: + resolution: {integrity: sha512-FQz52I8RXgFgOHym3XHYSREbNtkgSjF9prvMFH1nBsRyfL6SfCzoT1GuSDTlbsuPubM7/6Kbw0ZMQb8A+V+VsQ==} + peerDependencies: + typescript: '>=5' + peerDependenciesMeta: + typescript: + optional: true + valibot@0.42.1: resolution: {integrity: sha512-3keXV29Ar5b//Hqi4MbSdV7lfVp6zuYLZuA9V1PvQUsXqogr+u5lvLPLk3A4f74VUXDnf/JfWMN6sB+koJ/FFw==} peerDependencies: @@ -10393,10 +10072,6 @@ packages: resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==} engines: {node: '>=6'} - yargs-parser@20.2.9: - resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} - engines: {node: '>=10'} - yargs-parser@21.1.1: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} engines: {node: '>=12'} @@ -10405,10 +10080,6 @@ packages: resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==} engines: {node: '>=8'} - yargs@16.2.0: - resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} - engines: {node: '>=10'} - yargs@17.7.2: resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} engines: {node: '>=12'} @@ -10424,11 +10095,6 @@ packages: resolution: {integrity: sha512-b4JR1PFR10y1mKjhHY9LaGo6tmrgjit7hxVIeAmyMw3jegXR4dhYqLaQF5zMXZxY7tLpMyJeLjr1C4rLmkVe8g==} engines: {node: '>=12.20'} - z-schema@5.0.5: - resolution: {integrity: sha512-D7eujBWkLa3p2sIpJA0d1pr7es+a7m0vFAnZLlCEKq/Ij2k0MLi9Br2UPxoxdYystm5K1yeBGzub0FlYUEWj2Q==} - engines: {node: '>=8.0.0'} - hasBin: true - zod-validation-error@2.1.0: resolution: {integrity: sha512-VJh93e2wb4c3tWtGgTa0OF/dTt/zoPCPzXq4V11ZjxmEAFaPi/Zss1xIZdEB5RD8GD00U0/iVXgqkF77RV7pdQ==} engines: {node: '>=18.0.0'} @@ -10473,15 +10139,16 @@ snapshots: transitivePeerDependencies: - supports-color - '@animo-id/expo-mdoc-data-transfer@0.0.3-alpha.7(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.2.79)(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react@18.3.1)': + '@animo-id/expo-mdoc-data-transfer@0.0.3-alpha.7(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react@18.3.1)': dependencies: '@expo/config-plugins': 8.0.11 expo: 51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)) react: 18.3.1 - react-native: 0.74.6(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.2.79)(react@18.3.1) + react-native: 0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1) transitivePeerDependencies: - '@babel/core' - '@babel/preset-env' + - '@react-native-community/cli-server-api' - '@types/react' - bufferutil - encoding @@ -10497,32 +10164,48 @@ snapshots: react: 18.3.1 react-native: 0.74.6(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.2.79)(react@18.3.1) - '@animo-id/mdoc@0.2.38(patch_hash=zifb323ygrtdb6olnw5okh7czy)': + '@animo-id/mdoc@0.2.39': dependencies: compare-versions: 6.1.1 - '@animo-id/oauth2-utils@0.1.4-alpha-20241120145259(typescript@5.3.3)': + '@animo-id/oauth2-utils@0.1.4(typescript@5.3.3)': dependencies: buffer: 6.0.3 valibot: 0.42.1(typescript@5.3.3) transitivePeerDependencies: - typescript - '@animo-id/oauth2@0.1.4-alpha-20241120145259(typescript@5.3.3)': + '@animo-id/oauth2@0.1.4(typescript@5.3.3)': dependencies: - '@animo-id/oauth2-utils': 0.1.4-alpha-20241120145259(typescript@5.3.3) + '@animo-id/oauth2-utils': 0.1.4(typescript@5.3.3) valibot: 0.42.1(typescript@5.3.3) transitivePeerDependencies: - typescript - '@animo-id/oid4vci@0.1.4-alpha-20241120145259(typescript@5.3.3)': + '@animo-id/oid4vci@0.1.4(typescript@5.3.3)': dependencies: - '@animo-id/oauth2': 0.1.4-alpha-20241120145259(typescript@5.3.3) - '@animo-id/oauth2-utils': 0.1.4-alpha-20241120145259(typescript@5.3.3) + '@animo-id/oauth2': 0.1.4(typescript@5.3.3) + '@animo-id/oauth2-utils': 0.1.4(typescript@5.3.3) valibot: 0.42.1(typescript@5.3.3) transitivePeerDependencies: - typescript + '@animo-id/pex@4.1.1-alpha.0': + dependencies: + '@astronautlabs/jsonpath': 1.1.2 + '@sd-jwt/decode': 0.7.2 + '@sd-jwt/present': 0.7.2 + '@sd-jwt/types': 0.7.2 + '@sphereon/pex-models': 2.3.1 + '@sphereon/ssi-types': 0.30.2-next.135 + ajv: 8.17.1 + ajv-formats: 2.1.1(ajv@8.17.1) + jwt-decode: 3.1.2 + nanoid: 3.3.7 + uint8arrays: 3.1.1 + transitivePeerDependencies: + - supports-color + '@astronautlabs/jsonpath@1.1.2': dependencies: static-eval: 2.0.2 @@ -11675,10 +11358,10 @@ snapshots: '@cosmjs/utils@0.30.1': {} - '@credo-ts/anoncreds@0.6.0-alpha-20241120153226(@hyperledger/anoncreds-shared@0.2.4)(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1))(web-streams-polyfill@3.3.3)': + '@credo-ts/anoncreds@0.6.0-pr-2100-20241124170219(@hyperledger/anoncreds-shared@0.2.4)(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1))(typescript@5.3.3)(web-streams-polyfill@3.3.3)': dependencies: '@astronautlabs/jsonpath': 1.1.2 - '@credo-ts/core': 0.6.0-alpha-20241120153226(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1))(web-streams-polyfill@3.3.3) + '@credo-ts/core': 0.6.0-pr-2100-20241124170219(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1))(typescript@5.3.3)(web-streams-polyfill@3.3.3) '@hyperledger/anoncreds-shared': 0.2.4 '@sphereon/pex-models': 2.3.1 big-integer: 1.6.52 @@ -11692,11 +11375,12 @@ snapshots: - expo - react-native - supports-color + - typescript - web-streams-polyfill - '@credo-ts/askar@0.6.0-alpha-20241120153226(patch_hash=zbu2rcss5evxukkhh5w5venkba)(@hyperledger/aries-askar-shared@0.2.3)(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1))(web-streams-polyfill@3.3.3)': + '@credo-ts/askar@0.6.0-pr-2100-20241124170219(patch_hash=zbu2rcss5evxukkhh5w5venkba)(@hyperledger/aries-askar-shared@0.2.3)(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1))(typescript@5.3.3)(web-streams-polyfill@3.3.3)': dependencies: - '@credo-ts/core': 0.6.0-alpha-20241120153226(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1))(web-streams-polyfill@3.3.3) + '@credo-ts/core': 0.6.0-pr-2100-20241124170219(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1))(typescript@5.3.3)(web-streams-polyfill@3.3.3) '@hyperledger/aries-askar-shared': 0.2.3 bn.js: 5.2.1 class-transformer: 0.5.1 @@ -11709,17 +11393,18 @@ snapshots: - expo - react-native - supports-color + - typescript - web-streams-polyfill - '@credo-ts/cheqd@0.6.0-alpha-20241120153226(@hyperledger/anoncreds-shared@0.2.4)(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1))(web-streams-polyfill@3.3.3)': + '@credo-ts/cheqd@0.6.0-pr-2100-20241124170219(@hyperledger/anoncreds-shared@0.2.4)(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1))(typescript@5.3.3)(web-streams-polyfill@3.3.3)': dependencies: '@cheqd/sdk': 2.5.1 '@cheqd/ts-proto': 2.3.2 '@cosmjs/crypto': 0.30.1 '@cosmjs/proto-signing': 0.30.1 '@cosmjs/stargate': 0.30.1 - '@credo-ts/anoncreds': 0.6.0-alpha-20241120153226(@hyperledger/anoncreds-shared@0.2.4)(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1))(web-streams-polyfill@3.3.3) - '@credo-ts/core': 0.6.0-alpha-20241120153226(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1))(web-streams-polyfill@3.3.3) + '@credo-ts/anoncreds': 0.6.0-pr-2100-20241124170219(@hyperledger/anoncreds-shared@0.2.4)(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1))(typescript@5.3.3)(web-streams-polyfill@3.3.3) + '@credo-ts/core': 0.6.0-pr-2100-20241124170219(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1))(typescript@5.3.3)(web-streams-polyfill@3.3.3) '@stablelib/ed25519': 1.0.3 class-transformer: 0.5.1 class-validator: 0.14.1 @@ -11734,12 +11419,15 @@ snapshots: - expo - react-native - supports-color + - typescript - utf-8-validate - web-streams-polyfill - '@credo-ts/core@0.6.0-alpha-20241120153226(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.74.6(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.2.79)(react@18.3.1))(web-streams-polyfill@3.3.3)': + '@credo-ts/core@0.6.0-pr-2100-20241124170219(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.74.6(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.2.79)(react@18.3.1))(typescript@5.3.3)(web-streams-polyfill@3.3.3)': dependencies: - '@animo-id/mdoc': 0.2.38(patch_hash=zifb323ygrtdb6olnw5okh7czy) + '@animo-id/mdoc': 0.2.39 + '@animo-id/pex': 4.1.1-alpha.0 + '@astronautlabs/jsonpath': 1.1.2 '@digitalcredentials/jsonld': 6.0.0(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.74.6(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.2.79)(react@18.3.1))(web-streams-polyfill@3.3.3) '@digitalcredentials/jsonld-signatures': 9.4.0(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.74.6(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.2.79)(react@18.3.1))(web-streams-polyfill@3.3.3) '@digitalcredentials/vc': 6.0.1(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.74.6(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.2.79)(react@18.3.1))(web-streams-polyfill@3.3.3) @@ -11756,7 +11444,6 @@ snapshots: '@sd-jwt/sd-jwt-vc': 0.7.2 '@sd-jwt/types': 0.7.2 '@sd-jwt/utils': 0.7.2 - '@sphereon/pex': 5.0.0-unstable.25 '@sphereon/pex-models': 2.3.1 '@sphereon/ssi-types': 0.30.2-next.135 '@stablelib/ed25519': 1.0.3 @@ -11767,8 +11454,8 @@ snapshots: buffer: 6.0.3 class-transformer: 0.5.1 class-validator: 0.14.1 + dcql: 0.2.13(typescript@5.3.3) did-resolver: 4.1.0 - jsonpath: 1.1.1 lru_map: 0.4.1 luxon: 3.5.0 make-error: 1.3.6 @@ -11787,11 +11474,14 @@ snapshots: - expo - react-native - supports-color + - typescript - web-streams-polyfill - '@credo-ts/core@0.6.0-alpha-20241120153226(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1))(web-streams-polyfill@3.3.3)': + '@credo-ts/core@0.6.0-pr-2100-20241124170219(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1))(typescript@5.3.3)(web-streams-polyfill@3.3.3)': dependencies: - '@animo-id/mdoc': 0.2.38(patch_hash=zifb323ygrtdb6olnw5okh7czy) + '@animo-id/mdoc': 0.2.39 + '@animo-id/pex': 4.1.1-alpha.0 + '@astronautlabs/jsonpath': 1.1.2 '@digitalcredentials/jsonld': 6.0.0(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1))(web-streams-polyfill@3.3.3) '@digitalcredentials/jsonld-signatures': 9.4.0(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1))(web-streams-polyfill@3.3.3) '@digitalcredentials/vc': 6.0.1(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1))(web-streams-polyfill@3.3.3) @@ -11808,7 +11498,6 @@ snapshots: '@sd-jwt/sd-jwt-vc': 0.7.2 '@sd-jwt/types': 0.7.2 '@sd-jwt/utils': 0.7.2 - '@sphereon/pex': 5.0.0-unstable.25 '@sphereon/pex-models': 2.3.1 '@sphereon/ssi-types': 0.30.2-next.135 '@stablelib/ed25519': 1.0.3 @@ -11819,8 +11508,8 @@ snapshots: buffer: 6.0.3 class-transformer: 0.5.1 class-validator: 0.14.1 + dcql: 0.2.13(typescript@5.3.3) did-resolver: 4.1.0 - jsonpath: 1.1.1 lru_map: 0.4.1 luxon: 3.5.0 make-error: 1.3.6 @@ -11839,12 +11528,13 @@ snapshots: - expo - react-native - supports-color + - typescript - web-streams-polyfill - '@credo-ts/indy-vdr@0.6.0-alpha-20241120153226(@hyperledger/anoncreds-shared@0.2.4)(@hyperledger/indy-vdr-shared@0.2.2)(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1))(web-streams-polyfill@3.3.3)': + '@credo-ts/indy-vdr@0.6.0-pr-2100-20241124170219(@hyperledger/anoncreds-shared@0.2.4)(@hyperledger/indy-vdr-shared@0.2.2)(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1))(typescript@5.3.3)(web-streams-polyfill@3.3.3)': dependencies: - '@credo-ts/anoncreds': 0.6.0-alpha-20241120153226(@hyperledger/anoncreds-shared@0.2.4)(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1))(web-streams-polyfill@3.3.3) - '@credo-ts/core': 0.6.0-alpha-20241120153226(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1))(web-streams-polyfill@3.3.3) + '@credo-ts/anoncreds': 0.6.0-pr-2100-20241124170219(@hyperledger/anoncreds-shared@0.2.4)(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1))(typescript@5.3.3)(web-streams-polyfill@3.3.3) + '@credo-ts/core': 0.6.0-pr-2100-20241124170219(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1))(typescript@5.3.3)(web-streams-polyfill@3.3.3) '@hyperledger/indy-vdr-shared': 0.2.2 transitivePeerDependencies: - '@hyperledger/anoncreds-shared' @@ -11853,48 +11543,31 @@ snapshots: - expo - react-native - supports-color + - typescript - web-streams-polyfill - '@credo-ts/openid4vc@0.6.0-alpha-20241120153226(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1))(typescript@5.3.3)(web-streams-polyfill@3.3.3)': + '@credo-ts/openid4vc@0.6.0-pr-2100-20241124170219(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1))(typescript@5.3.3)(web-streams-polyfill@3.3.3)': dependencies: - '@animo-id/oauth2': 0.1.4-alpha-20241120145259(typescript@5.3.3) - '@animo-id/oid4vci': 0.1.4-alpha-20241120145259(typescript@5.3.3) - '@credo-ts/core': 0.6.0-alpha-20241120153226(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1))(web-streams-polyfill@3.3.3) - '@sphereon/did-auth-siop': 0.16.1-fix.173(typescript@5.3.3) - '@sphereon/oid4vc-common': 0.16.1-fix.173 + '@animo-id/oauth2': 0.1.4(typescript@5.3.3) + '@animo-id/oid4vci': 0.1.4(typescript@5.3.3) + '@credo-ts/core': 0.6.0-pr-2100-20241124170219(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1))(typescript@5.3.3)(web-streams-polyfill@3.3.3) + '@sphereon/did-auth-siop': https://gitpkg.vercel.app/animo/OID4VC/packages/siop-oid4vp?funke(typescript@5.3.3) + '@sphereon/oid4vc-common': https://gitpkg.vercel.app/animo/OID4VC/packages/common?funke '@sphereon/ssi-types': 0.30.2-next.135 class-transformer: 0.5.1 rxjs: 7.8.1 - zod: 3.23.8 transitivePeerDependencies: - - '@google-cloud/spanner' - - '@sap/hana-client' - - better-sqlite3 - domexception - encoding - expo - - hdb-pool - - ioredis - - mongodb - - mssql - - mysql2 - - oracledb - - pg - - pg-native - - pg-query-stream - react-native - - redis - - sql.js - - sqlite3 - supports-color - - ts-node - - typeorm-aurora-data-api-driver - typescript - web-streams-polyfill - '@credo-ts/question-answer@0.6.0-alpha-20241120153226(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1))(web-streams-polyfill@3.3.3)': + '@credo-ts/question-answer@0.6.0-pr-2100-20241124170219(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1))(typescript@5.3.3)(web-streams-polyfill@3.3.3)': dependencies: - '@credo-ts/core': 0.6.0-alpha-20241120153226(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1))(web-streams-polyfill@3.3.3) + '@credo-ts/core': 0.6.0-pr-2100-20241124170219(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1))(typescript@5.3.3)(web-streams-polyfill@3.3.3) class-transformer: 0.5.1 class-validator: 0.14.1 rxjs: 7.8.1 @@ -11904,19 +11577,20 @@ snapshots: - expo - react-native - supports-color + - typescript - web-streams-polyfill - '@credo-ts/react-hooks@0.6.1(@credo-ts/core@0.6.0-alpha-20241120153226(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1))(web-streams-polyfill@3.3.3))(@credo-ts/question-answer@0.6.0-alpha-20241120153226(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1))(web-streams-polyfill@3.3.3))(react@18.3.1)': + '@credo-ts/react-hooks@0.6.1(@credo-ts/core@0.6.0-pr-2100-20241124170219(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1))(typescript@5.3.3)(web-streams-polyfill@3.3.3))(@credo-ts/question-answer@0.6.0-pr-2100-20241124170219(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1))(typescript@5.3.3)(web-streams-polyfill@3.3.3))(react@18.3.1)': dependencies: - '@credo-ts/core': 0.6.0-alpha-20241120153226(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1))(web-streams-polyfill@3.3.3) - '@credo-ts/question-answer': 0.6.0-alpha-20241120153226(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1))(web-streams-polyfill@3.3.3) + '@credo-ts/core': 0.6.0-pr-2100-20241124170219(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1))(typescript@5.3.3)(web-streams-polyfill@3.3.3) + '@credo-ts/question-answer': 0.6.0-pr-2100-20241124170219(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1))(typescript@5.3.3)(web-streams-polyfill@3.3.3) react: 18.3.1 rxjs: 7.8.1 - '@credo-ts/react-native@0.6.0-alpha-20241120153226(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native-fs@2.20.0(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1)))(react-native-get-random-values@1.11.0(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1)))(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1))(web-streams-polyfill@3.3.3)': + '@credo-ts/react-native@0.6.0-pr-2100-20241124170219(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native-fs@2.20.0(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1)))(react-native-get-random-values@1.11.0(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1)))(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1))(typescript@5.3.3)(web-streams-polyfill@3.3.3)': dependencies: '@azure/core-asynciterator-polyfill': 1.0.2 - '@credo-ts/core': 0.6.0-alpha-20241120153226(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1))(web-streams-polyfill@3.3.3) + '@credo-ts/core': 0.6.0-pr-2100-20241124170219(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1))(typescript@5.3.3)(web-streams-polyfill@3.3.3) events: 3.3.0 react-native: 0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1) react-native-fs: 2.20.0(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1)) @@ -11926,6 +11600,7 @@ snapshots: - encoding - expo - supports-color + - typescript - web-streams-polyfill '@digitalbazaar/bitstring@3.1.0': @@ -12403,80 +12078,6 @@ snapshots: '@esbuild/win32-x64@0.23.1': optional: true - '@ethersproject/address@5.7.0': - dependencies: - '@ethersproject/bignumber': 5.7.0 - '@ethersproject/bytes': 5.7.0 - '@ethersproject/keccak256': 5.7.0 - '@ethersproject/logger': 5.7.0 - '@ethersproject/rlp': 5.7.0 - - '@ethersproject/bignumber@5.7.0': - dependencies: - '@ethersproject/bytes': 5.7.0 - '@ethersproject/logger': 5.7.0 - bn.js: 5.2.1 - - '@ethersproject/bytes@5.7.0': - dependencies: - '@ethersproject/logger': 5.7.0 - - '@ethersproject/constants@5.7.0': - dependencies: - '@ethersproject/bignumber': 5.7.0 - - '@ethersproject/keccak256@5.7.0': - dependencies: - '@ethersproject/bytes': 5.7.0 - js-sha3: 0.8.0 - - '@ethersproject/logger@5.7.0': {} - - '@ethersproject/networks@5.7.1': - dependencies: - '@ethersproject/logger': 5.7.0 - - '@ethersproject/properties@5.7.0': - dependencies: - '@ethersproject/logger': 5.7.0 - - '@ethersproject/random@5.7.0': - dependencies: - '@ethersproject/bytes': 5.7.0 - '@ethersproject/logger': 5.7.0 - - '@ethersproject/rlp@5.7.0': - dependencies: - '@ethersproject/bytes': 5.7.0 - '@ethersproject/logger': 5.7.0 - - '@ethersproject/signing-key@5.7.0': - dependencies: - '@ethersproject/bytes': 5.7.0 - '@ethersproject/logger': 5.7.0 - '@ethersproject/properties': 5.7.0 - bn.js: 5.2.1 - elliptic: 6.5.4 - hash.js: 1.1.7 - - '@ethersproject/strings@5.7.0': - dependencies: - '@ethersproject/bytes': 5.7.0 - '@ethersproject/constants': 5.7.0 - '@ethersproject/logger': 5.7.0 - - '@ethersproject/transactions@5.7.0': - dependencies: - '@ethersproject/address': 5.7.0 - '@ethersproject/bignumber': 5.7.0 - '@ethersproject/bytes': 5.7.0 - '@ethersproject/constants': 5.7.0 - '@ethersproject/keccak256': 5.7.0 - '@ethersproject/logger': 5.7.0 - '@ethersproject/properties': 5.7.0 - '@ethersproject/rlp': 5.7.0 - '@ethersproject/signing-key': 5.7.0 - '@expo-google-fonts/open-sans@0.2.3': {} '@expo-google-fonts/raleway@0.2.3': {} @@ -13297,8 +12898,6 @@ snapshots: pump: 3.0.2 tar-fs: 2.1.1 - '@noble/ciphers@0.4.1': {} - '@noble/ciphers@0.5.3': {} '@noble/curves@1.6.0': @@ -14600,12 +14199,7 @@ snapshots: '@sd-jwt/types': 0.7.2 '@sd-jwt/utils': 0.7.2 - '@sd-jwt/decode@0.6.1': - dependencies: - '@sd-jwt/types': 0.6.1 - '@sd-jwt/utils': 0.6.1 - - '@sd-jwt/decode@0.7.2': + '@sd-jwt/decode@0.7.2': dependencies: '@sd-jwt/types': 0.7.2 '@sd-jwt/utils': 0.7.2 @@ -14628,15 +14222,8 @@ snapshots: '@sd-jwt/jwt-status-list': 0.7.2 '@sd-jwt/utils': 0.7.2 - '@sd-jwt/types@0.6.1': {} - '@sd-jwt/types@0.7.2': {} - '@sd-jwt/utils@0.6.1': - dependencies: - '@sd-jwt/types': 0.6.1 - js-base64: 3.7.7 - '@sd-jwt/utils@0.7.2': dependencies: '@sd-jwt/types': 0.7.2 @@ -14667,15 +14254,16 @@ snapshots: '@sovpro/delimited-stream@1.1.0': {} - '@sphereon/did-auth-siop@0.16.1-fix.173(typescript@5.3.3)': + '@sphereon/did-auth-siop@https://gitpkg.vercel.app/animo/OID4VC/packages/siop-oid4vp?funke(typescript@5.3.3)': dependencies: '@astronautlabs/jsonpath': 1.1.2 - '@sphereon/jarm': 0.16.1-fix.173(typescript@5.3.3) - '@sphereon/oid4vc-common': 0.16.1-fix.173 + '@sphereon/jarm': https://gitpkg.vercel.app/animo/OID4VC/packages/jarm?funke(typescript@5.3.3) + '@sphereon/oid4vc-common': https://gitpkg.vercel.app/animo/OID4VC/packages/common?funke '@sphereon/pex': 5.0.0-unstable.24 '@sphereon/pex-models': 2.3.1 - '@sphereon/ssi-types': 0.30.2-next.129 + '@sphereon/ssi-types': 0.30.2-next.279 cross-fetch: 4.0.0 + dcql: 0.2.13(typescript@5.3.3) debug: 4.3.7 events: 3.3.0 jwt-decode: 4.0.0 @@ -14684,93 +14272,33 @@ snapshots: qs: 6.13.0 uint8arrays: 3.1.1 transitivePeerDependencies: - - '@google-cloud/spanner' - - '@sap/hana-client' - - better-sqlite3 - encoding - - hdb-pool - - ioredis - - mongodb - - mssql - - mysql2 - - oracledb - - pg - - pg-native - - pg-query-stream - - redis - - sql.js - - sqlite3 - supports-color - - ts-node - - typeorm-aurora-data-api-driver - typescript - '@sphereon/did-uni-client@0.6.3': + '@sphereon/jarm@https://gitpkg.vercel.app/animo/OID4VC/packages/jarm?funke(typescript@5.3.3)': dependencies: - cross-fetch: 3.1.8 - did-resolver: 4.1.0 - transitivePeerDependencies: - - encoding - - '@sphereon/jarm@0.16.1-fix.173(typescript@5.3.3)': - dependencies: - '@sphereon/oid4vc-common': 0.16.1-fix.173 + '@sphereon/oid4vc-common': https://gitpkg.vercel.app/animo/OID4VC/packages/common?funke valibot: 0.42.1(typescript@5.3.3) transitivePeerDependencies: - - '@google-cloud/spanner' - - '@sap/hana-client' - - better-sqlite3 - - encoding - - hdb-pool - - ioredis - - mongodb - - mssql - - mysql2 - - oracledb - - pg - - pg-native - - pg-query-stream - - redis - - sql.js - - sqlite3 - supports-color - - ts-node - - typeorm-aurora-data-api-driver - typescript - '@sphereon/kmp-mdl-mdoc@0.2.0-SNAPSHOT.22': + '@sphereon/kmp-mdl-mdoc@0.2.0-SNAPSHOT.22(patch_hash=7x5lo6qr5h5rmsca3oezb2kbdy)': dependencies: '@js-joda/core': 5.6.3 '@js-joda/timezone': 2.3.0(@js-joda/core@5.6.3) format-util: 1.0.5 - '@sphereon/oid4vc-common@0.16.1-fix.173': + '@sphereon/oid4vc-common@https://gitpkg.vercel.app/animo/OID4VC/packages/common?funke': dependencies: - '@sphereon/ssi-types': 0.30.1 + '@sphereon/ssi-types': 0.30.2-next.279 jwt-decode: 4.0.0 sha.js: 2.4.11 uint8arrays: 3.1.1 uuid: 9.0.1 transitivePeerDependencies: - - '@google-cloud/spanner' - - '@sap/hana-client' - - better-sqlite3 - - encoding - - hdb-pool - - ioredis - - mongodb - - mssql - - mysql2 - - oracledb - - pg - - pg-native - - pg-query-stream - - redis - - sql.js - - sqlite3 - supports-color - - ts-node - - typeorm-aurora-data-api-driver '@sphereon/pex-models@2.3.1': {} @@ -14790,292 +14318,40 @@ snapshots: transitivePeerDependencies: - supports-color - '@sphereon/pex@5.0.0-unstable.25': - dependencies: - '@astronautlabs/jsonpath': 1.1.2 - '@sd-jwt/decode': 0.7.2 - '@sd-jwt/present': 0.7.2 - '@sd-jwt/types': 0.7.2 - '@sphereon/pex-models': 2.3.1 - '@sphereon/ssi-types': 0.30.2-next.135 - ajv: 8.17.1 - ajv-formats: 2.1.1(ajv@8.17.1) - jwt-decode: 3.1.2 - nanoid: 3.3.7 - uint8arrays: 3.1.1 - transitivePeerDependencies: - - supports-color - - '@sphereon/ssi-sdk-ext.did-utils@0.24.1-unstable.130': - dependencies: - '@ethersproject/networks': 5.7.1 - '@ethersproject/transactions': 5.7.0 - '@sphereon/did-uni-client': 0.6.3 - '@sphereon/ssi-sdk-ext.key-utils': 0.24.1-unstable.130 - '@sphereon/ssi-sdk-ext.x509-utils': 0.24.1-unstable.130 - '@sphereon/ssi-sdk.agent-config': 0.29.1-unstable.161 - '@sphereon/ssi-sdk.core': 0.29.1-unstable.161 - '@sphereon/ssi-types': 0.29.1-unstable.161 - '@stablelib/ed25519': 1.0.3 - '@veramo/core': 4.2.0 - '@veramo/utils': 4.2.0 - did-jwt: 6.11.6 - did-resolver: 4.1.0 - elliptic: 6.6.0 - uint8arrays: 3.1.1 - transitivePeerDependencies: - - '@google-cloud/spanner' - - '@sap/hana-client' - - better-sqlite3 - - encoding - - hdb-pool - - ioredis - - mongodb - - mssql - - mysql2 - - oracledb - - pg - - pg-native - - pg-query-stream - - redis - - sql.js - - sqlite3 - - supports-color - - ts-node - - typeorm-aurora-data-api-driver - - '@sphereon/ssi-sdk-ext.identifier-resolution@0.24.1-unstable.130': - dependencies: - '@sphereon/ssi-sdk-ext.did-utils': 0.24.1-unstable.130 - '@sphereon/ssi-sdk-ext.key-utils': 0.24.1-unstable.130 - '@sphereon/ssi-sdk-ext.x509-utils': 0.24.1-unstable.130 - '@sphereon/ssi-sdk.agent-config': 0.29.1-unstable.161 - '@sphereon/ssi-types': 0.29.1-unstable.161 - '@veramo/core': 4.2.0 - '@veramo/utils': 4.2.0 - debug: 4.3.7 - pkijs: 3.2.4 - uint8arrays: 3.1.1 - transitivePeerDependencies: - - '@google-cloud/spanner' - - '@sap/hana-client' - - better-sqlite3 - - encoding - - hdb-pool - - ioredis - - mongodb - - mssql - - mysql2 - - oracledb - - pg - - pg-native - - pg-query-stream - - redis - - sql.js - - sqlite3 - - supports-color - - ts-node - - typeorm-aurora-data-api-driver - - '@sphereon/ssi-sdk-ext.jwt-service@0.24.1-unstable.130': - dependencies: - '@sphereon/ssi-sdk-ext.did-utils': 0.24.1-unstable.130 - '@sphereon/ssi-sdk-ext.identifier-resolution': 0.24.1-unstable.130 - '@sphereon/ssi-sdk-ext.key-manager': 0.24.1-unstable.130 - '@sphereon/ssi-sdk-ext.key-utils': 0.24.1-unstable.130 - '@sphereon/ssi-sdk-ext.x509-utils': 0.24.1-unstable.130 - '@sphereon/ssi-sdk.agent-config': 0.29.1-unstable.161 - '@sphereon/ssi-types': 0.29.1-unstable.161 - '@veramo/core': 4.2.0 - '@veramo/utils': 4.2.0 - debug: 4.3.7 - jwt-decode: 4.0.0 - uint8arrays: 3.1.1 - transitivePeerDependencies: - - '@google-cloud/spanner' - - '@sap/hana-client' - - better-sqlite3 - - encoding - - hdb-pool - - ioredis - - mongodb - - mssql - - mysql2 - - oracledb - - pg - - pg-native - - pg-query-stream - - redis - - sql.js - - sqlite3 - - supports-color - - ts-node - - typeorm-aurora-data-api-driver - - '@sphereon/ssi-sdk-ext.key-manager@0.24.1-unstable.130': - dependencies: - '@veramo/core': 4.2.0 - '@veramo/key-manager': 4.2.0 - uint8arrays: 3.1.1 - transitivePeerDependencies: - - supports-color - - '@sphereon/ssi-sdk-ext.key-utils@0.24.1-unstable.130': - dependencies: - '@ethersproject/random': 5.7.0 - '@sphereon/ssi-sdk-ext.x509-utils': 0.24.1-unstable.130 - '@sphereon/ssi-types': 0.29.1-unstable.161 - '@stablelib/ed25519': 1.0.3 - '@stablelib/sha256': 1.0.1 - '@stablelib/sha512': 1.0.1 - '@trust/keyto': 1.0.1 - '@veramo/core': 4.2.0 - base64url: 3.0.1 - debug: 4.3.7 - did-resolver: 4.1.0 - elliptic: 6.6.0 - lodash.isplainobject: 4.0.6 - multiformats: 9.9.0 - uint8arrays: 3.1.1 - varint: 6.0.0 - web-encoding: 1.1.5 - transitivePeerDependencies: - - supports-color - - '@sphereon/ssi-sdk-ext.x509-utils@0.24.1-unstable.130': - dependencies: - '@trust/keyto': 1.0.1 - debug: 4.3.7 - js-x509-utils: 1.0.7 - pkijs: 3.2.4 - uint8arrays: 3.1.1 - transitivePeerDependencies: - - supports-color - - '@sphereon/ssi-sdk.agent-config@0.29.1-unstable.161': - dependencies: - '@veramo/core': 4.2.0 - debug: 4.3.7 - jsonpointer: 5.0.1 - typeorm: 0.3.20 - url-parse: 1.5.10 - yaml: 2.6.0 - transitivePeerDependencies: - - '@google-cloud/spanner' - - '@sap/hana-client' - - better-sqlite3 - - hdb-pool - - ioredis - - mongodb - - mssql - - mysql2 - - oracledb - - pg - - pg-native - - pg-query-stream - - redis - - sql.js - - sqlite3 - - supports-color - - ts-node - - typeorm-aurora-data-api-driver - - '@sphereon/ssi-sdk.core@0.29.1-unstable.161': - dependencies: - '@sphereon/ssi-types': 0.29.1-unstable.161 - '@veramo/core': 4.2.0 - cross-fetch: 3.1.8 - debug: 4.3.7 - image-size: 2.0.0-beta.2 - uint8arrays: 3.1.1 - transitivePeerDependencies: - - encoding - - supports-color - - '@sphereon/ssi-types@0.29.1-unstable.161': - dependencies: - '@sd-jwt/decode': 0.6.1 - debug: 4.3.7 - events: 3.3.0 - jwt-decode: 3.1.2 - transitivePeerDependencies: - - supports-color - - '@sphereon/ssi-types@0.30.1': + '@sphereon/ssi-types@0.30.2-next.129': dependencies: '@sd-jwt/decode': 0.7.2 - '@sphereon/kmp-mdl-mdoc': 0.2.0-SNAPSHOT.22 - '@sphereon/ssi-sdk-ext.jwt-service': 0.24.1-unstable.130 + '@sphereon/kmp-mdl-mdoc': 0.2.0-SNAPSHOT.22(patch_hash=7x5lo6qr5h5rmsca3oezb2kbdy) debug: 4.3.7 events: 3.3.0 jwt-decode: 3.1.2 transitivePeerDependencies: - - '@google-cloud/spanner' - - '@sap/hana-client' - - better-sqlite3 - - encoding - - hdb-pool - - ioredis - - mongodb - - mssql - - mysql2 - - oracledb - - pg - - pg-native - - pg-query-stream - - redis - - sql.js - - sqlite3 - supports-color - - ts-node - - typeorm-aurora-data-api-driver - '@sphereon/ssi-types@0.30.2-next.129': + '@sphereon/ssi-types@0.30.2-next.135': dependencies: '@sd-jwt/decode': 0.7.2 - '@sphereon/kmp-mdl-mdoc': 0.2.0-SNAPSHOT.22 + '@sphereon/kmp-mdl-mdoc': 0.2.0-SNAPSHOT.22(patch_hash=7x5lo6qr5h5rmsca3oezb2kbdy) debug: 4.3.7 events: 3.3.0 jwt-decode: 3.1.2 transitivePeerDependencies: - supports-color - '@sphereon/ssi-types@0.30.2-next.135': + '@sphereon/ssi-types@0.30.2-next.279': dependencies: '@sd-jwt/decode': 0.7.2 - '@sphereon/kmp-mdl-mdoc': 0.2.0-SNAPSHOT.22 + '@sphereon/kmp-mdl-mdoc': 0.2.0-SNAPSHOT.22(patch_hash=7x5lo6qr5h5rmsca3oezb2kbdy) debug: 4.3.7 events: 3.3.0 jwt-decode: 3.1.2 transitivePeerDependencies: - supports-color - '@sqltools/formatter@1.2.5': {} - - '@stablelib/aead@1.0.1': {} - '@stablelib/binary@1.0.1': dependencies: '@stablelib/int': 1.0.1 - '@stablelib/bytes@1.0.1': {} - - '@stablelib/chacha20poly1305@1.0.1': - dependencies: - '@stablelib/aead': 1.0.1 - '@stablelib/binary': 1.0.1 - '@stablelib/chacha': 1.0.1 - '@stablelib/constant-time': 1.0.1 - '@stablelib/poly1305': 1.0.1 - '@stablelib/wipe': 1.0.1 - - '@stablelib/chacha@1.0.1': - dependencies: - '@stablelib/binary': 1.0.1 - '@stablelib/wipe': 1.0.1 - - '@stablelib/constant-time@1.0.1': {} - '@stablelib/ed25519@1.0.3': dependencies: '@stablelib/random': 1.0.2 @@ -15086,26 +14362,11 @@ snapshots: '@stablelib/int@1.0.1': {} - '@stablelib/keyagreement@1.0.1': - dependencies: - '@stablelib/bytes': 1.0.1 - - '@stablelib/poly1305@1.0.1': - dependencies: - '@stablelib/constant-time': 1.0.1 - '@stablelib/wipe': 1.0.1 - '@stablelib/random@1.0.2': dependencies: '@stablelib/binary': 1.0.1 '@stablelib/wipe': 1.0.1 - '@stablelib/sha256@1.0.1': - dependencies: - '@stablelib/binary': 1.0.1 - '@stablelib/hash': 1.0.1 - '@stablelib/wipe': 1.0.1 - '@stablelib/sha512@1.0.1': dependencies: '@stablelib/binary': 1.0.1 @@ -15114,26 +14375,6 @@ snapshots: '@stablelib/wipe@1.0.1': {} - '@stablelib/x25519@1.0.3': - dependencies: - '@stablelib/keyagreement': 1.0.1 - '@stablelib/random': 1.0.2 - '@stablelib/wipe': 1.0.1 - - '@stablelib/xchacha20@1.0.1': - dependencies: - '@stablelib/binary': 1.0.1 - '@stablelib/chacha': 1.0.1 - '@stablelib/wipe': 1.0.1 - - '@stablelib/xchacha20poly1305@1.0.1': - dependencies: - '@stablelib/aead': 1.0.1 - '@stablelib/chacha20poly1305': 1.0.1 - '@stablelib/constant-time': 1.0.1 - '@stablelib/wipe': 1.0.1 - '@stablelib/xchacha20': 1.0.1 - '@storybook/addon-actions@7.6.20': dependencies: '@storybook/core-events': 7.6.20 @@ -16965,12 +16206,6 @@ snapshots: '@tokenizer/token@0.3.0': {} - '@trust/keyto@1.0.1': - dependencies: - asn1.js: 5.4.1 - base64url: 3.0.1 - elliptic: 6.6.0 - '@types/babel__core@7.20.5': dependencies: '@babel/parser': 7.26.2 @@ -17101,7 +16336,11 @@ snapshots: '@types/node-forge@1.3.11': dependencies: - '@types/node': 22.8.6 + '@types/node': 18.18.8 + + '@types/node@18.18.8': + dependencies: + undici-types: 5.26.5 '@types/node@18.19.63': dependencies: @@ -17197,48 +16436,6 @@ snapshots: '@urql/core': 5.0.8(graphql@15.8.0) wonka: 6.3.4 - '@veramo/core@4.2.0': - dependencies: - credential-status: 2.0.6 - debug: 4.3.7 - did-jwt-vc: 3.2.15 - did-resolver: 4.1.0 - events: 3.3.0 - z-schema: 5.0.5 - transitivePeerDependencies: - - supports-color - - '@veramo/key-manager@4.2.0': - dependencies: - '@ethersproject/bytes': 5.7.0 - '@ethersproject/strings': 5.7.0 - '@ethersproject/transactions': 5.7.0 - '@stablelib/ed25519': 1.0.3 - '@veramo/core': 4.2.0 - did-jwt: 6.11.6 - uint8arrays: 3.1.1 - uuid: 9.0.1 - transitivePeerDependencies: - - supports-color - - '@veramo/utils@4.2.0': - dependencies: - '@ethersproject/transactions': 5.7.0 - '@stablelib/ed25519': 1.0.3 - '@veramo/core': 4.2.0 - blakejs: 1.2.1 - cross-fetch: 3.1.8 - debug: 4.3.7 - did-jwt: 6.11.6 - did-jwt-vc: 3.2.15 - did-resolver: 4.1.0 - elliptic: 6.6.0 - multiformats: 9.7.1 - uint8arrays: 3.1.1 - transitivePeerDependencies: - - encoding - - supports-color - '@web3-storage/multipart-parser@1.0.0': {} '@webassemblyjs/ast@1.12.1': @@ -17456,8 +16653,6 @@ snapshots: app-root-dir@1.0.2: {} - app-root-path@3.1.0: {} - appdirsjs@1.2.7: {} application-config-path@0.1.1: {} @@ -17507,17 +16702,6 @@ snapshots: asmcrypto.js@0.22.0: {} - asn1.js-rfc5280@3.0.0: - dependencies: - asn1.js: 5.4.1 - - asn1.js@5.4.1: - dependencies: - bn.js: 4.12.0 - inherits: 2.0.4 - minimalistic-assert: 1.0.1 - safer-buffer: 2.1.2 - asn1js@3.0.5: dependencies: pvtsutils: 1.3.5 @@ -17776,8 +16960,6 @@ snapshots: bech32@1.1.4: {} - bech32@2.0.0: {} - better-opn@3.0.2: dependencies: open: 8.4.2 @@ -17796,8 +16978,6 @@ snapshots: inherits: 2.0.4 readable-stream: 3.6.2 - blakejs@1.2.1: {} - bn.js@4.12.0: {} bn.js@5.2.1: {} @@ -17920,8 +17100,6 @@ snapshots: bytes@3.1.2: {} - bytestreamjs@2.0.1: {} - cacache@18.0.4: dependencies: '@npmcli/fs': 3.1.1 @@ -18033,7 +17211,7 @@ snapshots: chrome-launcher@0.15.2: dependencies: - '@types/node': 22.8.6 + '@types/node': 18.18.8 escape-string-regexp: 4.0.0 is-wsl: 2.2.0 lighthouse-logger: 1.4.2 @@ -18085,15 +17263,6 @@ snapshots: dependencies: restore-cursor: 3.1.0 - cli-highlight@2.1.11: - dependencies: - chalk: 4.1.2 - highlight.js: 10.7.3 - mz: 2.7.0 - parse5: 5.1.1 - parse5-htmlparser2-tree-adapter: 6.0.1 - yargs: 16.2.0 - cli-spinners@2.9.2: {} cli-table3@0.6.5: @@ -18108,12 +17277,6 @@ snapshots: strip-ansi: 6.0.1 wrap-ansi: 6.2.0 - cliui@7.0.4: - dependencies: - string-width: 4.2.3 - strip-ansi: 6.0.1 - wrap-ansi: 7.0.0 - cliui@8.0.1: dependencies: string-width: 4.2.3 @@ -18276,17 +17439,12 @@ snapshots: long: 4.0.0 protobufjs: 6.11.4 - credential-status@2.0.6: - dependencies: - did-jwt: 6.11.6 - did-resolver: 4.1.0 - credentials-context@2.0.0: {} - credo-ts-didweb-anoncreds@0.0.1-alpha.13(@credo-ts/anoncreds@0.6.0-alpha-20241120153226(@hyperledger/anoncreds-shared@0.2.4)(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1))(web-streams-polyfill@3.3.3))(@credo-ts/core@0.6.0-alpha-20241120153226(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1))(web-streams-polyfill@3.3.3))(@hyperledger/anoncreds-shared@0.2.4): + credo-ts-didweb-anoncreds@0.0.1-alpha.13(@credo-ts/anoncreds@0.6.0-pr-2100-20241124170219(@hyperledger/anoncreds-shared@0.2.4)(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1))(typescript@5.3.3)(web-streams-polyfill@3.3.3))(@credo-ts/core@0.6.0-pr-2100-20241124170219(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1))(typescript@5.3.3)(web-streams-polyfill@3.3.3))(@hyperledger/anoncreds-shared@0.2.4): dependencies: - '@credo-ts/anoncreds': 0.6.0-alpha-20241120153226(@hyperledger/anoncreds-shared@0.2.4)(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1))(web-streams-polyfill@3.3.3) - '@credo-ts/core': 0.6.0-alpha-20241120153226(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1))(web-streams-polyfill@3.3.3) + '@credo-ts/anoncreds': 0.6.0-pr-2100-20241124170219(@hyperledger/anoncreds-shared@0.2.4)(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1))(typescript@5.3.3)(web-streams-polyfill@3.3.3) + '@credo-ts/core': 0.6.0-pr-2100-20241124170219(expo@51.0.39(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0)))(react-native@0.76.1(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@react-native-community/cli-server-api@15.1.0)(@types/react@18.2.79)(react@18.3.1))(typescript@5.3.3)(web-streams-polyfill@3.3.3) '@hyperledger/anoncreds-shared': 0.2.4 canonicalize: 1.0.8 query-string: 7.1.3 @@ -18407,6 +17565,12 @@ snapshots: dayjs@1.11.13: {} + dcql@0.2.13(typescript@5.3.3): + dependencies: + valibot: 0.37.0(typescript@5.3.3) + transitivePeerDependencies: + - typescript + debug@2.6.9: dependencies: ms: 2.0.0 @@ -18495,11 +17659,6 @@ snapshots: dequal@2.0.3: {} - des.js@1.1.0: - dependencies: - inherits: 2.0.4 - minimalistic-assert: 1.0.1 - destroy@1.2.0: {} detect-indent@6.1.0: {} @@ -18521,38 +17680,6 @@ snapshots: transitivePeerDependencies: - supports-color - did-jwt-vc@3.2.15: - dependencies: - did-jwt: 7.4.7 - did-resolver: 4.1.0 - - did-jwt@6.11.6: - dependencies: - '@stablelib/ed25519': 1.0.3 - '@stablelib/random': 1.0.2 - '@stablelib/sha256': 1.0.1 - '@stablelib/x25519': 1.0.3 - '@stablelib/xchacha20poly1305': 1.0.1 - bech32: 2.0.0 - canonicalize: 2.0.0 - did-resolver: 4.1.0 - elliptic: 6.6.0 - js-sha3: 0.8.0 - multiformats: 9.9.0 - uint8arrays: 3.1.1 - - did-jwt@7.4.7: - dependencies: - '@noble/ciphers': 0.4.1 - '@noble/curves': 1.6.0 - '@noble/hashes': 1.5.0 - '@scure/base': 1.1.9 - canonicalize: 2.0.0 - did-resolver: 4.1.0 - multibase: 4.0.6 - multiformats: 9.9.0 - uint8arrays: 3.1.1 - did-jwt@8.0.4: dependencies: '@noble/ciphers': 0.5.3 @@ -18657,26 +17784,6 @@ snapshots: electron-to-chromium@1.5.50: {} - elliptic@6.5.4: - dependencies: - bn.js: 4.12.0 - brorand: 1.1.0 - hash.js: 1.1.7 - hmac-drbg: 1.0.1 - inherits: 2.0.4 - minimalistic-assert: 1.0.1 - minimalistic-crypto-utils: 1.0.1 - - elliptic@6.5.7: - dependencies: - bn.js: 4.12.0 - brorand: 1.1.0 - hash.js: 1.1.7 - hmac-drbg: 1.0.1 - inherits: 2.0.4 - minimalistic-assert: 1.0.1 - minimalistic-crypto-utils: 1.0.1 - elliptic@6.6.0: dependencies: bn.js: 4.12.0 @@ -18953,8 +18060,6 @@ snapshots: esm-resolve@1.0.11: {} - esprima@1.2.2: {} - esprima@4.0.1: {} esrecurse@4.3.0: @@ -19996,8 +19101,6 @@ snapshots: dependencies: source-map: 0.7.4 - highlight.js@10.7.3: {} - hmac-drbg@1.0.1: dependencies: hash.js: 1.1.7 @@ -20093,8 +19196,6 @@ snapshots: dependencies: queue: 6.0.2 - image-size@2.0.0-beta.2: {} - import-fresh@2.0.0: dependencies: caller-path: 2.0.0 @@ -20462,87 +19563,8 @@ snapshots: js-base64@3.7.7: {} - js-crypto-aes@1.0.6: - dependencies: - js-crypto-env: 1.0.5 - - js-crypto-ec@1.0.7: - dependencies: - asn1.js: 5.4.1 - buffer: 6.0.3 - elliptic: 6.5.7 - js-crypto-env: 1.0.5 - js-crypto-hash: 1.0.7 - js-crypto-key-utils: 1.0.7 - js-crypto-random: 1.0.5 - js-encoding-utils: 0.7.3 - - js-crypto-env@1.0.5: {} - - js-crypto-hash@1.0.7: - dependencies: - buffer: 6.0.3 - hash.js: 1.1.7 - js-crypto-env: 1.0.5 - md5: 2.3.0 - sha3: 2.1.4 - - js-crypto-hmac@1.0.7: - dependencies: - js-crypto-env: 1.0.5 - js-crypto-hash: 1.0.7 - - js-crypto-key-utils@1.0.7: - dependencies: - asn1.js: 5.4.1 - buffer: 6.0.3 - des.js: 1.1.0 - elliptic: 6.5.7 - js-crypto-aes: 1.0.6 - js-crypto-hash: 1.0.7 - js-crypto-pbkdf: 1.0.7 - js-crypto-random: 1.0.5 - js-encoding-utils: 0.7.3 - lodash.clonedeep: 4.5.0 - - js-crypto-pbkdf@1.0.7: - dependencies: - js-crypto-hash: 1.0.7 - js-crypto-hmac: 1.0.7 - js-encoding-utils: 0.7.3 - - js-crypto-random@1.0.5: - dependencies: - js-crypto-env: 1.0.5 - - js-crypto-rsa@1.0.7: - dependencies: - bn.js: 5.2.1 - buffer: 6.0.3 - js-crypto-env: 1.0.5 - js-crypto-hash: 1.0.7 - js-crypto-key-utils: 1.0.7 - js-crypto-random: 1.0.5 - js-encoding-utils: 0.7.3 - - js-encoding-utils@0.7.3: {} - - js-sha3@0.8.0: {} - js-tokens@4.0.0: {} - js-x509-utils@1.0.7: - dependencies: - asn1.js: 5.4.1 - asn1.js-rfc5280: 3.0.0 - bn.js: 5.2.1 - buffer: 6.0.3 - js-crypto-ec: 1.0.7 - js-crypto-key-utils: 1.0.7 - js-crypto-random: 1.0.5 - js-crypto-rsa: 1.0.7 - js-encoding-utils: 0.7.3 - js-yaml@3.14.1: dependencies: argparse: 1.0.10 @@ -20671,14 +19693,6 @@ snapshots: transitivePeerDependencies: - web-streams-polyfill - jsonpath@1.1.1: - dependencies: - esprima: 1.2.2 - static-eval: 2.0.2 - underscore: 1.12.1 - - jsonpointer@5.0.1: {} - jwt-decode@3.1.2: {} jwt-decode@4.0.0: {} @@ -20862,16 +19876,8 @@ snapshots: dependencies: p-locate: 6.0.0 - lodash.clonedeep@4.5.0: {} - lodash.debounce@4.0.8: {} - lodash.get@4.4.2: {} - - lodash.isequal@4.5.0: {} - - lodash.isplainobject@4.0.6: {} - lodash.throttle@4.1.1: {} lodash.truncate@4.4.2: {} @@ -21443,8 +20449,6 @@ snapshots: mkdirp@1.0.4: {} - mkdirp@2.1.6: {} - mlly@1.7.2: dependencies: acorn: 8.14.0 @@ -21466,8 +20470,6 @@ snapshots: multiformats@12.1.3: {} - multiformats@9.7.1: {} - multiformats@9.9.0: {} mz@2.7.0: @@ -21772,14 +20774,6 @@ snapshots: dependencies: pngjs: 3.4.0 - parse5-htmlparser2-tree-adapter@6.0.1: - dependencies: - parse5: 6.0.1 - - parse5@5.1.1: {} - - parse5@6.0.1: {} - parseurl@1.3.3: {} pascal-case@3.1.2: @@ -21869,15 +20863,6 @@ snapshots: dependencies: find-up: 3.0.0 - pkijs@3.2.4: - dependencies: - '@noble/hashes': 1.5.0 - asn1js: 3.0.5 - bytestreamjs: 2.0.1 - pvtsutils: 1.3.5 - pvutils: 1.1.3 - tslib: 2.8.1 - plist@3.1.0: dependencies: '@xmldom/xmldom': 0.8.10 @@ -22096,8 +21081,6 @@ snapshots: querystring@0.2.1: {} - querystringify@2.2.0: {} - queue-microtask@1.2.3: {} queue@6.0.2: @@ -22693,8 +21676,6 @@ snapshots: rc: 1.2.8 resolve: 1.7.1 - requires-port@1.0.0: {} - reselect@4.1.8: {} resolve-from@3.0.0: {} @@ -22907,10 +21888,6 @@ snapshots: inherits: 2.0.4 safe-buffer: 5.2.1 - sha3@2.1.4: - dependencies: - buffer: 6.0.3 - shallow-clone@3.0.1: dependencies: kind-of: 6.0.3 @@ -23516,26 +22493,6 @@ snapshots: typedarray@0.0.6: {} - typeorm@0.3.20: - dependencies: - '@sqltools/formatter': 1.2.5 - app-root-path: 3.1.0 - buffer: 6.0.3 - chalk: 4.1.2 - cli-highlight: 2.1.11 - dayjs: 1.11.13 - debug: 4.3.7 - dotenv: 16.4.5 - glob: 10.4.5 - mkdirp: 2.1.6 - reflect-metadata: 0.2.2 - sha.js: 2.4.11 - tslib: 2.8.1 - uuid: 9.0.1 - yargs: 17.7.2 - transitivePeerDependencies: - - supports-color - typescript@5.3.3: {} ua-parser-js@1.0.39: {} @@ -23558,8 +22515,6 @@ snapshots: has-symbols: 1.0.3 which-boxed-primitive: 1.0.2 - underscore@1.12.1: {} - undici-types@5.26.5: {} undici-types@6.19.8: {} @@ -23639,11 +22594,6 @@ snapshots: url-join@4.0.0: {} - url-parse@1.5.10: - dependencies: - querystringify: 2.2.0 - requires-port: 1.0.0 - url@0.11.4: dependencies: punycode: 1.4.1 @@ -23702,6 +22652,10 @@ snapshots: uuid@9.0.1: {} + valibot@0.37.0(typescript@5.3.3): + optionalDependencies: + typescript: 5.3.3 + valibot@0.42.1(typescript@5.3.3): optionalDependencies: typescript: 5.3.3 @@ -23960,8 +22914,6 @@ snapshots: camelcase: 5.3.1 decamelize: 1.2.0 - yargs-parser@20.2.9: {} - yargs-parser@21.1.1: {} yargs@15.4.1: @@ -23978,16 +22930,6 @@ snapshots: y18n: 4.0.3 yargs-parser: 18.1.3 - yargs@16.2.0: - dependencies: - cliui: 7.0.4 - escalade: 3.2.0 - get-caller-file: 2.0.5 - require-directory: 2.1.1 - string-width: 4.2.3 - y18n: 5.0.8 - yargs-parser: 20.2.9 - yargs@17.7.2: dependencies: cliui: 8.0.1 @@ -24007,14 +22949,6 @@ snapshots: yocto-queue@1.1.1: {} - z-schema@5.0.5: - dependencies: - lodash.get: 4.4.2 - lodash.isequal: 4.5.0 - validator: 13.12.0 - optionalDependencies: - commander: 9.5.0 - zod-validation-error@2.1.0(zod@3.23.8): dependencies: zod: 3.23.8 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index e10bc3de..77349e76 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -7,26 +7,29 @@ catalog: react: 18.3.1 "@types/react": ~18.2.79 react-docgen-typescript: 2.2.2 - "@credo-ts/anoncreds": 0.6.0-alpha-20241120153226 - "@credo-ts/askar": 0.6.0-alpha-20241120153226 - "@credo-ts/cheqd": 0.6.0-alpha-20241120153226 - "@credo-ts/core": 0.6.0-alpha-20241120153226 - "@credo-ts/indy-vdr": 0.6.0-alpha-20241120153226 - "@credo-ts/openid4vc": 0.6.0-alpha-20241120153226 - "@credo-ts/question-answer": 0.6.0-alpha-20241120153226 - "@credo-ts/react-native": 0.6.0-alpha-20241120153226 + "@credo-ts/anoncreds": 0.6.0-pr-2100-20241124170219 + "@credo-ts/askar": 0.6.0-pr-2100-20241124170219 + "@credo-ts/cheqd": 0.6.0-pr-2100-20241124170219 + "@credo-ts/core": 0.6.0-pr-2100-20241124170219 + "@credo-ts/indy-vdr": 0.6.0-pr-2100-20241124170219 + "@credo-ts/openid4vc": 0.6.0-pr-2100-20241124170219 + "@credo-ts/question-answer": 0.6.0-pr-2100-20241124170219 + "@credo-ts/react-native": 0.6.0-pr-2100-20241124170219 "@credo-ts/react-hooks": 0.6.1 "@hyperledger/anoncreds-react-native": ^0.2.4 "@hyperledger/aries-askar-react-native": ^0.2.3 "@hyperledger/indy-vdr-react-native": ^0.2.0 typescript: ~5.3.3 + "@sphereon/did-auth-siop": https://gitpkg.vercel.app/animo/OID4VC/packages/siop-oid4vp?funke + "@sphereon/jarm": https://gitpkg.vercel.app/animo/OID4VC/packages/jarm?funke + "@sphereon/oid4vc-common": https://gitpkg.vercel.app/animo/OID4VC/packages/common?funke "@animo-id/expo-ausweis-sdk": 0.0.1-alpha.14 - "@animo-id/oid4vci": 0.1.4-alpha-20241120145259 - "@animo-id/oauth2": 0.1.4-alpha-20241120145259 - "@animo-id/oauth2-utils": 0.1.4-alpha-20241120145259 + "@animo-id/oid4vci": 0.1.4 + "@animo-id/oauth2": 0.1.4 + "@animo-id/oauth2-utils": 0.1.4 "@animo-id/expo-secure-environment": 0.1.0-alpha.11 "@animo-id/expo-mdoc-data-transfer": 0.0.3-alpha.7 - "@animo-id/mdoc": 0.2.38 + "@animo-id/mdoc": 0.2.39 "@unimodules/react-native-adapter": "./noop" "@unimodules/core": "./noop" expo: ~51.0.39 \ No newline at end of file