Skip to content

Commit

Permalink
feat(openid4vc): persistance and events (#1793)
Browse files Browse the repository at this point in the history
Signed-off-by: Timo Glastra <timo@animo.id>
  • Loading branch information
TimoGlastra authored Mar 13, 2024
1 parent 1a46e9f commit f4c386a
Show file tree
Hide file tree
Showing 62 changed files with 2,541 additions and 703 deletions.
4 changes: 2 additions & 2 deletions demo-openid/src/Verifier.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ export class Verifier extends BaseAgent<{ askar: AskarModule; openId4VcVerifier:

// TODO: add method to show the received presentation submission
public async createProofRequest(presentationDefinition: DifPresentationExchangeDefinitionV2) {
const { authorizationRequestUri } = await this.agent.modules.openId4VcVerifier.createAuthorizationRequest({
const { authorizationRequest } = await this.agent.modules.openId4VcVerifier.createAuthorizationRequest({
requestSigner: {
method: 'did',
didUrl: this.verificationMethod.id,
Expand All @@ -100,7 +100,7 @@ export class Verifier extends BaseAgent<{ askar: AskarModule; openId4VcVerifier:
},
})

return authorizationRequestUri
return authorizationRequest
}

public async exit() {
Expand Down
2 changes: 1 addition & 1 deletion packages/action-menu/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
"@credo-ts/core": "0.4.2",
"class-transformer": "0.5.1",
"class-validator": "0.14.1",
"rxjs": "^7.2.0"
"rxjs": "^7.8.0"
},
"devDependencies": {
"reflect-metadata": "^0.1.13",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import type { CredentialWithRevocationMetadata } from '../models/utils'
import type { AnonCredsCredentialProve, CreateW3cPresentationOptions, AnonCredsHolderService } from '../services'
import type {
AgentContext,
IAnoncredsDataIntegrityService,
IAnonCredsDataIntegrityService,
AnoncredsDataIntegrityVerifyPresentation,
DifPresentationExchangeDefinition,
DifPresentationExchangeSubmission,
Expand Down Expand Up @@ -36,7 +36,7 @@ import { getW3cAnonCredsCredentialMetadata } from './utils'
export type PathComponent = string | number

@injectable()
export class AnonCredsDataIntegrityService implements IAnoncredsDataIntegrityService {
export class AnonCredsDataIntegrityService implements IAnonCredsDataIntegrityService {
private getDataIntegrityProof(credential: W3cJsonLdVerifiableCredential) {
const cryptosuite = ANONCREDS_DATA_INTEGRITY_CRYPTOSUITE
if (Array.isArray(credential.proof)) {
Expand Down
4 changes: 2 additions & 2 deletions packages/anoncreds/tests/anoncredsSetup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import {
V2CredentialProtocol,
V2ProofProtocol,
DidsModule,
PresentationExchangeProofFormatService,
DifPresentationExchangeProofFormatService,
TypedArrayEncoder,
ProofState,
} from '@credo-ts/core'
Expand Down Expand Up @@ -91,7 +91,7 @@ export const getAnonCredsModules = ({

const anonCredsCredentialFormatService = new AnonCredsCredentialFormatService()
const anonCredsProofFormatService = new AnonCredsProofFormatService()
const presentationExchangeProofFormatService = new PresentationExchangeProofFormatService()
const presentationExchangeProofFormatService = new DifPresentationExchangeProofFormatService()

const cheqdSdk = cheqd ? new CheqdModule(getCheqdModuleConfig(cheqd.seed, cheqd.rpcUrl)) : undefined
const modules = {
Expand Down
2 changes: 1 addition & 1 deletion packages/askar/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
"bn.js": "^5.2.1",
"class-transformer": "0.5.1",
"class-validator": "0.14.1",
"rxjs": "^7.2.0",
"rxjs": "^7.8.0",
"tsyringe": "^4.8.0"
},
"devDependencies": {
Expand Down
2 changes: 1 addition & 1 deletion packages/cheqd/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
"@stablelib/ed25519": "^1.0.3",
"class-transformer": "^0.5.1",
"class-validator": "0.14.1",
"rxjs": "^7.2.0",
"rxjs": "^7.8.0",
"tsyringe": "^4.8.0"
},
"devDependencies": {
Expand Down
6 changes: 3 additions & 3 deletions packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@
"@multiformats/base-x": "^4.0.1",
"@sd-jwt/core": "^0.2.1",
"@sd-jwt/decode": "^0.2.1",
"@sphereon/pex": "3.2.1-unstable.7",
"@sphereon/pex-models": "^2.2.0",
"@sphereon/pex": "3.3.0",
"@sphereon/pex-models": "^2.2.2",
"@sphereon/ssi-types": "^0.18.1",
"@stablelib/ed25519": "^1.0.2",
"@stablelib/sha256": "^1.0.1",
Expand All @@ -49,7 +49,7 @@
"object-inspect": "^1.10.3",
"query-string": "^7.0.1",
"reflect-metadata": "^0.1.13",
"rxjs": "^7.2.0",
"rxjs": "^7.8.0",
"tsyringe": "^4.8.0",
"uuid": "^9.0.0",
"varint": "^6.0.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import type { Query } from '../../storage/StorageService'
import type { VerificationMethod } from '../dids'
import type { SdJwtVcRecord } from '../sd-jwt-vc'
import type { W3cCredentialRecord } from '../vc'
import type { IAnoncredsDataIntegrityService } from '../vc/data-integrity/models/IAnonCredsDataIntegrityService'
import type { IAnonCredsDataIntegrityService } from '../vc/data-integrity/models/IAnonCredsDataIntegrityService'
import type {
PresentationSignCallBackParams,
SdJwtDecodedVerifiableCredentialWithKbJwtInput,
Expand All @@ -35,7 +35,6 @@ import { Hasher, JsonTransformer } from '../../utils'
import { DidsApi, getKeyFromVerificationMethod } from '../dids'
import { SdJwtVcApi } from '../sd-jwt-vc'
import {
W3cJsonLdVerifiableCredential,
ClaimFormat,
SignatureSuiteRegistry,
W3cCredentialRepository,
Expand Down Expand Up @@ -398,7 +397,7 @@ export class DifPresentationExchangeService {
* and all credentials have an ANONCREDS_DATA_INTEGRITY proof we default to
* signing the presentation using the ANONCREDS_DATA_INTEGRITY_CRYPTOSUITE
*/
private shouldSignUsingAnoncredsDataIntegrity(
private shouldSignUsingAnonCredsDataIntegrity(
presentationToCreate: PresentationToCreate,
presentationSubmission: DifPresentationExchangeSubmission
) {
Expand Down Expand Up @@ -460,13 +459,13 @@ export class DifPresentationExchangeService {

return signedPresentation.encoded as W3CVerifiablePresentation
} else if (presentationToCreate.claimFormat === ClaimFormat.LdpVp) {
if (this.shouldSignUsingAnoncredsDataIntegrity(presentationToCreate, presentationSubmission)) {
if (this.shouldSignUsingAnonCredsDataIntegrity(presentationToCreate, presentationSubmission)) {
// make sure the descriptors format properties are set correctly
presentationSubmission.descriptor_map = presentationSubmission.descriptor_map.map((descriptor) => ({
...descriptor,
format: 'di_vp',
}))
const anoncredsDataIntegrityService = agentContext.dependencyManager.resolve<IAnoncredsDataIntegrityService>(
const anoncredsDataIntegrityService = agentContext.dependencyManager.resolve<IAnonCredsDataIntegrityService>(
AnonCredsDataIntegrityServiceSymbol
)
const presentation = await anoncredsDataIntegrityService.createPresentation(agentContext, {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import type {
DifPresentationExchangeSubmission,
} from '../../../dif-presentation-exchange'
import type {
IAnoncredsDataIntegrityService,
IAnonCredsDataIntegrityService,
W3cVerifiablePresentation,
W3cVerifyPresentationResult,
} from '../../../vc'
Expand Down Expand Up @@ -53,7 +53,9 @@ const PRESENTATION_EXCHANGE_PRESENTATION_PROPOSAL = 'dif/presentation-exchange/d
const PRESENTATION_EXCHANGE_PRESENTATION_REQUEST = 'dif/presentation-exchange/definitions@v1.0'
const PRESENTATION_EXCHANGE_PRESENTATION = 'dif/presentation-exchange/submission@v1.0'

export class PresentationExchangeProofFormatService implements ProofFormatService<DifPresentationExchangeProofFormat> {
export class DifPresentationExchangeProofFormatService
implements ProofFormatService<DifPresentationExchangeProofFormat>
{
public readonly formatKey = 'presentationExchange' as const

private presentationExchangeService(agentContext: AgentContext) {
Expand Down Expand Up @@ -227,12 +229,11 @@ export class PresentationExchangeProofFormatService implements ProofFormatServic
return { attachment, format }
}

private shouldVerifyUsingAnoncredsDataIntegrity(
private shouldVerifyUsingAnonCredsDataIntegrity(
presentation: W3cVerifiablePresentation,
presentationSubmission: DifPresentationExchangeSubmission
) {
if (presentation.claimFormat !== ClaimFormat.LdpVp) return false

const descriptorMap = presentationSubmission.descriptor_map

const verifyUsingDataIntegrity = descriptorMap.every((descriptor) => descriptor.format === ClaimFormat.DiVp)
Expand Down Expand Up @@ -300,9 +301,9 @@ export class PresentationExchangeProofFormatService implements ProofFormatServic
})
} else if (parsedPresentation.claimFormat === ClaimFormat.LdpVp) {
if (
this.shouldVerifyUsingAnoncredsDataIntegrity(parsedPresentation, jsonPresentation.presentation_submission)
this.shouldVerifyUsingAnonCredsDataIntegrity(parsedPresentation, jsonPresentation.presentation_submission)
) {
const dataIntegrityService = agentContext.dependencyManager.resolve<IAnoncredsDataIntegrityService>(
const dataIntegrityService = agentContext.dependencyManager.resolve<IAnonCredsDataIntegrityService>(
AnonCredsDataIntegrityServiceSymbol
)
const proofVerificationResult = await dataIntegrityService.verifyPresentation(agentContext, {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { ProofsModule } from '../../../ProofsModule'
import { ProofRole, ProofState } from '../../../models'
import { V2ProofProtocol } from '../../../protocol'
import { ProofExchangeRecord } from '../../../repository'
import { PresentationExchangeProofFormatService } from '../DifPresentationExchangeProofFormatService'
import { DifPresentationExchangeProofFormatService } from '../DifPresentationExchangeProofFormatService'

const mockProofRecord = () =>
new ProofExchangeRecord({
Expand Down Expand Up @@ -99,15 +99,15 @@ describe('Presentation Exchange ProofFormatService', () => {
{
pex: new DifPresentationExchangeModule(),
proofs: new ProofsModule({
proofProtocols: [new V2ProofProtocol({ proofFormats: [new PresentationExchangeProofFormatService()] })],
proofProtocols: [new V2ProofProtocol({ proofFormats: [new DifPresentationExchangeProofFormatService()] })],
}),
}
)
)

await agent.initialize()

pexFormatService = agent.dependencyManager.resolve(PresentationExchangeProofFormatService)
pexFormatService = agent.dependencyManager.resolve(DifPresentationExchangeProofFormatService)
})

describe('Create Presentation Exchange Proof Proposal / Request', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export const AnonCredsDataIntegrityServiceSymbol = Symbol('AnonCredsDataIntegrit
* to it's unique properties, in order to not pollute,
* the existing api's.
*/
export interface IAnoncredsDataIntegrityService {
export interface IAnonCredsDataIntegrityService {
createPresentation(
agentContext: AgentContext,
options: AnoncredsDataIntegrityCreatePresentation
Expand Down
4 changes: 2 additions & 2 deletions packages/core/tests/jsonld.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { InMemoryWalletModule } from '../../../tests/InMemoryWalletModule'
import { askarModule } from '../../askar/tests/helpers'
import { BbsModule } from '../../bbs-signatures/src/BbsModule'
import {
PresentationExchangeProofFormatService,
DifPresentationExchangeProofFormatService,
V2ProofProtocol,
CacheModule,
CredentialEventTypes,
Expand Down Expand Up @@ -41,7 +41,7 @@ export const getJsonLdModules = ({
}),
proofs: new ProofsModule({
autoAcceptProofs,
proofProtocols: [new V2ProofProtocol({ proofFormats: [new PresentationExchangeProofFormatService()] })],
proofProtocols: [new V2ProofProtocol({ proofFormats: [new DifPresentationExchangeProofFormatService()] })],
}),
cache: new CacheModule({
cache: new InMemoryLruCache({ limit: 100 }),
Expand Down
2 changes: 1 addition & 1 deletion packages/indy-vdr/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
"@types/ref-array-di": "^1.2.6",
"@types/ref-struct-di": "^1.1.10",
"rimraf": "^4.4.0",
"rxjs": "^7.2.0",
"rxjs": "^7.8.0",
"typescript": "~4.9.5"
},
"peerDependencies": {
Expand Down
9 changes: 5 additions & 4 deletions packages/openid4vc/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,11 @@
"dependencies": {
"@credo-ts/core": "0.4.2",
"@sphereon/ssi-types": "^0.18.1",
"@sphereon/oid4vci-client": "0.8.2-next.48",
"@sphereon/oid4vci-common": "0.8.2-next.48",
"@sphereon/oid4vci-issuer": "0.8.2-next.48",
"@sphereon/did-auth-siop": "0.6.0-unstable.9"
"@sphereon/oid4vci-client": "^0.10.1",
"@sphereon/oid4vci-common": "^0.10.1",
"@sphereon/oid4vci-issuer": "^0.10.1",
"@sphereon/did-auth-siop": "0.6.2",
"rxjs": "^7.8.0"
},
"devDependencies": {
"@credo-ts/tenants": "0.4.2",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@ export class OpenId4VciHolderService {
uri: credentialOffer,
resolveOfferUri: true,
retrieveServerMetadata: true,
// This is a separate call, so we don't fetch it here, however it may be easier to just construct it here?
createAuthorizationRequestURL: false,
})

if (!client.credentialOffer?.credential_offer) {
Expand Down Expand Up @@ -188,7 +190,7 @@ export class OpenId4VciHolderService {
codeChallenge,
redirectUri,
credentialOffer: credentialOfferPayload,
codeChallengeMethod: CodeChallengeMethod.SHA256,
codeChallengeMethod: CodeChallengeMethod.S256,
// TODO: Read HAIP SdJwtVc's should always be requested via scopes
// TODO: should we now always use scopes instead of authDetails? or both????
scope: scope ?? [],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import express from 'express'

import { AskarModule } from '../../../../askar/src'
import { askarModuleConfig } from '../../../../askar/tests/helpers'
import { createAgentFromModules } from '../../../tests/utils'
import { OpenId4VcVerifierModule } from '../../openid4vc-verifier'
import { waitForVerificationSessionRecordSubject, createAgentFromModules } from '../../../tests/utils'
import { OpenId4VcVerificationSessionState, OpenId4VcVerifierModule } from '../../openid4vc-verifier'
import { OpenId4VcHolderModule } from '../OpenId4VcHolderModule'

const port = 3121
Expand Down Expand Up @@ -60,16 +60,17 @@ describe('OpenId4VcHolder | OpenID4VP', () => {
})

it('siop authorization request without presentation exchange', async () => {
const { authorizationRequestUri } = await verifier.agent.modules.openId4VcVerifier.createAuthorizationRequest({
requestSigner: {
method: 'did',
didUrl: verifier.kid,
},
verifierId: openIdVerifier.verifierId,
})
const { authorizationRequest, verificationSession } =
await verifier.agent.modules.openId4VcVerifier.createAuthorizationRequest({
requestSigner: {
method: 'did',
didUrl: verifier.kid,
},
verifierId: openIdVerifier.verifierId,
})

const resolvedAuthorizationRequest = await holder.agent.modules.openId4VcHolder.resolveSiopAuthorizationRequest(
authorizationRequestUri
authorizationRequest
)

const { submittedResponse, serverResponse } =
Expand All @@ -93,11 +94,14 @@ describe('OpenId4VcHolder | OpenID4VP', () => {
state: expect.any(String),
})

await waitForVerificationSessionRecordSubject(verifier.replaySubject, {
state: OpenId4VcVerificationSessionState.ResponseVerified,
contextCorrelationId: verifier.agent.context.contextCorrelationId,
verificationSessionId: verificationSession.id,
})

const { idToken, presentationExchange } =
await verifier.agent.modules.openId4VcVerifier.verifyAuthorizationResponse({
authorizationResponse: submittedResponse,
verifierId: openIdVerifier.verifierId,
})
await verifier.agent.modules.openId4VcVerifier.getVerifiedAuthorizationResponse(verificationSession.id)

expect(presentationExchange).toBeUndefined()
expect(idToken).toMatchObject({
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export enum OpenId4VcIssuanceSessionState {
OfferCreated = 'OfferCreated',
OfferUriRetrieved = 'OfferUriRetrieved',
AccessTokenRequested = 'AccessTokenRequested',
AccessTokenCreated = 'AccessTokenCreated',
CredentialRequestReceived = 'CredentialRequestReceived',
CredentialIssued = 'CredentialIssued',
Error = 'Error',
}
Loading

0 comments on commit f4c386a

Please sign in to comment.