Skip to content

Commit

Permalink
fix: issues (#232)
Browse files Browse the repository at this point in the history
Signed-off-by: Timo Glastra <[email protected]>
  • Loading branch information
TimoGlastra authored Nov 26, 2024
1 parent 3119fa2 commit e75b105
Show file tree
Hide file tree
Showing 12 changed files with 140 additions and 104 deletions.
14 changes: 8 additions & 6 deletions apps/easypid/src/app/(app)/_layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,19 @@ export default function AppLayout() {
// It could be that the onboarding is cut of mid-process, and e.g. the user closes the app
// if this is the case we will redo the onboarding
const [hasFinishedOnboarding] = useHasFinishedOnboarding()
const [resetWalletState, setResetWalletState] = useState<'resetting' | 'reset'>()
const [hasResetWallet, setHasResetWallet] = useState(false)
const shouldResetWallet =
secureUnlock.state !== 'not-configured' && secureUnlock.state !== 'initializing' && !hasFinishedOnboarding
const isWalletLocked = secureUnlock.state === 'locked' || secureUnlock.state === 'acquired-wallet-key'

useEffect(() => {
if (resetWalletState || !shouldResetWallet) return
// Reset state
if (hasResetWallet && !shouldResetWallet) setHasResetWallet(false)
if (!shouldResetWallet || hasResetWallet) return

setResetWalletState('resetting')
resetWallet(secureUnlock).then(() => setResetWalletState('reset'))
}, [secureUnlock, resetWalletState, shouldResetWallet])
setHasResetWallet(true)
resetWallet(secureUnlock)
}, [secureUnlock, hasResetWallet, shouldResetWallet])

// If we are intializing and the wallet was opened using a deeplinkg we will be redirected
// to the authentication screen. We first save the redirection url and use that when navigation
Expand All @@ -66,7 +68,7 @@ export default function AppLayout() {
}

// This should show the splash screen
if (secureUnlock.state === 'initializing' || (shouldResetWallet && resetWalletState !== 'reset')) {
if (secureUnlock.state === 'initializing' || shouldResetWallet) {
return null
}

Expand Down
2 changes: 1 addition & 1 deletion apps/easypid/src/app/+native-intent.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { parseInvitationUrl } from '@package/agent'
import { deeplinkSchemes } from '@package/app'
import * as Haptics from 'expo-haptics'
import { Platform } from 'react-native'
import { router } from 'expo-router'
import { Platform } from 'react-native'

export async function redirectSystemPath({ path, initial }: { path: string; initial: boolean }) {
const isRecognizedDeeplink = deeplinkSchemes.some((scheme) => path.startsWith(scheme))
Expand Down
6 changes: 5 additions & 1 deletion apps/easypid/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,16 @@ const animoFunkeRelyingPartyCertificate =
const ubiqueRootCertificate =
'MIIBZjCCAQygAwIBAgIGAZGJt173MAoGCCqGSM49BAMCMB8xHTAbBgNVBAMMFGh0dHBzOi8vYXV0aG9yaXR5LmNoMB4XDTI0MDgyNTEzMjYyMVoXDTI1MDgyNTEzMjYyMVowHzEdMBsGA1UEAwwUaHR0cHM6Ly9hdXRob3JpdHkuY2gwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAScIjAmHrkp3TC6bisgaqmszbKkpY0iGTdHF2rcRemJCV+ikotDt7G+ApwG0m6fxt8aBJHeJ2mssLvZBmZj5LtWozQwMjAfBgNVHREEGDAWghRodHRwczovL2F1dGhvcml0eS5jaDAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMCA0gAMEUCIQCpQsxyQx/5knqhGnDCiAo6MpQmTCd7vA9WehF4/1P8/QIgEnAtFVTP1uThuTEna1RD4Ji35+z1h8pDoMyLPd3Uaig='

const ubiqueIssuer =
'MIICsTCCAlegAwIBAgIUeN7cTJgPmbK39asN8Wf3VLOSCTAwCgYIKoZIzj0EAwIwgcYxCzAJBgNVBAYTAkRFMR0wGwYDVQQIDBRHZW1laW5kZSBNdXN0ZXJzdGFkdDEUMBIGA1UEBwwLTXVzdGVyc3RhZHQxHTAbBgNVBAoMFEdlbWVpbmRlIE11c3RlcnN0YWR0MQswCQYDVQQLDAJJVDEpMCcGA1UEAwwgaXNzdWFuY2UuZ2VtZWluZGUtbXVzdGVyc3RhZHQuZGUxKzApBgkqhkiG9w0BCQEWHHRlc3RAZ2VtZWluZGUtbXVzdGVyc3RhZHQuZGUwHhcNMjQxMTE1MDgzNzA4WhcNMzQxMTEzMDgzNzA4WjCBxjELMAkGA1UEBhMCREUxHTAbBgNVBAgMFEdlbWVpbmRlIE11c3RlcnN0YWR0MRQwEgYDVQQHDAtNdXN0ZXJzdGFkdDEdMBsGA1UECgwUR2VtZWluZGUgTXVzdGVyc3RhZHQxCzAJBgNVBAsMAklUMSkwJwYDVQQDDCBpc3N1YW5jZS5nZW1laW5kZS1tdXN0ZXJzdGFkdC5kZTErMCkGCSqGSIb3DQEJARYcdGVzdEBnZW1laW5kZS1tdXN0ZXJzdGFkdC5kZTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABDYXt8M+5E1ADj5N2Rv/zIwBlvkTlt3gsscrKP4owg6km9Ejv5bHqDWY+nQi29ezNH2tkhGrKe0ZsmeH9ZqUsI+jITAfMB0GA1UdDgQWBBRSW2AGYj1dJ5Nz84/XojDDjH00XzAKBggqhkjOPQQDAgNIADBFAiBJ7ohG3x9iBlbTeSLnJGTFdwfw10mM9sd1J/TpoijcfAIhALgJgE/w3/J7jJMvZq+EiUT8DkhKTTUNhN74uA+bL4v6'

export const trustedX509Certificates = [
ubiqueIssuer,
bdrPidIssuerCertificate,
animoFunkeRelyingPartyCertificate,
ubiqueRootCertificate,
oldAnimoFunkeRelyingPartyCertificate,
'MIIBKDCBzqADAgECAhAyWHL4SEss2wMO1QQybg/fMAoGCCqGSM49BAMCMA0xCzAJBgNVBAYTAk5MMB4XDTcwMDEwMTAwMDAwMFoXDTI1MTEyMjA4MjIxMlowDTELMAkGA1UEBhMCTkwwOTATBgcqhkjOPQIBBggqhkjOPQMBBwMiAALcD1XzKepFxWMAOqV+ln1fybBt7DRO5CV0f9A6mRp2xaMwMC4wLAYDVR0RBCUwI4IhMDRkNy0yMTctMTIzLTE4LTI2Lm5ncm9rLWZyZWUuYXBwMAoGCCqGSM49BAMCA0kAMEYCIQDWjkAm/iLhGWcgKILW48f43vEUByvJd2R4lxdTdK9w+wIhALcZIgrH2h9SoXHjuI9ktOMbfVHxt59iq+lOKsC4yOUQ',
'MIIBJzCBz6ADAgECAhA0WLLsSm0Hf5R2/q7neHUKMAoGCCqGSM49BAMCMA0xCzAJBgNVBAYTAk5MMB4XDTcwMDEwMTAwMDAwMFoXDTI1MTEyMjA4MjIxMlowDTELMAkGA1UEBhMCTkwwOTATBgcqhkjOPQIBBggqhkjOPQMBBwMiAALcD1XzKepFxWMAOqV+ln1fybBt7DRO5CV0f9A6mRp2xaMxMC8wLQYDVR0RBCYwJIIiNGFjNS0xMDktMzctMTUwLTE5OC5uZ3Jvay1mcmVlLmFwcDAKBggqhkjOPQQDAgNHADBEAiAEqDL6WHBelM4YW3L0k2criU+Za/FlDEuAJKuY+LiY/AIgR0qGuW9qu4wUo/kcJ75mv+jAwV25ABmYAnbUX/7u5lI=',
]

// https://gitlab.opencode.de/bmi/eudi-wallet/eidas-2.0-architekturkonzept/-/blob/main/architecture-proposal.md#pid-contents
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,11 +74,14 @@ export function FunkeCredentialNotificationScreen() {
// TODO: where to transform?
// Combine oid4vci issuer metadata and openid fed into one pipeline. If openid it's trusted
const issuerMetadata = resolvedCredentialOffer?.metadata.credentialIssuer
const configuration =
resolvedCredentialOffer?.offeredCredentialConfigurations[
// TODO: handle empty configuration ids
resolvedCredentialOffer.credentialOfferPayload.credential_configuration_ids[0]
]
// We want the first supported configuration id
// TODO: handle empty configuration ids
const configurationId = resolvedCredentialOffer?.offeredCredentialConfigurations
? Object.keys(resolvedCredentialOffer.offeredCredentialConfigurations)[0]
: undefined
const configuration = configurationId
? resolvedCredentialOffer?.offeredCredentialConfigurations[configurationId]
: undefined

const credentialDisplay = getCredentialDisplayWithDefaults(
configuration && issuerMetadata
Expand Down Expand Up @@ -122,11 +125,13 @@ export function FunkeCredentialNotificationScreen() {
async (
resolvedCredentialOffer: OpenId4VciResolvedCredentialOffer,
tokenResponse: OpenId4VciRequestTokenResponse,
configurationId: string,
resolvedAuthorizationRequest?: OpenId4VciResolvedAuthorizationRequest
) => {
const credentialResponses = await receiveCredentialFromOpenId4VciOffer({
agent,
resolvedCredentialOffer,
credentialConfigurationIdsToRequest: [configurationId],
accessToken: tokenResponse,
clientId: resolvedAuthorizationRequest ? authorization.clientId : undefined,
})
Expand Down Expand Up @@ -164,7 +169,7 @@ export function FunkeCredentialNotificationScreen() {

const acquireCredentialsAuth = useCallback(
async (authorizationCode: string) => {
if (!resolvedCredentialOffer || !resolvedAuthorizationRequest) {
if (!resolvedCredentialOffer || !resolvedAuthorizationRequest || !configurationId) {
setErrorReason('Credential information could not be extracted')
return
}
Expand All @@ -179,20 +184,20 @@ export function FunkeCredentialNotificationScreen() {
'codeVerifier' in resolvedAuthorizationRequest ? resolvedAuthorizationRequest.codeVerifier : undefined,
})

await retrieveCredentials(resolvedCredentialOffer, tokenResponse, resolvedAuthorizationRequest)
await retrieveCredentials(resolvedCredentialOffer, tokenResponse, configurationId, resolvedAuthorizationRequest)
} catch (error) {
agent.config.logger.error(`Couldn't receive credential from OpenID4VCI offer`, {
error,
})
setErrorReason('Error while retrieving credentials')
}
},
[resolvedCredentialOffer, resolvedAuthorizationRequest, retrieveCredentials, agent]
[resolvedCredentialOffer, resolvedAuthorizationRequest, retrieveCredentials, agent, configurationId]
)

const acquireCredentialsPreAuth = useCallback(
async (txCode?: string) => {
if (!resolvedCredentialOffer) {
if (!resolvedCredentialOffer || !configurationId) {
setErrorReason('Credential information could not be extracted')
return
}
Expand All @@ -203,23 +208,22 @@ export function FunkeCredentialNotificationScreen() {
resolvedCredentialOffer,
txCode,
})
await retrieveCredentials(resolvedCredentialOffer, tokenResponse)
await retrieveCredentials(resolvedCredentialOffer, tokenResponse, configurationId)
} catch (error) {
agent.config.logger.error(`Couldn't receive credential from OpenID4VCI offer`, {
error,
})
setErrorReason('Error while retrieving credentials')
}
},
[resolvedCredentialOffer, agent, retrieveCredentials]
[resolvedCredentialOffer, agent, retrieveCredentials, configurationId]
)

const parsePresentationRequestUrl = useCallback(
(oid4vpRequestUrl: string) =>
getCredentialsForProofRequest({
agent,
uri: oid4vpRequestUrl,
allowUntrustedCertificates: true,
})
.then(setCredentialsForRequest)
.catch((error) => {
Expand Down Expand Up @@ -276,7 +280,6 @@ export function FunkeCredentialNotificationScreen() {
agent,
resolvedRequest: credentialsForRequest,
selectedCredentials: {},
allowUntrustedCertificate: true,
})

const { authorizationCode } = await acquireAuthorizationCodeUsingPresentation({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ export function FunkeOpenIdPresentationNotificationScreen() {
agent,
data: params.data,
uri: params.uri,
allowUntrustedCertificates: true,
})
.then(setCredentialsForRequest)
.catch((error) => {
Expand Down Expand Up @@ -93,7 +92,6 @@ export function FunkeOpenIdPresentationNotificationScreen() {
agent,
resolvedRequest: credentialsForRequest,
selectedCredentials: {},
allowUntrustedCertificate: true,
})

await addSharedActivityForCredentialsForRequest(agent, credentialsForRequest, 'success')
Expand Down
1 change: 1 addition & 0 deletions apps/easypid/src/utils/resetWallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
import { removeShouldUseCloudHsm } from '../features/onboarding/useShouldUseCloudHsm'

export async function resetWallet(secureUnlock: SecureUnlockReturn<SecureUnlockContext>) {
console.log('Resetting wallet')
if (secureUnlock.state === 'unlocked') {
const agent = secureUnlock.context.agent
secureUnlock.lock()
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@
"@credo-ts/indy-vdr": "catalog:",
"@credo-ts/openid4vc": "catalog:",
"@credo-ts/question-answer": "catalog:",
"@credo-ts/react-native": "catalog:"
"@credo-ts/react-native": "catalog:",
"@sphereon/pex-models": "catalog:"
},
"patchedDependencies": {
"@hyperledger/[email protected]": "patches/@[email protected]",
Expand Down
41 changes: 36 additions & 5 deletions packages/agent/src/agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
Agent,
AutoAcceptCredential,
AutoAcceptProof,
ClaimFormat,
ConnectionsModule,
CredentialsModule,
DidsModule,
Expand All @@ -23,13 +24,15 @@ import {
KeyDidRegistrar,
KeyDidResolver,
LogLevel,
Mdoc,
MediationRecipientModule,
MediatorPickupStrategy,
ProofsModule,
V2CredentialProtocol,
V2ProofProtocol,
WebDidResolver,
WsOutboundTransport,
X509Module,
} from '@credo-ts/core'
import {
IndyVdrAnonCredsRegistry,
Expand All @@ -45,6 +48,7 @@ import { ariesAskar } from '@hyperledger/aries-askar-react-native'
import { indyVdr } from '@hyperledger/indy-vdr-react-native'
import { DidWebAnonCredsRegistry } from 'credo-ts-didweb-anoncreds'

import { bdrPidIssuerCertificate, pidSchemes } from '../../../apps/easypid/src/constants'
import { indyNetworks } from './indyNetworks'
import { appLogger } from './logger'

Expand Down Expand Up @@ -80,16 +84,43 @@ export const initializeEasyPIDAgent = async ({
modules: {
ariesAskar: askarModule,
openId4VcHolder: new OpenId4VcHolderModule(),
x509: new X509Module({
getTrustedCertificatesForVerification: (agentContext, { certificateChain, verification }) => {
if (verification.type === 'credential') {
// Only allow BDR certificate for PID credentials for now
if (
verification.credential instanceof Mdoc &&
pidSchemes.msoMdocDoctypes.includes(verification.credential.docType)
) {
return [bdrPidIssuerCertificate]
}

if (
verification.credential.claimFormat === ClaimFormat.SdJwtVc &&
pidSchemes.sdJwtVcVcts.includes(verification.credential.payload.vct as string)
) {
return [bdrPidIssuerCertificate]
}

// If not PID, we allow any certificate for now
return [certificateChain[0].toString('pem')]
}

// Allow any actor for auth requests for now
if (verification.type === 'oauth2SecuredAuthorizationRequest') {
return [certificateChain[0].toString('pem')]
}

return undefined
},
trustedCertificates:
trustedX509Certificates.length > 0 ? (trustedX509Certificates as [string, ...string[]]) : undefined,
}),
},
})

await agent.initialize()

// Register the trusted x509 certificates
for (const trustedCertificate of trustedX509Certificates) {
agent.x509.addTrustedCertificate(trustedCertificate)
}

return agent
}

Expand Down
17 changes: 10 additions & 7 deletions packages/agent/src/format/formatPresentation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -207,27 +207,30 @@ export function formatDcqlCredentialsForRequest(dcqlQueryResult: DcqlQueryResult
const credentialForDisplay = getCredentialForDisplay(match.record)

let disclosed: FormattedSubmissionEntrySatisfiedCredential['disclosed']
if (match.output.credentialFormat === 'vc+sd-jwt') {
if (match.output.credential_format === '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
)
// TODO: remove once selective disclosure in credo tested
// const disclosedDecoded = applyLimitdisclosureForSdJwtRequestedPayload(
// match.record.compactSdJwtVc,
// match.output.claims
// )

const { attributes, metadata } = getAttributesAndMetadataForSdJwtPayload(disclosedDecoded.prettyClaims)
// Creod already applied selective disclosure on payload
const { attributes, metadata } = getAttributesAndMetadataForSdJwtPayload(match.output.claims)
disclosed = {
attributes,
metadata,
paths: getDisclosedAttributePathArrays(attributes, 2),
}
} else if (match.output.credentialFormat === 'mso_mdoc') {
} else if (match.output.credential_format === 'mso_mdoc') {
if (match.record.type !== 'MdocRecord') throw new Error('Expected MdocRecord')

// TODO: check if fixed now
// FIXME: the disclosed payload here doesn't have the correct encoding anymore
// once we serialize input??
disclosed = {
Expand Down
Loading

0 comments on commit e75b105

Please sign in to comment.