Skip to content

Commit

Permalink
it actually compiles and runs!!
Browse files Browse the repository at this point in the history
Signed-off-by: Timo Glastra <timo@animo.id>
  • Loading branch information
TimoGlastra committed Jan 28, 2024
1 parent 6754b30 commit 226de98
Show file tree
Hide file tree
Showing 19 changed files with 295 additions and 802 deletions.
44 changes: 25 additions & 19 deletions demo-openid/src/Holder.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import type {
OfferedCredentialWithMetadata,
ResolvedPresentationRequest,
ResolvedCredentialOffer,
OpenId4VciResolvedCredentialOffer,
OpenId4VcSiopResolvedAuthorizationRequest,
} from '@aries-framework/openid4vc'

import { AskarModule } from '@aries-framework/askar'
import { W3cJwtVerifiableCredential, W3cJsonLdVerifiableCredential } from '@aries-framework/core'
import {
W3cJwtVerifiableCredential,
W3cJsonLdVerifiableCredential,
DifPresentationExchangeService,
} from '@aries-framework/core'
import { OpenId4VcHolderModule } from '@aries-framework/openid4vc'
import { ariesAskar } from '@hyperledger/aries-askar-nodejs'

Expand Down Expand Up @@ -36,8 +39,8 @@ export class Holder extends BaseAgent<ReturnType<typeof getOpenIdHolderModules>>
}

public async requestAndStoreCredentials(
resolvedCredentialOffer: ResolvedCredentialOffer,
credentialsToRequest: OfferedCredentialWithMetadata[]
resolvedCredentialOffer: OpenId4VciResolvedCredentialOffer,
credentialsToRequest: string[]
) {
const credentials = await this.agent.modules.openId4VcHolder.acceptCredentialOfferUsingPreAuthorizedCode(
resolvedCredentialOffer,
Expand Down Expand Up @@ -65,25 +68,28 @@ export class Holder extends BaseAgent<ReturnType<typeof getOpenIdHolderModules>>
}

public async resolveProofRequest(proofRequest: string) {
const resolvedProofRequest = await this.agent.modules.openId4VcHolder.resolveProofRequest(proofRequest)

if (resolvedProofRequest.proofType === 'authentication')
throw new Error('We only support presentation requests for now.')
const resolvedProofRequest = await this.agent.modules.openId4VcHolder.resolveSiopAuthorizationRequest(proofRequest)

return resolvedProofRequest
}

public async acceptPresentationRequest(
resolvedPresentationRequest: ResolvedPresentationRequest,
submissionEntryIndexes: number[]
) {
const { presentationRequest, presentationSubmission } = resolvedPresentationRequest
const submissionResult = await this.agent.modules.openId4VcHolder.acceptPresentationRequest(presentationRequest, {
submission: presentationSubmission,
submissionEntryIndexes,
public async acceptPresentationRequest(resolvedPresentationRequest: OpenId4VcSiopResolvedAuthorizationRequest) {
const presentationExchangeService = this.agent.dependencyManager.resolve(DifPresentationExchangeService)

if (!resolvedPresentationRequest.presentationExchange) {
throw new Error('Missing presentation exchange on resolved authorization request')
}

const submissionResult = await this.agent.modules.openId4VcHolder.acceptSiopAuthorizationRequest({
authorizationRequest: resolvedPresentationRequest.authorizationRequest,
presentationExchange: {
credentials: presentationExchangeService.selectCredentialsForRequest(
resolvedPresentationRequest.presentationExchange.credentialsForRequest
),
},
})

return submissionResult.status
return submissionResult.serverResponse
}

public async exit() {
Expand Down
96 changes: 52 additions & 44 deletions demo-openid/src/HolderInquirer.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import type { ResolvedCredentialOffer, ResolvedPresentationRequest } from '@aries-framework/openid4vc'

import { clear } from 'console'
import type { SdJwtVcRecord, W3cCredentialRecord } from '@aries-framework/core/src'
import type {
OpenId4VcSiopResolvedAuthorizationRequest,
OpenId4VciResolvedCredentialOffer,
} from '@aries-framework/openid4vc'

import { DifPresentationExchangeService } from '@aries-framework/core/src'
import console, { clear } from 'console'
import { textSync } from 'figlet'
import { prompt } from 'inquirer'

Expand All @@ -26,8 +31,8 @@ enum PromptOptions {

export class HolderInquirer extends BaseInquirer {
public holder: Holder
public resolvedCredentialOffer?: ResolvedCredentialOffer
public resolvedPresentationRequest?: ResolvedPresentationRequest
public resolvedCredentialOffer?: OpenId4VciResolvedCredentialOffer
public resolvedPresentationRequest?: OpenId4VcSiopResolvedAuthorizationRequest

public constructor(holder: Holder) {
super()
Expand Down Expand Up @@ -89,59 +94,57 @@ export class HolderInquirer extends BaseInquirer {
this.resolvedCredentialOffer = resolvedCredentialOffer

console.log(greenText(`Received credential offer for the following credentials.`))
console.log(
greenText(resolvedCredentialOffer.offeredCredentials.map((credential) => credential.types.join(', ')).join('\n'))
)
console.log(greenText(resolvedCredentialOffer.offeredCredentials.map((credential) => credential.id).join('\n')))
}

public async requestCredential() {
if (!this.resolvedCredentialOffer) {
throw new Error('No credential offer resolved yet.')
}

const credentialsThatCanBeRequested = this.resolvedCredentialOffer.offeredCredentials.map((credential) =>
credential.types.join(', ')
const credentialsThatCanBeRequested = this.resolvedCredentialOffer.offeredCredentials.map(
(credential) => credential.id
)

const choice = await prompt([this.inquireOptions(credentialsThatCanBeRequested)])

const credentialToRequest = this.resolvedCredentialOffer.offeredCredentials.find(
(credential) => credential.types.join(', ') == choice.options
(credential) => credential.id === choice.options
)
if (!credentialToRequest) throw new Error('Credential to request not found.')

console.log(greenText(`Requesting the following credential '${credentialToRequest.types.join(', ')}'`))
console.log(greenText(`Requesting the following credential '${credentialToRequest.id}'`))

const credentials = await this.holder.requestAndStoreCredentials(
this.resolvedCredentialOffer,
this.resolvedCredentialOffer.offeredCredentials
)

const credentialTypes = await Promise.all(
credentials.map((credential) =>
credential.type === 'W3cCredentialRecord'
? `${credential.credential.type.join(', ')}, CredentialType: W3cVerifiableCredential`
: this.holder.agent.sdJwtVc
.fromCompact(credential.compactSdJwtVc)
.then((a) => `${a.prettyClaims.vct}, CredentialType: SdJwtVc`)
)
this.resolvedCredentialOffer.offeredCredentials.map((o) => o.id)
)

console.log(greenText(`Received and stored the following credentials.`))
console.log(greenText(credentialTypes.join('\n')))
console.log('')
credentials.forEach(this.printCredential)
}

public async resolveProofRequest() {
const proofRequestUri = await prompt([this.inquireInput('Enter proof request: ')])
this.resolvedPresentationRequest = await this.holder.resolveProofRequest(proofRequestUri.input)

const presentationDefinition =
this.resolvedPresentationRequest.presentationRequest.presentationDefinitions[0].definition

console.log(greenText(`Presentation Purpose: '${presentationDefinition.purpose}'`))

if (this.resolvedPresentationRequest.presentationSubmission.areRequirementsSatisfied) {
console.log(greenText(`All requirements for creating the presentation are satisfied.`))
const presentationDefinition = this.resolvedPresentationRequest?.presentationExchange?.definition
console.log(greenText(`Presentation Purpose: '${presentationDefinition?.purpose}'`))

if (this.resolvedPresentationRequest?.presentationExchange?.credentialsForRequest.areRequirementsSatisfied) {
const selectedCredentials = Object.values(
this.holder.agent.dependencyManager
.resolve(DifPresentationExchangeService)
.selectCredentialsForRequest(this.resolvedPresentationRequest.presentationExchange.credentialsForRequest)
).flatMap((e) => e)
console.log(
greenText(
`All requirements for creating the presentation are satisfied. The following credentials will be shared`,
true
)
)
selectedCredentials.forEach(this.printCredential)
} else {
console.log(redText(`No credentials available that satisfy the proof request.`))
}
Expand All @@ -150,22 +153,14 @@ export class HolderInquirer extends BaseInquirer {
public async acceptPresentationRequest() {
if (!this.resolvedPresentationRequest) throw new Error('No presentation request resolved yet.')

// we know that only one credential is in the wallet and it satisfies the proof request.
// The submission entry index for this credential is 0.
const credential =
this.resolvedPresentationRequest.presentationSubmission.requirements[0].submissionEntry[0]
.verifiableCredentials[0]
const submissionEntryIndexes = [0]

console.log(greenText(`Accepting the presentation request, with the following credential.`))
console.log(greenText(credential.credential.type.join(', ')))
console.log(greenText(`Accepting the presentation request.`))

const status = await this.holder.acceptPresentationRequest(this.resolvedPresentationRequest, submissionEntryIndexes)
const serverResponse = await this.holder.acceptPresentationRequest(this.resolvedPresentationRequest)

if (status >= 200 && status < 300) {
console.log(`received success status code '${status}'`)
if (serverResponse.status >= 200 && serverResponse.status < 300) {
console.log(`received success status code '${serverResponse.status}'`)
} else {
console.log(`received error status code '${status}'`)
console.log(`received error status code '${serverResponse.status}'`)
}
}

Expand All @@ -188,6 +183,19 @@ export class HolderInquirer extends BaseInquirer {
await runHolder()
}
}

private printCredential = (credential: W3cCredentialRecord | SdJwtVcRecord) => {
if (credential.type === 'W3cCredentialRecord') {
console.log(greenText(`W3cCredentialRecord with claim format ${credential.credential.claimFormat}`, true))
console.log(JSON.stringify(credential.credential.jsonCredential, null, 2))
console.log('')
} else {
console.log(greenText(`SdJwtVcRecord`, true))
const prettyClaims = this.holder.agent.sdJwtVc.fromCompact(credential.compactSdJwtVc).prettyClaims
console.log(JSON.stringify(prettyClaims, null, 2))
console.log('')
}
}
}

void runHolder()
27 changes: 16 additions & 11 deletions demo-openid/src/Issuer.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import type { DidKey } from '@aries-framework/core'
import type {
CredentialHolderBinding,
CredentialHolderDidBinding,
CredentialRequestToCredentialMapper,
OpenId4VcCredentialHolderBinding,
OpenId4VcCredentialHolderDidBinding,
OpenId4VciCredentialRequestToCredentialMapper,
OpenId4VciCredentialSupportedWithId,
OpenId4VcIssuerRecord,
} from '@aries-framework/openid4vc'

import { AskarModule } from '@aries-framework/askar'
import {
ClaimFormat,
parseDid,
AriesFrameworkError,
W3cCredential,
Expand Down Expand Up @@ -51,14 +52,15 @@ function getCredentialRequestToCredentialMapper({
issuerDidKey,
}: {
issuerDidKey: DidKey
}): CredentialRequestToCredentialMapper {
}): OpenId4VciCredentialRequestToCredentialMapper {
return async ({ holderBinding, credentialsSupported }) => {
const credentialSupported = credentialsSupported[0]

if (credentialSupported.id === universityDegreeCredential.id) {
assertDidBasedHolderBinding(holderBinding)

return {
format: ClaimFormat.JwtVc,
credential: new W3cCredential({
type: universityDegreeCredential.types,
issuer: new W3cIssuer({
Expand All @@ -77,6 +79,7 @@ function getCredentialRequestToCredentialMapper({
assertDidBasedHolderBinding(holderBinding)

return {
format: ClaimFormat.JwtVc,
credential: new W3cCredential({
type: openBadgeCredential.types,
issuer: new W3cIssuer({
Expand All @@ -93,6 +96,7 @@ function getCredentialRequestToCredentialMapper({

if (credentialSupported.id === universityDegreeCredentialSdJwt.id) {
return {
format: ClaimFormat.SdJwtVc,
payload: { vct: universityDegreeCredentialSdJwt.vct, university: 'innsbruck', degree: 'bachelor' },
holder: holderBinding,
issuer: {
Expand Down Expand Up @@ -131,7 +135,7 @@ export class Issuer extends BaseAgent<{
},
},
}),
} as const,
},
})

this.app.use('/oid4vci', openId4VciRouter)
Expand All @@ -148,14 +152,13 @@ export class Issuer extends BaseAgent<{
}

public async createCredentialOffer(offeredCredentials: string[]) {
const { credentialOfferUri } = await this.agent.modules.openId4VcIssuer.createCredentialOffer({
const { credentialOffer } = await this.agent.modules.openId4VcIssuer.createCredentialOffer({
issuerId: this.issuerRecord.issuerId,
offeredCredentials,
scheme: 'openid-credential-offer',
preAuthorizedCodeFlowConfig: { userPinRequired: false },
})

return credentialOfferUri
return credentialOffer
}

public async exit() {
Expand All @@ -170,7 +173,9 @@ export class Issuer extends BaseAgent<{
}

function assertDidBasedHolderBinding(
holderBinding: CredentialHolderBinding
): asserts holderBinding is CredentialHolderDidBinding {
throw new AriesFrameworkError('Only did based holder bindings supported for this credential type')
holderBinding: OpenId4VcCredentialHolderBinding
): asserts holderBinding is OpenId4VcCredentialHolderDidBinding {
if (holderBinding.method !== 'did') {
throw new AriesFrameworkError('Only did based holder bindings supported for this credential type')
}
}
Loading

0 comments on commit 226de98

Please sign in to comment.