Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main' into feat/funke-receive-pid
Browse files Browse the repository at this point in the history
  • Loading branch information
TimoGlastra committed Aug 1, 2024
2 parents cf65e07 + e201857 commit 0bb0307
Show file tree
Hide file tree
Showing 75 changed files with 4,726 additions and 3,980 deletions.
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,6 @@ android

# build output
dist/
types/
packages/ui/types

storybook-static
storybook-static
9 changes: 9 additions & 0 deletions apps/funke/agent/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { type FunkeAppAgent, useAgent } from '@package/agent'
import { useSecureUnlock as _useSecureUnlock } from '@package/secure-store/secureUnlock'

export { initializeAppAgent } from './initialize'

export const useAppAgent = useAgent<FunkeAppAgent>
export type AppAgent = FunkeAppAgent

export const useSecureUnlock = () => _useSecureUnlock<{ agent?: AppAgent }>()
12 changes: 12 additions & 0 deletions apps/funke/agent/initialize.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { initializeFunkeAgent } from '@package/agent'
import { trustedCertificates } from '../constants'

export function initializeAppAgent({ walletKey }: { walletKey: string }) {
return initializeFunkeAgent({
keyDerivation: 'raw',
walletId: 'funke-wallet',
walletKey: walletKey,
walletLabel: 'Funke Wallet',
trustedX509Certificates: trustedCertificates,
})
}
16 changes: 16 additions & 0 deletions apps/funke/app.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,30 @@ const { version } = require('./package.json')

const APP_VARIANT = process.env.APP_VARIANT || 'production'

// https://demo.pid-issuer.bundesdruckerei.de
const bdrPidIssuerCertificate = `-----BEGIN CERTIFICATE-----
MIICeTCCAiCgAwIBAgIUB5E9QVZtmUYcDtCjKB/H3VQv72gwCgYIKoZIzj0EAwIwgYgxCzAJBgNVBAYTAkRFMQ8wDQYDVQQHDAZCZXJsaW4xHTAbBgNVBAoMFEJ1bmRlc2RydWNrZXJlaSBHbWJIMREwDwYDVQQLDAhUIENTIElERTE2MDQGA1UEAwwtU1BSSU5EIEZ1bmtlIEVVREkgV2FsbGV0IFByb3RvdHlwZSBJc3N1aW5nIENBMB4XDTI0MDUzMTA2NDgwOVoXDTM0MDUyOTA2NDgwOVowgYgxCzAJBgNVBAYTAkRFMQ8wDQYDVQQHDAZCZXJsaW4xHTAbBgNVBAoMFEJ1bmRlc2RydWNrZXJlaSBHbWJIMREwDwYDVQQLDAhUIENTIElERTE2MDQGA1UEAwwtU1BSSU5EIEZ1bmtlIEVVREkgV2FsbGV0IFByb3RvdHlwZSBJc3N1aW5nIENBMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEYGzdwFDnc7+Kn5ibAvCOM8ke77VQxqfMcwZL8IaIA+WCROcCfmY/giH92qMru5p/kyOivE0RC/IbdMONvDoUyaNmMGQwHQYDVR0OBBYEFNRWGMCJOOgOWIQYyXZiv6u7xZC+MB8GA1UdIwQYMBaAFNRWGMCJOOgOWIQYyXZiv6u7xZC+MBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA0cAMEQCIGEm7wkZKHt/atb4MdFnXW6yrnwMUT2u136gdtl10Y6hAiBuTFqvVYth1rbxzCP0xWZHmQK9kVyxn8GPfX27EIzzsw==
-----END CERTIFICATE-----`

// https://funke.animo.id
const animoFunkeRelyingPartyCertificate =
'MIIBAzCBq6ADAgECAhArxq0w60RTDK4WY9HzgcvBMAoGCCqGSM49BAMCMAAwIBcNNzAwMTAxMDAwMDAwWhgPMjI4NjExMjAxNzQ2NDBaMAAwOTATBgcqhkjOPQIBBggqhkjOPQMBBwMiAALcD1XzKepFxWMAOqV+ln1fybBt7DRO5CV0f9A6mRp2xaMlMCMwIQYDVR0RBBowGIYWaHR0cHM6Ly9mdW5rZS5hbmltby5pZDAKBggqhkjOPQQDAgNHADBEAiAfvGG6sqrvzIMWYpJB5VLloo9f51loYXSkKxJIOztlNwIgLLSvEl0Dmp5vtj2buZ2nXQ2RBKxiLbc5eYGeMeoUnjk='

const variants = {
development: {
bundle: '.dev',
name: ' (Dev)',
trustedCertificates: [animoFunkeRelyingPartyCertificate, bdrPidIssuerCertificate],
},
preview: {
bundle: '.preview',
name: ' (Preview)',
trustedCertificates: [animoFunkeRelyingPartyCertificate, bdrPidIssuerCertificate],
},
production: {
bundle: '',
name: '',
trustedCertificates: [animoFunkeRelyingPartyCertificate, bdrPidIssuerCertificate],
},
}

Expand Down Expand Up @@ -103,10 +115,14 @@ const config = {
})),
],
},
experiments: {
tsconfigPaths: true,
},
extra: {
eas: {
projectId: 'b5f457fa-bcab-4c6e-8092-8cdf1239027a',
},
trustedCertificates: variant.trustedCertificates,
},
}

Expand Down
4 changes: 2 additions & 2 deletions apps/funke/app/(app)/_layout.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Text } from 'react-native'
import { Redirect, Stack } from 'expo-router'
import { Text } from 'react-native'

import { useSecureUnlock } from '../_layout'
import { useSecureUnlock } from '@/agent'
import { AgentProvider } from '@package/agent'

export default function AppLayout() {
Expand Down
12 changes: 3 additions & 9 deletions apps/funke/app/(app)/index.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,18 @@
import type { FunkeAppAgent } from '@package/agent'

import { initializeFunkeAgent, useAgent } from '@package/agent'
import { useAppAgent } from '@/agent'
import { addMessageListener } from '@animo-id/expo-ausweis-sdk'
import { Button, Paragraph, XStack, YStack } from '@package/ui'
import { Stack } from 'expo-router'
import { useEffect, useState } from 'react'
import { useSafeAreaInsets } from 'react-native-safe-area-context'
import { ReceivePidUseCase, type ReceivePidUseCaseState } from '../../use-cases/ReceivePidUseCase'
import { addMessageListener } from '@animo-id/expo-ausweis-sdk'

export const initializeAppAgent = initializeFunkeAgent
export const useAppAgent = useAgent<FunkeAppAgent>

export default function Screen() {
const { top } = useSafeAreaInsets()
// FIXME: should be useReceivePidUseCase as the state is now not updated....
const [receivePidUseCase, setReceivePidUseCase] = useState<ReceivePidUseCase>()
const [state, setState] = useState<ReceivePidUseCaseState | 'not-initialized'>('not-initialized')
const [credential, setCredential] = useState<string>()
const { agent } = useAgent()
const { agent } = useAppAgent()

useEffect(() => {
const { remove } = addMessageListener((message) => {
Expand All @@ -29,7 +24,6 @@ export default function Screen() {

useEffect(() => {
ReceivePidUseCase.initialize({ agent, onStateChange: setState }).then((pidUseCase) => {
console.log('got pid use case')
setReceivePidUseCase(pidUseCase)
})
}, [agent])
Expand Down
5 changes: 1 addition & 4 deletions apps/funke/app/_layout.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
import { NoInternetToastProvider, Provider, useTransparentNavigationBar } from '@package/app'
import { SecureUnlockProvider, useSecureUnlock as _useSecureUnlock } from '@package/secure-store/secureUnlock'
import { SecureUnlockProvider } from '@package/secure-store/secureUnlock'
import { DefaultTheme, ThemeProvider } from '@react-navigation/native'
import { Slot } from 'expo-router'
import * as SplashScreen from 'expo-splash-screen'

import tamaguiConfig from '../tamagui.config'
import type { FunkeAppAgent } from '@package/agent'

void SplashScreen.preventAutoHideAsync()

export const useSecureUnlock = () => _useSecureUnlock<{ agent?: FunkeAppAgent }>()

export const unstable_settings = {
// Ensure any route can link back to `/`
initialRouteName: '(app)/index',
Expand Down
15 changes: 4 additions & 11 deletions apps/funke/app/authenticate.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import { Redirect } from 'expo-router'
import { Text, View } from 'react-native'

import { useSecureUnlock } from './_layout'
import { useEffect } from 'react'
import { initializeAppAgent } from './(app)'
import * as SplashScreen from 'expo-splash-screen'
import { initializeAppAgent, useSecureUnlock } from '@/agent'
import type { SecureUnlockMethod } from '@package/secure-store/secureUnlock'
import { secureUnlockVersion } from '../../../packages/secure-store/secure-unlock/version'
import * as SplashScreen from 'expo-splash-screen'
import { useEffect } from 'react'

/**
* Authenticate screen is redirect to from app layout when app is configured but locked
Expand All @@ -19,13 +17,8 @@ export default function Authenticate() {
if (secureUnlock.state !== 'unlocked') return

initializeAppAgent({
keyDerivation: 'raw',
walletId: `funke-wallet-${secureUnlockVersion}`,
walletKey: secureUnlock.walletKey,
walletLabel: 'Funke Wallet',
}).then((agent) => {
secureUnlock.setContext({ agent })
})
}).then((agent) => secureUnlock.setContext({ agent }))
}, [secureUnlock])

// We want to wait until the agent is initialized before redirecting
Expand Down
9 changes: 2 additions & 7 deletions apps/funke/app/onboarding/index.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import { Redirect } from 'expo-router'
import { Text, View } from 'react-native'

import { useSecureUnlock } from '../_layout'
import { useEffect } from 'react'
import { initializeAppAgent } from '../(app)'
import { initializeAppAgent, useSecureUnlock } from '@/agent'
import * as SplashScreen from 'expo-splash-screen'
import { secureUnlockVersion } from '../../../../packages/secure-store/secure-unlock/version'
import { useEffect } from 'react'

/**
* Onboarding screen is redirect to from app layout when app is not configured
Expand All @@ -18,10 +16,7 @@ export default function Onboarding() {
if (secureUnlock.state !== 'unlocked') return

initializeAppAgent({
keyDerivation: 'raw',
walletId: `funke-wallet-${secureUnlockVersion}`,
walletKey: secureUnlock.walletKey,
walletLabel: 'Funke Wallet',
}).then((agent) => secureUnlock.setContext({ agent }))
}, [secureUnlock])

Expand Down
Binary file added apps/funke/assets/german-issuer-image.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 12 additions & 0 deletions apps/funke/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import ExpoConstants from 'expo-constants'

export const FUNKE_WALLET_SEED_CREDENTIAL_RECORD_ID = 'FUNKE_WALLET_SEED_CREDENTIAL_RECORD_ID '
export const FUNKE_WALLET_INSTANCE_LONG_TERM_AES_KEY_ID = 'FUNKE_WALLET_INSTANCE_LONG_TERM_AES_KEY_ID'

const TRUSTED_CERTIFICATES = ExpoConstants.expoConfig?.extra?.trustedCertificates as [string, ...string[]] | undefined

if (!Array.isArray(TRUSTED_CERTIFICATES)) {
throw new Error('Trusted Certificates provided in the expo config is not an array')
}

export const trustedCertificates = TRUSTED_CERTIFICATES
4 changes: 4 additions & 0 deletions apps/funke/crypto/aes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { aes128Gcm } from '@package/agent'
import { FUNKE_WALLET_INSTANCE_LONG_TERM_AES_KEY_ID } from '../constants'

export const funkeAes128Gcm = aes128Gcm(FUNKE_WALLET_INSTANCE_LONG_TERM_AES_KEY_ID)
35 changes: 35 additions & 0 deletions apps/funke/crypto/bPrime.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { type AgentContext, TypedArrayEncoder } from '@credo-ts/core'
import { Key, KeyAlgs, KeyMethod } from '@hyperledger/aries-askar-react-native'
import { kdf } from '@package/secure-store/kdf'
import { funkeAes128Gcm } from './aes'

/**
*
* Derive a key pair based on a numeric pin according to the steps in B'
*
* returns pin_derived_eph_pub + pin_derived_eph_priv
*
* @todo Might be good later to add methods like `signWithPidPin`
*
*/
export const deriveKeypairFromPin = async (agentContext: AgentContext, pin: Array<number>) => {
if (!(await funkeAes128Gcm.aes128GcmHasKey({ agentContext }))) {
throw new Error('No AES key found in storage. Flow is called in an incorrect way!')
}

const pinSecret = await funkeAes128Gcm.aes128GcmEncrypt({
agentContext,
data: new Uint8Array(pin),
})

const pinSeed = await kdf.derive(
TypedArrayEncoder.toUtf8String(new Uint8Array(pin)),
TypedArrayEncoder.toUtf8String(pinSecret)
)

return Key.fromSeed({
seed: new Uint8Array(TypedArrayEncoder.fromHex(pinSeed)),
method: KeyMethod.None,
algorithm: KeyAlgs.EcSecp256r1,
})
}
12 changes: 8 additions & 4 deletions apps/funke/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,17 @@
},
"dependencies": {
"@animo-id/expo-ausweis-sdk": "0.0.1-alpha.5",
"@animo-id/expo-secure-environment": "0.0.1-alpha.0",
"@credo-ts/core": "*",
"@expo-google-fonts/open-sans": "^0.2.3",
"@expo-google-fonts/raleway": "^0.2.3",
"@gorhom/bottom-sheet": "^4.6.3",
"@hyperledger/anoncreds-react-native": "^0.2.2",
"@hyperledger/aries-askar-react-native": "^0.2.3",
"@hyperledger/indy-vdr-react-native": "^0.2.0",
"@hyperledger/anoncreds-react-native": "*",
"@hyperledger/aries-askar-react-native": "*",
"@hyperledger/indy-vdr-react-native": "*",
"@package/agent": "workspace:*",
"@package/app": "workspace:*",
"@package/secure-store": "workspace:*",
"@package/ui": "workspace:*",
"@react-native-community/blur": "^4.3.2",
"@react-native-community/netinfo": "11.3.1",
Expand All @@ -37,6 +40,7 @@
"expo-linking": "~6.3.1",
"expo-navigation-bar": "~3.0.6",
"expo-router": "~3.5.16",
"expo-secure-store": "~13.0.1",
"expo-splash-screen": "~0.27.5",
"expo-status-bar": "~1.12.1",
"expo-system-ui": "~3.0.6",
Expand All @@ -55,7 +59,7 @@
},
"devDependencies": {
"@babel/core": "^7.24.4",
"@tamagui/babel-plugin": "^1.91.4",
"@tamagui/babel-plugin": "^1.104.2",
"typescript": "*"
}
}
1 change: 1 addition & 0 deletions apps/funke/storage/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './seedCredential'
18 changes: 18 additions & 0 deletions apps/funke/storage/seedCredential.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import type { Agent } from '@credo-ts/core'
import { walletJsonStore } from '@package/agent'
import { FUNKE_WALLET_SEED_CREDENTIAL_RECORD_ID } from '../constants'

export const seedCredentialStorage = {
store: async (agent: Agent, seedCredential: string) =>
walletJsonStore.store(agent, FUNKE_WALLET_SEED_CREDENTIAL_RECORD_ID, {
seedCredential,
}),

update: async (agent: Agent, seedCredential: string) =>
walletJsonStore.update(agent, FUNKE_WALLET_SEED_CREDENTIAL_RECORD_ID, {
seedCredential,
}),

getById: async (agent: Agent) =>
walletJsonStore.getById<{ seedCredential: string }>(agent, FUNKE_WALLET_SEED_CREDENTIAL_RECORD_ID),
}
16 changes: 12 additions & 4 deletions apps/funke/tamagui.config.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
// don't import from here, that's handled already
// instead this is just setting types for this folder
import { radius, size, space, zIndex } from '@tamagui/themes'

import { configInput, fontOpenSans, fontRaleway, hexColors } from '@package/ui/src/config/tamagui.config'
import { createTamagui, createTokens } from 'tamagui'

export const tokensInput = {
color: hexColors,
radius,
radius: {
...radius,
button: 16,
},
size,
zIndex,
space,
Expand Down Expand Up @@ -45,9 +46,16 @@ const config = createTamagui({
fonts: {
default: fontOpenSans,
heading: fontRaleway,
// Somehow adding body font gives build errors?!
// body: fontOpenSans,
},
themes: {
light: tokens.color,
light: {
...tokens.color,

// Button
buttonHeight: 53,
},
},
})

Expand Down
8 changes: 7 additions & 1 deletion apps/funke/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
{
"extends": "../../tsconfig.json"
"extends": "../../tsconfig.json",
"compilerOptions": {
"rootDir": "./",
"paths": {
"@/*": ["./apps/funke/*"]
}
}
}
18 changes: 9 additions & 9 deletions apps/funke/use-cases/ReceivePidUseCase.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
import type { AppAgent } from '@/agent'
import { AusweisAuthFlow } from '@animo-id/expo-ausweis-sdk'
import {
type FullAppAgent,
receiveCredentialFromOpenId4VciOffer,
type OpenId4VciRequestTokenResponse,
type OpenId4VciResolvedAuthorizationRequest,
type OpenId4VciResolvedCredentialOffer,
acquireAccessToken,
receiveCredentialFromOpenId4VciOffer,
resolveOpenId4VciOffer,
type OpenId4VciResolvedCredentialOffer,
type OpenId4VciResolvedAuthorizationRequest,
type OpenId4VciRequestTokenResponse,
} from '@package/agent'
import { AusweisAuthFlow } from '@animo-id/expo-ausweis-sdk'

export interface ReceivePidUseCaseOptions {
agent: FullAppAgent
agent: AppAgent
onStateChange?: (newState: ReceivePidUseCaseState) => void
}

export type ReceivePidUseCaseState = 'id-card-auth' | 'acquire-access-token' | 'retrieve-credential' | 'error'

export class ReceivePidUseCase {
private agent: FullAppAgent
private agent: AppAgent

private resolvedCredentialOffer: OpenId4VciResolvedCredentialOffer
private resolvedAuthorizationRequest: OpenId4VciResolvedAuthorizationRequest
Expand All @@ -36,7 +36,7 @@ export class ReceivePidUseCase {
private static REDIRECT_URI = 'https://funke.animo.id/redirect'

private constructor(
agent: FullAppAgent,
agent: AppAgent,
resolvedAuthorizationRequest: OpenId4VciResolvedAuthorizationRequest,
resolvedCredentialOffer: OpenId4VciResolvedCredentialOffer,
onStateChange?: (newState: ReceivePidUseCaseState) => void
Expand Down
Loading

0 comments on commit 0bb0307

Please sign in to comment.