Skip to content

Commit

Permalink
feat: add issuance, update to new version
Browse files Browse the repository at this point in the history
Signed-off-by: Timo Glastra <[email protected]>
  • Loading branch information
TimoGlastra committed Oct 29, 2024
1 parent f588af5 commit 9ca53cd
Show file tree
Hide file tree
Showing 9 changed files with 2,144 additions and 2,381 deletions.
3 changes: 1 addition & 2 deletions agent/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,7 @@
"@sphereon/oid4vci-common": "https://gitpkg.vercel.app/animo/OID4VC/packages/oid4vci-common?funke",
"@sphereon/oid4vci-issuer": "https://gitpkg.vercel.app/animo/OID4VC/packages/issuer?funke",
"@sphereon/oid4vci-client": "https://gitpkg.vercel.app/animo/OID4VC/packages/client?funke",
"@sphereon/jarm": "https://gitpkg.vercel.app/animo/OID4VC/packages/jarm?funke",
"@sphereon/ssi-types": "0.29.1-unstable.208"
"@sphereon/jarm": "https://gitpkg.vercel.app/animo/OID4VC/packages/jarm?funke"
}
}
}
7 changes: 6 additions & 1 deletion agent/src/endpoints.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,12 @@ apiRouter.get('/issuer', async (_, response: Response) => {

return response.json({
credentialsSupported: issuer.credentialsSupported.map((c) => ({
display: (c as { vct: string }).vct,
display:
c.format === 'vc+sd-jwt'
? `${c.vct} (vc+sd-jwt)`
: c.format === 'mso_mdoc'
? `${c.doctype} (mso_mdoc)`
: 'Unregistered format',
id: c.id,
})),
display: issuer.display,
Expand Down
67 changes: 57 additions & 10 deletions agent/src/issuer.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
import type { KeyType } from '@credo-ts/core'
import type { OpenId4VciCredentialRequestToCredentialMapper } from '@credo-ts/openid4vc'
import type { OpenId4VciCredentialRequestToCredentialMapper, OpenId4VciSignMdocCredential } from '@credo-ts/openid4vc'
import { agent } from './agent'
import { AGENT_HOST } from './constants'
import { credentialsSupported, issuerDisplay, mockPidOpenId4VcPlaygroundCredentialSdJwtVcJwk } from './issuerMetadata'
import {
credentialsSupported,
issuerDisplay,
mockPidOpenId4VcPlaygroundCredentialMsoMdocJwk,
mockPidOpenId4VcPlaygroundCredentialSdJwtVcJwk,
} from './issuerMetadata'
import { getX509Certificate } from './keyMethods'

const issuerId = 'e451c49f-1186-4fe4-816d-a942151dfd59'
Expand Down Expand Up @@ -40,8 +45,9 @@ export const credentialRequestToCredentialMapper: OpenId4VciCredentialRequestToC
// FIXME: it would be useful if holderBinding would include some metadata on the key type / alg used
// for the key binding
holderBinding,
credentialConfigurationIds,
}) => {
const credentialSupported = credentialsSupported[0]
const credentialConfigurationId = credentialConfigurationIds[0]

const x509Certificate = getX509Certificate()

Expand All @@ -52,16 +58,13 @@ export const credentialRequestToCredentialMapper: OpenId4VciCredentialRequestToC
throw new Error(`Unsupported holder binding method: ${holderBinding.method}`)
}

if (
credentialSupported.format === 'vc+sd-jwt' &&
credentialSupported.id === mockPidOpenId4VcPlaygroundCredentialSdJwtVcJwk.id
) {
if (credentialConfigurationId === mockPidOpenId4VcPlaygroundCredentialSdJwtVcJwk.id) {
return {
credentialSupportedId: credentialSupported.id,
credentialSupportedId: mockPidOpenId4VcPlaygroundCredentialSdJwtVcJwk.id,
format: 'vc+sd-jwt',
holder: holderBinding,
payload: {
vct: credentialSupported.vct,
vct: mockPidOpenId4VcPlaygroundCredentialSdJwtVcJwk.vct,
given_name: 'Erika',
family_name: 'Mustermann',
birthdate: '1963-08-12',
Expand Down Expand Up @@ -112,5 +115,49 @@ export const credentialRequestToCredentialMapper: OpenId4VciCredentialRequestToC
}
}

throw new Error(`Unsupported credential ${credentialSupported.id}`)
if (credentialConfigurationId === mockPidOpenId4VcPlaygroundCredentialMsoMdocJwk.id) {
return {
credentialSupportedId: mockPidOpenId4VcPlaygroundCredentialMsoMdocJwk.id,
format: 'mso_mdoc',
holderKey: holderBinding.key,
docType: mockPidOpenId4VcPlaygroundCredentialMsoMdocJwk.doctype,
issuerCertificate: x509Certificate,
namespaces: {
'eu.europa.ec.eudi.pid.1': {
resident_country: 'DE',
age_over_12: true,
family_name_birth: 'GABLER',
given_name: 'ERIKA',
age_birth_year: 1984,
age_over_18: true,
age_over_21: true,
resident_city: 'KÖLN',
family_name: 'MUSTERMANN',
birth_place: 'BERLIN',
expiry_date: new Date('2024-08-26T14:49:42.124Z'),
issuing_country: 'DE',
age_over_65: false,
issuance_date: new Date('2024-08-12T14:49:42.124Z'),
resident_street: 'HEIDESTRASSE 17',
age_over_16: true,
resident_postal_code: '51147',
birth_date: '1984-01-26',
issuing_authority: 'DE',
age_over_14: true,
age_in_years: 40,
nationality: new Map([
['value', 'DE'],
['countryName', 'Germany'],
]),
},
},
validityInfo: {
validUntil: new Date('2025-08-26T14:49:42.124Z'),
validFrom: new Date('2024-08-12T14:49:42.124Z'),
signed: new Date(),
},
} satisfies OpenId4VciSignMdocCredential
}

throw new Error(`Unsupported credential ${credentialConfigurationId}`)
}
24 changes: 20 additions & 4 deletions agent/src/issuerMetadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,27 @@ export const mockPidOpenId4VcPlaygroundCredentialSdJwtVcJwk = {
vct: 'https://example.bmi.bund.de/credential/pid/1.0',
cryptographic_binding_methods_supported: ['jwk'],
cryptographic_suites_supported: [JwaSignatureAlgorithm.ES256],
// @ts-ignore
credential_signing_alg_values_supported: [JwaSignatureAlgorithm.ES256],
display: [
{
name: 'SD-JWT-VC',
description: 'JWK holder binding',
name: 'PID',
description: 'Mock PID issued by Animo',
background_color: ANIMO_DARK_BACKGROUND,
locale: 'en',
text_color: WHITE,
},
],
} as const satisfies OpenId4VciCredentialSupportedWithId

export const mockPidOpenId4VcPlaygroundCredentialMsoMdocJwk = {
id: 'mockPidOpenId4VcPlaygroundMsoMdocJwk',
format: OpenId4VciCredentialFormatProfile.MsoMdoc,
doctype: 'eu.europa.ec.eudi.pid.1',
cryptographic_binding_methods_supported: ['jwk'],
cryptographic_suites_supported: [JwaSignatureAlgorithm.ES256],
display: [
{
name: 'PID',
description: 'Mock PID issued by Animo',
background_color: ANIMO_DARK_BACKGROUND,
locale: 'en',
text_color: WHITE,
Expand All @@ -42,6 +57,7 @@ export const mockPidOpenId4VcPlaygroundCredentialSdJwtVcJwk = {

export const credentialsSupported = [
mockPidOpenId4VcPlaygroundCredentialSdJwtVcJwk,
mockPidOpenId4VcPlaygroundCredentialMsoMdocJwk,
] as const satisfies OpenId4VciCredentialSupportedWithId[]

type CredentialSupportedId = (typeof credentialsSupported)[number]['id']
Expand Down
1 change: 1 addition & 0 deletions agent/src/keyMethods/createSelfSignedCertificate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export const createSelfSignedCertificate = async (key: Key) =>
await X509Service.createSelfSignedCertificate(agent.context, {
key,
extensions: [[{ type: 'dns', value: AGENT_DNS }]],
name: 'C=NL',
notBefore: new Date(0), // Thu Jan 01 1970 01:00:00 GMT+0100 (Central European Standard Time)
notAfter: new Date(1763799732333), // Sat Nov 22 2025 09:22:12 GMT+0100 (Central European Standard Time)
})
Expand Down
3 changes: 1 addition & 2 deletions agent/src/keyMethods/setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,7 @@ export async function setupX509Certificate() {
console.log('======= X.509 Certificate ===========')
console.log(x509Certificate)

const x509 = agent.dependencyManager.resolve(X509Api)
await x509.addTrustedCertificate(x509Certificate)
agent.x509.addTrustedCertificate(x509Certificate)
}

export function getX509Certificate() {
Expand Down
14 changes: 7 additions & 7 deletions app/components/IssueTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Card } from '@/components/ui/card'
import { Label } from '@/components/ui/label'
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip'
import { ExclamationTriangleIcon } from '@radix-ui/react-icons'
import { InfoCircledIcon } from '@radix-ui/react-icons'
import { type FormEvent, useEffect, useState } from 'react'
import QRCode from 'react-qr-code'
import { createOffer, getIssuer, getX509Certificate } from '../lib/api'
Expand Down Expand Up @@ -45,19 +45,19 @@ export function IssueTab({ disabled = false }: { disabled?: boolean }) {

return (
<Card className="p-6">
<Alert variant="warning" className="mb-5">
<ExclamationTriangleIcon className="h-4 w-4" />
<AlertTitle>Warning</AlertTitle>
<Alert variant="default" className="mb-5">
<InfoCircledIcon className="h-4 w-4" />
<AlertTitle>Info</AlertTitle>
<AlertDescription>
This playground was built in the context for the{' '}
<a className="underline" href="https://www.sprind.org/en/challenges/eudi-wallet-prototypes/">
EUDI Wallet Prototype Funke
</a>
. Tabs that are not compatible with the current deployed version of{' '}
. It is only compatible with the current deployed version of{' '}
<a className="underline" href="https://github.com/animo/paradym-wallet/tree/main/apps/easypid">
Animo&apos;s EUDI Wallet Prototype
</a>{' '}
are disabled for public use.
</a>
.
</AlertDescription>
</Alert>
<form className="space-y-4" onSubmit={disabled ? undefined : onSubmitIssueCredential}>
Expand Down
2 changes: 1 addition & 1 deletion app/components/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export function Main() {
<VerifyTab />
</TabsContent>
<TabsContent value="issue">
<IssueTab disabled />
<IssueTab />
</TabsContent>
<TabsContent value="receive">
<ReceiveTab disabled />
Expand Down
Loading

0 comments on commit 9ca53cd

Please sign in to comment.