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 ? (