Skip to content

Commit

Permalink
feat: add custom eaas
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 9ca53cd commit b8cd196
Show file tree
Hide file tree
Showing 3 changed files with 148 additions and 53 deletions.
40 changes: 20 additions & 20 deletions agent/src/endpoints.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,15 @@ import {
DifPresentationExchangeService,
JsonTransformer,
KeyType,
MdocVerifiablePresentation,
// Mdoc,
// MdocVerifiablePresentation,
RecordNotFoundError,
TypedArrayEncoder,
W3cJsonLdVerifiablePresentation,
W3cJwtVerifiablePresentation,
getJwkFromKey,
} from '@credo-ts/core'
import { OpenId4VcVerificationSessionState } from '@credo-ts/openid4vc'
import { Key as AskarKey, KeyAlgs } from '@hyperledger/aries-askar-nodejs'
import express, { type NextFunction, type Request, type Response } from 'express'
import z from 'zod'
import { agent } from './agent'
Expand Down Expand Up @@ -60,15 +59,16 @@ apiRouter.get('/issuer', async (_, response: Response) => {
const issuer = await getIssuer()

return response.json({
credentialsSupported: issuer.credentialsSupported.map((c) => ({
display:
c.format === 'vc+sd-jwt'
? `${c.vct} (vc+sd-jwt)`
: c.format === 'mso_mdoc'
? `${c.doctype} (mso_mdoc)`
: 'Unregistered format',
id: c.id,
})),
credentialsSupported: issuer.credentialsSupported.map((c) => {
const displayName =
c.display?.[0]?.name ??
(c.format === 'vc+sd-jwt' ? c.vct : c.format === 'mso_mdoc' ? c.doctype : 'Unregistered format')

return {
display: `${displayName} (${c.format})`,
id: c.id,
}
}),
display: issuer.display,
availableX509Certificates: [AGENT_HOST],
})
Expand Down Expand Up @@ -208,16 +208,16 @@ apiRouter.get('/requests/:verificationSessionId', async (request, response) => {
}
}

// if (presentation instanceof MdocVerifiablePresentation) {
// const deviceSigned = JSON.parse(presentation.deviceSignedBase64Url).deviceSigned
// const disclosedClaims = await Mdoc.getDisclosedClaims(deviceSigned)
// console.log('disclosedClaims', JSON.stringify(disclosedClaims, null, 2))
if (presentation instanceof MdocVerifiablePresentation) {
const deviceSigned = JSON.parse(presentation.deviceSignedBase64Url).deviceSigned
// const disclosedClaims = await Mdoc.getDisclosedClaims(deviceSigned)
// console.log('disclosedClaims', JSON.stringify(disclosedClaims, null, 2))

// return {
// pretty: JsonTransformer.toJSON(disclosedClaims),
// encoded: deviceSigned,
// }
// }
return {
pretty: JsonTransformer.toJSON({}),
encoded: deviceSigned,
}
}

return {
pretty: {
Expand Down
60 changes: 56 additions & 4 deletions agent/src/issuer.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
import type { KeyType } from '@credo-ts/core'
import type { OpenId4VciCredentialRequestToCredentialMapper, OpenId4VciSignMdocCredential } from '@credo-ts/openid4vc'
import type {
OpenId4VciCredentialRequestToCredentialMapper,
OpenId4VciSignMdocCredential,
OpenId4VciSignSdJwtCredential,
} from '@credo-ts/openid4vc'
import { agent } from './agent'
import { AGENT_HOST } from './constants'
import {
credentialsSupported,
issuerDisplay,
mockEmployeeBadgeMdoc,
mockIdenticonAttendeeSdJwt,
mockPidOpenId4VcPlaygroundCredentialMsoMdocJwk,
mockPidOpenId4VcPlaygroundCredentialSdJwtVcJwk,
} from './issuerMetadata'
Expand Down Expand Up @@ -46,7 +52,7 @@ export const credentialRequestToCredentialMapper: OpenId4VciCredentialRequestToC
// for the key binding
holderBinding,
credentialConfigurationIds,
}) => {
}): Promise<OpenId4VciSignMdocCredential | OpenId4VciSignSdJwtCredential> => {
const credentialConfigurationId = credentialConfigurationIds[0]

const x509Certificate = getX509Certificate()
Expand Down Expand Up @@ -112,7 +118,29 @@ export const credentialRequestToCredentialMapper: OpenId4VciCredentialRequestToC
],
age_equal_or_over: { _sd: ['12', '14', '16', '18', '21', '65'] },
},
}
} as const satisfies OpenId4VciSignSdJwtCredential
}

if (credentialConfigurationId === mockIdenticonAttendeeSdJwt.id) {
return {
credentialSupportedId: mockIdenticonAttendeeSdJwt.id,
format: 'vc+sd-jwt',
holder: holderBinding,
payload: {
vct: mockIdenticonAttendeeSdJwt.vct,
first_name: 'Erika',
last_name: 'Mustermann',
sponsorship_tier: 'Platinum',
},
issuer: {
method: 'x5c',
x5c: [x509Certificate],
issuer: AGENT_HOST,
},
disclosureFrame: {
_sd: ['first_name', 'last_name'],
},
} as const
}

if (credentialConfigurationId === mockPidOpenId4VcPlaygroundCredentialMsoMdocJwk.id) {
Expand Down Expand Up @@ -156,7 +184,31 @@ export const credentialRequestToCredentialMapper: OpenId4VciCredentialRequestToC
validFrom: new Date('2024-08-12T14:49:42.124Z'),
signed: new Date(),
},
} satisfies OpenId4VciSignMdocCredential
} as const satisfies OpenId4VciSignMdocCredential
}

if (credentialConfigurationId === mockEmployeeBadgeMdoc.id) {
return {
credentialSupportedId: mockEmployeeBadgeMdoc.id,
format: 'mso_mdoc',
holderKey: holderBinding.key,
docType: mockEmployeeBadgeMdoc.doctype,
issuerCertificate: x509Certificate,
namespaces: {
[mockEmployeeBadgeMdoc.doctype]: {
is_admin: true,
last_name: 'Mustermann',
first_name: 'Erika',
department: 'Sales',
employee_id: '181888100',
},
},
validityInfo: {
validUntil: new Date('2025-08-26T14:49:42.124Z'),
validFrom: new Date('2024-08-12T14:49:42.124Z'),
signed: new Date(),
},
} as const satisfies OpenId4VciSignMdocCredential
}

throw new Error(`Unsupported credential ${credentialConfigurationId}`)
Expand Down
101 changes: 72 additions & 29 deletions agent/src/issuerMetadata.ts
Original file line number Diff line number Diff line change
@@ -1,67 +1,110 @@
import { JwaSignatureAlgorithm } from '@credo-ts/core'
import { JwaSignatureAlgorithm } from "@credo-ts/core";
import {
OpenId4VciCredentialFormatProfile,
type OpenId4VciCredentialSupportedWithId,
type OpenId4VciIssuerMetadataDisplay,
} from '@credo-ts/openid4vc'
} from "@credo-ts/openid4vc";

const ANIMO_DARK_BACKGROUND = '#202223'
const WHITE = '#FFFFFF'
const ANIMO_DARK_BACKGROUND = "#202223";
const WHITE = "#FFFFFF";

export const issuerDisplay = [
{
background_color: ANIMO_DARK_BACKGROUND,
name: 'Animo + Funke OpenID4VC Playground',
locale: 'en',
name: "Animo + Funke OpenID4VC Playground",
locale: "en",
logo: {
alt_text: 'Animo logo',
url: 'https://i.imgur.com/PUAIUed.jpeg',
alt_text: "Animo logo",
url: "https://i.imgur.com/PUAIUed.jpeg",
},
text_color: WHITE,
},
] satisfies OpenId4VciIssuerMetadataDisplay[]
] satisfies OpenId4VciIssuerMetadataDisplay[];

export const mockIdenticonAttendeeSdJwt = {
format: "vc+sd-jwt",
id: "mockIdenticonAttendeeSdJwt",
vct: "https://funke.animo.id/IdenticonAttendee",
cryptographic_binding_methods_supported: ["jwk"],
cryptographic_suites_supported: [JwaSignatureAlgorithm.ES256],
proof_types_supported: {
jwt: {
proof_signing_alg_values_supported: [JwaSignatureAlgorithm.ES256],
},
},
display: [
{
name: "Identicon Attendee",
background_image: {
url: "https://i.imgur.com/uiczYkL.png",
uri: "https://i.imgur.com/uiczYkL.png",
},
text_color: WHITE,
},
],
} as const satisfies OpenId4VciCredentialSupportedWithId;

export const mockEmployeeBadgeMdoc = {
format: "mso_mdoc",
doctype: "id.animo.employeebadge",
id: "mockEmployeeBadgeMdoc",
cryptographic_binding_methods_supported: ["cose_key"],
cryptographic_suites_supported: [JwaSignatureAlgorithm.ES256],
proof_types_supported: {
jwt: {
proof_signing_alg_values_supported: [JwaSignatureAlgorithm.ES256],
},
},
display: [
{
name: "Animo Employee Badge",
background_color: ANIMO_DARK_BACKGROUND,
text_color: WHITE,
},
],
} as const satisfies OpenId4VciCredentialSupportedWithId;

export const mockPidOpenId4VcPlaygroundCredentialSdJwtVcJwk = {
id: 'mockPidOpenId4VcPlaygroundSdJwtVcJwk',
id: "mockPidOpenId4VcPlaygroundSdJwtVcJwk",
format: OpenId4VciCredentialFormatProfile.SdJwtVc,
vct: 'https://example.bmi.bund.de/credential/pid/1.0',
cryptographic_binding_methods_supported: ['jwk'],
vct: "https://example.bmi.bund.de/credential/pid/1.0",
cryptographic_binding_methods_supported: ["jwk"],
cryptographic_suites_supported: [JwaSignatureAlgorithm.ES256],
display: [
{
name: 'PID',
description: 'Mock PID issued by Animo',
name: "PID",
description: "Mock PID issued by Animo",
background_color: ANIMO_DARK_BACKGROUND,
locale: 'en',
locale: "en",
text_color: WHITE,
},
],
} as const satisfies OpenId4VciCredentialSupportedWithId
} as const satisfies OpenId4VciCredentialSupportedWithId;

export const mockPidOpenId4VcPlaygroundCredentialMsoMdocJwk = {
id: 'mockPidOpenId4VcPlaygroundMsoMdocJwk',
id: "mockPidOpenId4VcPlaygroundMsoMdocJwk",
format: OpenId4VciCredentialFormatProfile.MsoMdoc,
doctype: 'eu.europa.ec.eudi.pid.1',
cryptographic_binding_methods_supported: ['jwk'],
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',
name: "PID",
description: "Mock PID issued by Animo",
background_color: ANIMO_DARK_BACKGROUND,
locale: 'en',
locale: "en",
text_color: WHITE,
},
],
} as const satisfies OpenId4VciCredentialSupportedWithId
} as const satisfies OpenId4VciCredentialSupportedWithId;

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

type CredentialSupportedId = (typeof credentialsSupported)[number]['id']
type CredentialSupportedId = (typeof credentialsSupported)[number]["id"];
export const credentialSupportedIds = credentialsSupported.map((s) => s.id) as [
CredentialSupportedId,
...CredentialSupportedId[],
]
...CredentialSupportedId[]
];

0 comments on commit b8cd196

Please sign in to comment.