From ca553cf0446d6c2716ee674e65b6f62e18524343 Mon Sep 17 00:00:00 2001 From: Rizel Scarlett Date: Mon, 29 Jan 2024 17:44:50 -0500 Subject: [PATCH 01/31] first few codesnippets --- .../verifiable-credentials/fan-club-vc.mdx | 149 ++++++++++++++++++ 1 file changed, 149 insertions(+) diff --git a/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx b/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx index 34b3864c5..3eead5101 100644 --- a/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx +++ b/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx @@ -3,6 +3,8 @@ title: VC Workflow hide_title: true sidebar_position: 10 --- +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; # Verifiable Credentials for Fan Club Membership @@ -14,11 +16,41 @@ In this tutorial, we'll learn how to use [verifiable credentials](/docs/web5/lea ## Setting the Stage Before we start issuing and verifying credentials, let's set up our environment by installing the [@web5/credentials](https://www.npmjs.com/package/@web5/credentials) and [@web5/dids](https://www.npmjs.com/package/@web5/dids) packages: + + + ```bash npm install @web5/credentials npm install @web5/dids ``` + + + + +**Configure Repositories** + +```kotlin +repositories { + mavenCentral() + maven("https://jitpack.io") + maven("https://repo.danubetech.com/repository/maven-public/") + maven("https://repository.jboss.org/nexus/content/repositories/thirdparty-releases/") +} +``` + +**Configure Dependencies** + +```kotlin +dependencies { + implementation("xyz.block:web5-credentials:0.0.9-delta") + implementation("xyz.block:web5-dids:0.0.9-delta") +} +``` + + + + ## The Cast There are a few characters involved in our story: @@ -36,6 +68,9 @@ This is because verifiable credentials use DIDs to identify issuers and holders. If you need to create DIDs, you can do so with the [@web5/dids](https://www.npmjs.com/package/@web5/dids) package: + + + ```js import { DidKeyMethod } from '@web5/dids'; @@ -43,11 +78,32 @@ const fanClubIssuerDid = await DidKeyMethod.create(); const aliceDid = await DidKeyMethod.create(); ``` + + + + +```kotlin +import web5.sdk.crypto.InMemoryKeyManager +import web5.sdk.dids.methods.key.DidKey + +val fanClubIssuerDidObject = DidKey.create(InMemoryKeyManager()) +val fanClubIssuerDid = fanClubIssuerDidObject.resolve() + +val aliceDidObject = DidKey.create(InMemoryKeyManager()) +val aliceDid = aliceDidObject.resolve() +``` + + + + ### Model Credential Now, let's create the **SwiftiesFanClub** credential. We'll first model it with a class with some basic properties, `level` and `legit`: + + + ```js title="Issuer.js" import { VerifiableCredential, PresentationExchange } from "@web5/credentials"; @@ -62,6 +118,25 @@ class SwiftiesFanClub { } ``` + + + + +```kotlin title="Issuer.kt" +import web5.sdk.credentials.VerifiableCredential +import web5.sdk.credentials.PresentationExchange +import web5.sdk.credentials.model.PresentationDefinitionV2 + +data class SwiftiesFanClub( + // indicates the fan's dedication level + val level: String, + // indicates if the fan is a genuine Swiftie + val legit: Boolean +) +``` + + + :::note Note that credentials can be customized to fit various needs and scenarios. In our example, we used `level` and `legit`, but you could add more properties like `memberSince`, `favoriteAlbum`, or any other relevant data that suits your use case. ::: @@ -70,6 +145,9 @@ Note that credentials can be customized to fit various needs and scenarios. In o Next we can create the verifiable credential with an instance of the class: + + + ```js title="Issuer.js" const vc = await VerifiableCredential.create({ type: 'SwiftiesFanClub', @@ -79,6 +157,21 @@ const vc = await VerifiableCredential.create({ }); ``` + + + + +```kotlin title="Issuer.kt" +val vc = VerifiableCredential.create( + type = "SwiftiesFanClub", + issuer = fanClubIssuerDid.didDocument.id.toString(), + subject = aliceDid.didDocument.id.toString(), + data =SwiftiesFanClub(level = "Stan", legit = true) +) +``` + + + ### Credential Properties Let's break down the `VerifiableCredential.create()` method to understand what each property means and how it contributes to our credential: @@ -96,6 +189,9 @@ Let's break down the `VerifiableCredential.create()` method to understand what e `VerifiableCredential.create()` returns a VC as a JSON object: + + + ```js vcDataModel: { '@context': [ 'https://www.w3.org/2018/credentials/v1' ], @@ -111,14 +207,53 @@ vcDataModel: { } ``` + + + + +```js +{ + "@context": [ + "https://www.w3.org/2018/credentials/v1" + ], + "type": [ + "VerifiableCredential", + "SwiftiesFanClub" + ], + "id": "urn:uuid:daa5ff01-9b7d-485b-9410-22a42952d46c", + "issuer": "did:key:z6Mkn4w6nSaWe4fjNJRvaHZwFnMm5VexvjzDeozEu2G7jC34", + "issuanceDate": "2023-12-14T08:20:41Z", + "credentialSubject": { + "id": "did:key:z6MkjGSeekPGE9QfczHWyW8v2ZzJU68kqSHzV7L2dmQyuyDu", + "level": "Stan", + "legit": true + } +} +``` + + + ### Sign Credential Last but not least, we must cryptographically sign the VC to make it official: + + + ```js title="Issuer.js" const signedVcJwt = await vc.sign({ did: fanClubIssuerDid }); ``` + + + + +```kotlin title="Issuer.kt" +val signedVcJwt = vc.sign(fanClubIssuerDidObject) +``` + + + Signing the credential returns a [VC JSON Web Token](/docs/web5/build/verifiable-credentials/jwt-to-vc#what-is-a-jwt), ideal for secure transmission of the credential. @@ -265,10 +400,24 @@ The signed VC JWT is a secure representation of the credential, ideal for transm However, the verifier will likely need to inspect or use the data within the credential. They can use `parseJwt()` to convert the JWT back into a `VerifiableCredential` object. + + + + ```js title="Verifier.js" const parsedVC = await VerifiableCredential.parseJwt( { vcJwt: signedVcJwt }); ``` + + + + +```kotlin title="Issuer.kt" +val parsedJwt = VerifiableCredential.parseJwt(signedVcJwt) +``` + + + This returns: ```js From 639c7d40655f65d81c9e3235601a894764f55201 Mon Sep 17 00:00:00 2001 From: Rizel Scarlett Date: Mon, 29 Jan 2024 18:33:32 -0500 Subject: [PATCH 02/31] verifying code snippet --- .../verifiable-credentials/fan-club-vc.mdx | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx b/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx index 3eead5101..dd9fb23fe 100644 --- a/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx +++ b/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx @@ -384,6 +384,9 @@ The result of the presentation: After receiving the credential, the verifier will want to verify it to ensure that it is valid and has not been tampered with. They can do this with `VerifiableCredential.verify()`. If verification is unsuccessful, an error will be thrown: + + + ```js title="Verifier.js" try { await VerifiableCredential.verify({ vcJwt: signedVcJwt }); @@ -393,6 +396,20 @@ try { } ``` + + + +```kotlin title="Verifier.kt" +try { + VerifiableCredential.verify(signedVcJwt) + println("\nVC Verification successful!\n") +} catch (err: Exception) { + println("\nVC Verification failed: ${err.message}\n") +} +``` + + + ### Parse JWT into VC The signed VC JWT is a secure representation of the credential, ideal for transmission or storage. From 869afed4d974267d763aca2237121645c7145b69 Mon Sep 17 00:00:00 2001 From: Rizel Scarlett Date: Mon, 29 Jan 2024 18:40:01 -0500 Subject: [PATCH 03/31] return value of parsed vc --- .../verifiable-credentials/fan-club-vc.mdx | 31 ++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx b/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx index dd9fb23fe..40e908bc5 100644 --- a/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx +++ b/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx @@ -429,7 +429,7 @@ const parsedVC = await VerifiableCredential.parseJwt( { vcJwt: signedVcJwt }); -```kotlin title="Issuer.kt" +```kotlin title="Verifier.kt" val parsedJwt = VerifiableCredential.parseJwt(signedVcJwt) ``` @@ -437,6 +437,9 @@ val parsedJwt = VerifiableCredential.parseJwt(signedVcJwt) This returns: + + + ```js vcDataModel: { '@context': [ 'https://www.w3.org/2018/credentials/v1' ], @@ -452,4 +455,30 @@ vcDataModel: { } ``` + + + +```js +{ + "@context": [ + "https://www.w3.org/2018/credentials/v1" + ], + "type": [ + "VerifiableCredential", + "SwiftiesFanClub" + ], + "id": "urn:uuid:daa5ff01-9b7d-485b-9410-22a42952d46c", + "issuer": "did:key:z6Mkn4w6nSaWe4fjNJRvaHZwFnMm5VexvjzDeozEu2G7jC34", + "issuanceDate": "2023-12-14T08:20:41Z", + "credentialSubject": { + "id": "did:key:z6MkjGSeekPGE9QfczHWyW8v2ZzJU68kqSHzV7L2dmQyuyDu", + "level": "Stan", + "legit": true + } +} +``` + + + + Given Alice's verified credential, she's all set to receive her free merch for being a proud member of the Swifties Fan Club! \ No newline at end of file From 1b996302846c3ce02862fbbdc4ed534333e9cf92 Mon Sep 17 00:00:00 2001 From: Rizel Scarlett Date: Tue, 30 Jan 2024 09:26:37 -0500 Subject: [PATCH 04/31] just import all the credential model to reduce imports --- site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx b/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx index 40e908bc5..2e0e3739f 100644 --- a/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx +++ b/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx @@ -125,7 +125,7 @@ class SwiftiesFanClub { ```kotlin title="Issuer.kt" import web5.sdk.credentials.VerifiableCredential import web5.sdk.credentials.PresentationExchange -import web5.sdk.credentials.model.PresentationDefinitionV2 +import web5.sdk.credentials.model.* data class SwiftiesFanClub( // indicates the fan's dedication level From 61e7e5e8edb05813fdd54f91d7943cf290059be4 Mon Sep 17 00:00:00 2001 From: Rizel Scarlett Date: Tue, 30 Jan 2024 09:37:31 -0500 Subject: [PATCH 05/31] satisfies presentation def --- .../verifiable-credentials/fan-club-vc.mdx | 56 ++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx b/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx index 2e0e3739f..4bff6626f 100644 --- a/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx +++ b/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx @@ -125,7 +125,6 @@ class SwiftiesFanClub { ```kotlin title="Issuer.kt" import web5.sdk.credentials.VerifiableCredential import web5.sdk.credentials.PresentationExchange -import web5.sdk.credentials.model.* data class SwiftiesFanClub( // indicates the fan's dedication level @@ -277,6 +276,9 @@ A presentation exchange is the process where the holder of VCs presents them to To kick off the presentation exchange, the Swag Supplier (verifier) will send a request to Alice, which includes a presentation definition, specifying what credentials or claims are needed. Here's how the verifier can create the presentation definition, and validate that it is properly formed: + + + ```js title="Verifier.js" import { VerifiableCredential, PresentationExchange } from "@web5/credentials"; @@ -304,6 +306,40 @@ const presentationDefinition = { const definitionValidation = PresentationExchange.validateDefinition({ presentationDefinition }); ``` + + + + +```kotlin title="Verifier.kt" +import web5.sdk.credentials.PresentationExchange +import web5.sdk.credentials.VerifiableCredential +import web5.sdk.credentials.model.* + +val presentationDefinition = PresentationDefinitionV2( + id = "presDefId123", + name = "Swifties Fan Club Presentation Definition", + purpose = "for proving membership in the fan club", + inputDescriptors = listOf( + InputDescriptorV2( + id = "legitness", + purpose = "are you legit or not?", + constraints = ConstraintsV2( + fields = listOf( + FieldV2( + path = listOf("$.vc.credentialSubject.legit") + ) + ) + ) + ) + ) +) +``` + + + + + + A successful validation would result in: ```js @@ -316,6 +352,9 @@ Once a presentation definition is presented to Alice, she'd want to make sure th This can be done by passing the JWT(s) and the presentation definition to `satisfiesPresentationDefinition()` method. Typically this step is done by the app that Alice is using to store and present her credentials: + + + ```js title="Wallet.js" // Does VC Satisfy the Presentation Definition try { @@ -326,6 +365,21 @@ try { } ``` + + + + +```kotlin title="Wallet.kt" +try { + PresentationExchange.satisfiesPresentationDefinition(listOf(signedVcJwt), presentationDefinition) + println("\nVC Satisfies Presentation Definition!\n") +} catch (e: Exception) { + println("VC does not satisfy Presentation Definition: ${e.message}") +} +``` + + + ### Create Presentation Once Alice's app is confident that her credential satisfies the presentation definition, the presentation would be created: From 3c1fa51302c911a5c8161282f9cf2c864075e7e9 Mon Sep 17 00:00:00 2001 From: Rizel Scarlett Date: Tue, 30 Jan 2024 10:07:25 -0500 Subject: [PATCH 06/31] create presentation result --- .../verifiable-credentials/fan-club-vc.mdx | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx b/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx index 4bff6626f..6cac31b23 100644 --- a/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx +++ b/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx @@ -370,6 +370,7 @@ try { ```kotlin title="Wallet.kt" +// Does VC Satisfy the Presentation Definition try { PresentationExchange.satisfiesPresentationDefinition(listOf(signedVcJwt), presentationDefinition) println("\nVC Satisfies Presentation Definition!\n") @@ -384,12 +385,28 @@ try { Once Alice's app is confident that her credential satisfies the presentation definition, the presentation would be created: + + + + ```js title="Wallet.js" // Create Presentation Result that contains a Verifiable Presentation and Presentation Submission const presentationResult = PresentationExchange.createPresentationFromCredentials({vcJwts: [signedVcJwt], presentationDefinition: presentationDefinition }); console.log('\nPresentation Result: ' + JSON.stringify(presentationResult)); ``` + + + + +```kt title="Wallet.kt" +// Create Presentation Result that contains a Verifiable Presentation and Presentation Submission +val presentationResult = PresentationExchange.createPresentationFromCredentials(listOf(signedSimpleVcJwt), presentationDefinition) +println("Presentation Result: ${presentationResult}") +``` + + + The result of the presentation: ```json From 67b6e0067591cc187d4fa28e9ec85f5490137f77 Mon Sep 17 00:00:00 2001 From: Rizel Scarlett Date: Tue, 30 Jan 2024 10:08:16 -0500 Subject: [PATCH 07/31] kotlin results are json --- site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx b/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx index 6cac31b23..6c8905f48 100644 --- a/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx +++ b/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx @@ -210,7 +210,7 @@ vcDataModel: { -```js +```json { "@context": [ "https://www.w3.org/2018/credentials/v1" @@ -529,7 +529,7 @@ vcDataModel: { -```js +```json { "@context": [ "https://www.w3.org/2018/credentials/v1" From a61872da14aa1187b95ff8c076f49068b57c148e Mon Sep 17 00:00:00 2001 From: Rizel Scarlett Date: Tue, 30 Jan 2024 10:12:13 -0500 Subject: [PATCH 08/31] formatting --- site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx b/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx index 6c8905f48..4519954e6 100644 --- a/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx +++ b/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx @@ -165,7 +165,7 @@ val vc = VerifiableCredential.create( type = "SwiftiesFanClub", issuer = fanClubIssuerDid.didDocument.id.toString(), subject = aliceDid.didDocument.id.toString(), - data =SwiftiesFanClub(level = "Stan", legit = true) + data = SwiftiesFanClub(level = "Stan", legit = true) ) ``` @@ -527,7 +527,7 @@ vcDataModel: { ``` - + ```json { From d2569c8a62fbb4664193bc307aa87fe875ff8d6a Mon Sep 17 00:00:00 2001 From: Rizel Scarlett Date: Wed, 31 Jan 2024 14:34:50 -0500 Subject: [PATCH 09/31] removing unnecessary repo --- site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx | 1 - 1 file changed, 1 deletion(-) diff --git a/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx b/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx index 4519954e6..cea450c0d 100644 --- a/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx +++ b/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx @@ -35,7 +35,6 @@ repositories { mavenCentral() maven("https://jitpack.io") maven("https://repo.danubetech.com/repository/maven-public/") - maven("https://repository.jboss.org/nexus/content/repositories/thirdparty-releases/") } ``` From a499cc77ac165a9bb7b1f7646e21076643fa5352 Mon Sep 17 00:00:00 2001 From: Rizel Scarlett Date: Wed, 31 Jan 2024 15:23:47 -0500 Subject: [PATCH 10/31] updating to newer version of sdk --- .../verifiable-credentials/fan-club-vc.mdx | 38 ++++++++++++------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx b/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx index cea450c0d..42b0bc70b 100644 --- a/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx +++ b/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx @@ -6,6 +6,9 @@ sidebar_position: 10 import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; + + + # Verifiable Credentials for Fan Club Membership Alice is a long-time fan of one of the biggest pop stars in the world! @@ -42,8 +45,8 @@ repositories { ```kotlin dependencies { - implementation("xyz.block:web5-credentials:0.0.9-delta") - implementation("xyz.block:web5-dids:0.0.9-delta") + implementation("xyz.block:web5-credentials:0.10.0") + implementation("xyz.block:web5-dids:0.10.0") } ``` @@ -85,11 +88,8 @@ const aliceDid = await DidKeyMethod.create(); import web5.sdk.crypto.InMemoryKeyManager import web5.sdk.dids.methods.key.DidKey -val fanClubIssuerDidObject = DidKey.create(InMemoryKeyManager()) -val fanClubIssuerDid = fanClubIssuerDidObject.resolve() - -val aliceDidObject = DidKey.create(InMemoryKeyManager()) -val aliceDid = aliceDidObject.resolve() +val fanClubIssuerDid = DidKey.create(InMemoryKeyManager()) +val aliceDid = DidKey.create(InMemoryKeyManager()) ``` @@ -128,6 +128,7 @@ import web5.sdk.credentials.PresentationExchange data class SwiftiesFanClub( // indicates the fan's dedication level val level: String, + // indicates if the fan is a genuine Swiftie val legit: Boolean ) @@ -162,8 +163,8 @@ const vc = await VerifiableCredential.create({ ```kotlin title="Issuer.kt" val vc = VerifiableCredential.create( type = "SwiftiesFanClub", - issuer = fanClubIssuerDid.didDocument.id.toString(), - subject = aliceDid.didDocument.id.toString(), + issuer = fanClubIssuerDid.uri, + subject = aliceDid.uri, data = SwiftiesFanClub(level = "Stan", legit = true) ) ``` @@ -247,7 +248,7 @@ const signedVcJwt = await vc.sign({ did: fanClubIssuerDid }); ```kotlin title="Issuer.kt" -val signedVcJwt = vc.sign(fanClubIssuerDidObject) +val signedVcJwt = vc.sign(fanClubIssuerDid) ``` @@ -332,19 +333,28 @@ val presentationDefinition = PresentationDefinitionV2( ) ) ) + +val definitionValidation = PresentationExchange.validateDefinition(presentationDefinition) ``` - - - -A successful validation would result in: +:::note +A successful validation would result in + + ```js [ Checked { tag: 'root', status: 'info', message: 'ok' } ] ``` + + + This returns an undefined result, but if unsuccessful, it will throw an error. + + +::: + ### Satisfy Presentation Definition Once a presentation definition is presented to Alice, she'd want to make sure that the credentials she has satifies the requirements before submitting them. From ed2fb1acaf520f5ffe4c5ffbaabe5a954319439f Mon Sep 17 00:00:00 2001 From: Rizel Scarlett Date: Thu, 1 Feb 2024 16:59:10 -0500 Subject: [PATCH 11/31] shnip code snippets --- .../verifiable-credentials/fan-club-vc.mdx | 444 ++++++++++-------- site/src/components/language/Shnip.jsx | 28 +- 2 files changed, 255 insertions(+), 217 deletions(-) diff --git a/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx b/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx index 42b0bc70b..42a5982b7 100644 --- a/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx +++ b/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx @@ -19,38 +19,35 @@ In this tutorial, we'll learn how to use [verifiable credentials](/docs/web5/lea ## Setting the Stage Before we start issuing and verifying credentials, let's set up our environment by installing the [@web5/credentials](https://www.npmjs.com/package/@web5/credentials) and [@web5/dids](https://www.npmjs.com/package/@web5/dids) packages: - - - -```bash + - - - -**Configure Repositories** - -```kotlin + `, + language: 'JavaScript', + codeLanguage: 'bash', + }, + { + code: ` +// Configure repositories repositories { mavenCentral() maven("https://jitpack.io") maven("https://repo.danubetech.com/repository/maven-public/") } -``` - -**Configure Dependencies** - -```kotlin +// Configure dependencies dependencies { implementation("xyz.block:web5-credentials:0.10.0") implementation("xyz.block:web5-dids:0.10.0") } -``` - - + `, + language: 'Kotlin', + breakLineAt:[6] + } + ]} +/> ## The Cast @@ -70,71 +67,70 @@ This is because verifiable credentials use DIDs to identify issuers and holders. If you need to create DIDs, you can do so with the [@web5/dids](https://www.npmjs.com/package/@web5/dids) package: - - - -```js + - - - -```kotlin + `, + language: 'JavaScript', + breakLineAt: [1] + }, + { + code: ` import web5.sdk.crypto.InMemoryKeyManager import web5.sdk.dids.methods.key.DidKey - val fanClubIssuerDid = DidKey.create(InMemoryKeyManager()) val aliceDid = DidKey.create(InMemoryKeyManager()) -``` - - - + `, + language: 'Kotlin', + breakLineAt:[2] + } + ]} +/> ### Model Credential Now, let's create the **SwiftiesFanClub** credential. We'll first model it with a class with some basic properties, `level` and `legit`: - - - -```js title="Issuer.js" + - - - -```kotlin title="Issuer.kt" + `, + language: 'JavaScript', + breakLineAt: [1, 5], + title: 'Issuer.js' + }, + { + code: ` import web5.sdk.credentials.VerifiableCredential import web5.sdk.credentials.PresentationExchange - data class SwiftiesFanClub( // indicates the fan's dedication level val level: String, - // indicates if the fan is a genuine Swiftie val legit: Boolean ) -``` - - + `, + language: 'Kotlin', + breakLineAt:[2, 5], + title: 'Issuer.kt' + } + ]} +/> :::note Note that credentials can be customized to fit various needs and scenarios. In our example, we used `level` and `legit`, but you could add more properties like `memberSince`, `favoriteAlbum`, or any other relevant data that suits your use case. @@ -144,32 +140,34 @@ Note that credentials can be customized to fit various needs and scenarios. In o Next we can create the verifiable credential with an instance of the class: - - - -```js title="Issuer.js" + - - - -```kotlin title="Issuer.kt" + `, + language: 'JavaScript', + title: 'Issuer.js' + }, + { + code: ` val vc = VerifiableCredential.create( type = "SwiftiesFanClub", issuer = fanClubIssuerDid.uri, subject = aliceDid.uri, data = SwiftiesFanClub(level = "Stan", legit = true) ) -``` - - + `, + language: 'Kotlin', + title: 'Issuer.kt' + } + ]} +/> ### Credential Properties @@ -188,10 +186,10 @@ Let's break down the `VerifiableCredential.create()` method to understand what e `VerifiableCredential.create()` returns a VC as a JSON object: - - - -```js + - - - -```json + `, + language: 'JavaScript', + title: 'Issuer.js' + }, + { + code: ` { "@context": [ "https://www.w3.org/2018/credentials/v1" @@ -228,30 +225,37 @@ vcDataModel: { "legit": true } } -``` - - + `, + language: 'Kotlin', + codeLanguage: 'json' + } + ]} +/> + ### Sign Credential Last but not least, we must cryptographically sign the VC to make it official: - - - -```js title="Issuer.js" + - - - -```kotlin title="Issuer.kt" + `, + language: 'JavaScript', + title: 'Issuer.js' + }, + { + code: ` val signedVcJwt = vc.sign(fanClubIssuerDid) -``` - - + `, + language: 'Kotlin', + title: 'Issuer.kt' + } + ]} +/> + Signing the credential returns a [VC JSON Web Token](/docs/web5/build/verifiable-credentials/jwt-to-vc#what-is-a-jwt), ideal for secure transmission of the credential. @@ -276,12 +280,11 @@ A presentation exchange is the process where the holder of VCs presents them to To kick off the presentation exchange, the Swag Supplier (verifier) will send a request to Alice, which includes a presentation definition, specifying what credentials or claims are needed. Here's how the verifier can create the presentation definition, and validate that it is properly formed: - - - -```js title="Verifier.js" + - - - -```kotlin title="Verifier.kt" + `, + language: 'JavaScript', + title: 'Verifier.js', + breakLineAt: [1, 21] + }, + { + code: ` import web5.sdk.credentials.PresentationExchange import web5.sdk.credentials.VerifiableCredential import web5.sdk.credentials.model.* - val presentationDefinition = PresentationDefinitionV2( id = "presDefId123", name = "Swifties Fan Club Presentation Definition", @@ -333,27 +334,22 @@ val presentationDefinition = PresentationDefinitionV2( ) ) ) - val definitionValidation = PresentationExchange.validateDefinition(presentationDefinition) -``` - - + `, + language: 'Kotlin', + title: 'Verifier.kt', + breakLineAt: [3, 21] + } + ]} +/> -:::note -A successful validation would result in - - +For the **JavaScript SDK**, a successful validation would result in ```js [ Checked { tag: 'root', status: 'info', message: 'ok' } ] ``` + For the **Kotlin SDK**, this returns an undefined result, but if unsuccessful, it will throw an error. - - - This returns an undefined result, but if unsuccessful, it will throw an error. - - -::: ### Satisfy Presentation Definition @@ -361,10 +357,10 @@ Once a presentation definition is presented to Alice, she'd want to make sure th This can be done by passing the JWT(s) and the presentation definition to `satisfiesPresentationDefinition()` method. Typically this step is done by the app that Alice is using to store and present her credentials: - - - -```js title="Wallet.js" + - - - -```kotlin title="Wallet.kt" + `, + language: 'JavaScript', + title: 'Wallet.js' + }, + { + code: ` // Does VC Satisfy the Presentation Definition try { PresentationExchange.satisfiesPresentationDefinition(listOf(signedVcJwt), presentationDefinition) println("\nVC Satisfies Presentation Definition!\n") -} catch (e: Exception) { - println("VC does not satisfy Presentation Definition: ${e.message}") +} catch (err: Exception) { + println("VC does not satisfy Presentation Definition: " + err.message) } -``` - - + `, + language: 'Kotlin', + title: 'Issuer.kt' + } + ]} +/> ### Create Presentation Once Alice's app is confident that her credential satisfies the presentation definition, the presentation would be created: - - - - -```js title="Wallet.js" + - - - -```kt title="Wallet.kt" + `, + language: 'JavaScript', + title: 'Wallet.js' + }, + { + code: ` // Create Presentation Result that contains a Verifiable Presentation and Presentation Submission val presentationResult = PresentationExchange.createPresentationFromCredentials(listOf(signedSimpleVcJwt), presentationDefinition) -println("Presentation Result: ${presentationResult}") -``` - - +println("Presentation Result" + presentationResult) + `, + language: 'Kotlin', + title: 'Issuer.kt' + } + ]} +/> The result of the presentation: -```json + + ## Act 3: Verifying the Credential After receiving the credential, the verifier will want to verify it to ensure that it is valid and has not been tampered with. They can do this with `VerifiableCredential.verify()`. If verification is unsuccessful, an error will be thrown: - - - -```js title="Verifier.js" + - - -```kotlin title="Verifier.kt" + console.log('VC Verification failed: ' + err.message'); + `, + language: 'JavaScript', + title: 'Verifier.js' + }, + { + code: ` try { VerifiableCredential.verify(signedVcJwt) - println("\nVC Verification successful!\n") + println("VC Verification successful!") } catch (err: Exception) { - println("\nVC Verification failed: ${err.message}\n") + println("VC Verification failed:" + err.message) } -``` - - + `, + language: 'Kotlin', + title: 'Verifier.kt' + } + ]} +/> + ### Parse JWT into VC @@ -497,30 +523,32 @@ The signed VC JWT is a secure representation of the credential, ideal for transm However, the verifier will likely need to inspect or use the data within the credential. They can use `parseJwt()` to convert the JWT back into a `VerifiableCredential` object. - - - - -```js title="Verifier.js" + - - - -```kotlin title="Verifier.kt" + `, + language: 'JavaScript', + title: 'Verifier.js' + }, + { + code: ` val parsedJwt = VerifiableCredential.parseJwt(signedVcJwt) -``` - - + `, + language: 'Kotlin', + title: 'Verifier.kt' + } + ]} +/> -This returns: - - +This returns: -```js + - - -```json + `, + language: 'JavaScript', + title: 'Verifier.js' + }, + { + code: ` { "@context": [ "https://www.w3.org/2018/credentials/v1" @@ -556,9 +584,13 @@ vcDataModel: { "legit": true } } -``` + `, + language: 'Kotlin', + codeLanguage: 'json', + title: 'Verifier.kt' + } + ]} +/> - - Given Alice's verified credential, she's all set to receive her free merch for being a proud member of the Swifties Fan Club! \ No newline at end of file diff --git a/site/src/components/language/Shnip.jsx b/site/src/components/language/Shnip.jsx index f8f7a72e8..c54c298ea 100644 --- a/site/src/components/language/Shnip.jsx +++ b/site/src/components/language/Shnip.jsx @@ -6,20 +6,26 @@ import CodeBlock from '@theme/CodeBlock'; const Shnip = ({ snippets, inlineSnippets }) => { // support line breaks for inline code snippets - const addLineBreaks = (code, breakLines) => { - if (!breakLines || breakLines.length === 0) { - return code; +const addLineBreaks = (code, breakLines) => { + if (!breakLines || breakLines.length === 0) { + return code.trim(); + } + let lines = code.trim().split('\n'); + if (lines[0] === '') { + lines.shift(); + breakLines = breakLines.map((line) => line - 1); + } + breakLines.forEach((lineNumber) => { + let adjustedLineNumber = lineNumber - 1; + if (adjustedLineNumber >= 0 && adjustedLineNumber < lines.length) { + lines[adjustedLineNumber] += '\n'; } + }); + + return lines.join('\n'); +}; - const lines = code.split('\n'); - breakLines.forEach((lineNumber) => { - if (lineNumber < lines.length) { - lines[lineNumber] += '\n'; - } - }); - return lines.join('\n'); - }; return ( <> From 510c115c152e77bec935d5c72696da53995f9e24 Mon Sep 17 00:00:00 2001 From: Rizel Scarlett Date: Thu, 1 Feb 2024 17:51:16 -0500 Subject: [PATCH 12/31] note about undefined result --- .../verifiable-credentials/fan-club-vc.mdx | 21 +++++++++++++------ site/src/components/language/Shnip.jsx | 13 +++++++++--- 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx b/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx index 42a5982b7..869124ac2 100644 --- a/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx +++ b/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx @@ -343,12 +343,21 @@ val definitionValidation = PresentationExchange.validateDefinition(presentationD ]} /> -For the **JavaScript SDK**, a successful validation would result in - -```js -[ Checked { tag: 'root', status: 'info', message: 'ok' } ] -``` - For the **Kotlin SDK**, this returns an undefined result, but if unsuccessful, it will throw an error. +A successful validation would result in: + ### Satisfy Presentation Definition diff --git a/site/src/components/language/Shnip.jsx b/site/src/components/language/Shnip.jsx index c54c298ea..05138e838 100644 --- a/site/src/components/language/Shnip.jsx +++ b/site/src/components/language/Shnip.jsx @@ -4,7 +4,7 @@ import LanguageTabBar from '@site/src/components/language/LanguageTabBar'; import CodeSnippet from '@site/src/components/CodeSnippet'; import CodeBlock from '@theme/CodeBlock'; -const Shnip = ({ snippets, inlineSnippets }) => { +const Shnip = ({ snippets, inlineSnippets, inlineContent }) => { // support line breaks for inline code snippets const addLineBreaks = (code, breakLines) => { if (!breakLines || breakLines.length === 0) { @@ -44,8 +44,8 @@ const addLineBreaks = (code, breakLines) => { {inlineSnippets && inlineSnippets.map( - ({ code, language, codeLanguage, title, breakLineAt }) => ( -
+ ({ code, language, codeLanguage, title, breakLineAt }, index) => ( +
{
), )} + + {inlineContent && + inlineContent.map(({ content, language }, index) => ( +
+ {content} +
+ ))} ); From 20a46fd06f5a487f6c035c3cdb1c7e44d488ebee Mon Sep 17 00:00:00 2001 From: Rizel Scarlett Date: Thu, 1 Feb 2024 20:55:00 -0500 Subject: [PATCH 13/31] create did key shnip --- .../verifiable-credentials/fan-club-vc.mdx | 25 +++++++++---- .../fan-club-vc.test.js | 36 +++++++++++++++++++ 2 files changed, 54 insertions(+), 7 deletions(-) create mode 100644 site/testsuites/testsuite-javascript/__tests__/web5/build/verifiable-credentials/fan-club-vc.test.js diff --git a/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx b/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx index 869124ac2..cb9634e9f 100644 --- a/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx +++ b/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx @@ -3,9 +3,8 @@ title: VC Workflow hide_title: true sidebar_position: 10 --- -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; +import createDidKeys from '!!raw-loader!@site/snippets/testsuite-javascript/__tests__/web5/build/verifiable-credentials/createDidKeys.snippet.js' @@ -49,7 +48,6 @@ dependencies { ]} /> - ## The Cast There are a few characters involved in our story: @@ -69,18 +67,31 @@ If you need to create DIDs, you can do so with the [@web5/dids](https://www.npmj + + + { + beforeAll(async () => { + await setUpWeb5(); + web5 = globalThis.web5; + did = globalThis.did; + + vi.mock('@web5/api', () => { + return { + Web5: { + connect: vi.fn(() => { + return { + web5, + did, + }; + }), + }, + }; + }); + }); + + test('createDidKeys creates an issuer DID and alice DID with did:key method', async () => { + // :snippet-start: createDidKeys + const fanClubIssuerDid = await DidKeyMethod.create(); + const aliceDid = await DidKeyMethod.create(); + // :snippet-end: + + expect(aliceDid.did).toMatch(/^did:key:/); + expect(fanClubIssuerDid.did).toMatch(/^did:key:/); + }); +}); From 4c4f16ed2a33aa5c2679900a28cd4ad86d9b26b2 Mon Sep 17 00:00:00 2001 From: Rizel Scarlett Date: Thu, 1 Feb 2024 22:22:16 -0500 Subject: [PATCH 14/31] more js code shnips --- .../verifiable-credentials/fan-club-vc.mdx | 61 +++--- site/src/components/CodeSnippet.jsx | 3 +- .../fan-club-vc.test.js | 193 ++++++++++++++++-- 3 files changed, 207 insertions(+), 50 deletions(-) diff --git a/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx b/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx index cb9634e9f..45988068f 100644 --- a/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx +++ b/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx @@ -5,6 +5,9 @@ sidebar_position: 10 --- import createDidKeys from '!!raw-loader!@site/snippets/testsuite-javascript/__tests__/web5/build/verifiable-credentials/createDidKeys.snippet.js' +import createSwiftieFanClubClass from '!!raw-loader!@site/snippets/testsuite-javascript/__tests__/web5/build/verifiable-credentials/createSwiftieFanClubClass.snippet.js' +import createVerifiableCredential from '!!raw-loader!@site/snippets/testsuite-javascript/__tests__/web5/build/verifiable-credentials/createVerifiableCredential.snippet.js' +import signVC from '!!raw-loader!@site/snippets/testsuite-javascript/__tests__/web5/build/verifiable-credentials/signVC.snippet.js' @@ -91,13 +94,10 @@ import web5.sdk.dids.methods.key.DidKey inlineSnippets={[ { code: ` -import web5.sdk.crypto.InMemoryKeyManager -import web5.sdk.dids.methods.key.DidKey val fanClubIssuerDid = DidKey.create(InMemoryKeyManager()) val aliceDid = DidKey.create(InMemoryKeyManager()) `, language: 'Kotlin', - breakLineAt:[2] } ]} /> @@ -106,29 +106,33 @@ val aliceDid = DidKey.create(InMemoryKeyManager()) Now, let's create the **SwiftiesFanClub** credential. We'll first model it with a class with some basic properties, `level` and `legit`: - + + { let finalSnippet; @@ -27,7 +28,7 @@ const CodeSnippet = ({ finalSnippet = snippet; } - return {finalSnippet}; + return {finalSnippet}; }; export default CodeSnippet; diff --git a/site/testsuites/testsuite-javascript/__tests__/web5/build/verifiable-credentials/fan-club-vc.test.js b/site/testsuites/testsuite-javascript/__tests__/web5/build/verifiable-credentials/fan-club-vc.test.js index 4ee11ec07..1ca96c56e 100644 --- a/site/testsuites/testsuite-javascript/__tests__/web5/build/verifiable-credentials/fan-club-vc.test.js +++ b/site/testsuites/testsuite-javascript/__tests__/web5/build/verifiable-credentials/fan-club-vc.test.js @@ -1,27 +1,150 @@ +// import { test, expect, vi, describe, beforeAll } from 'vitest'; +// import { DidKeyMethod } from '@web5/dids'; +// import { VerifiableCredential } from '@web5/credentials'; +// import { setUpWeb5 } from '../../../setup-web5'; + +// let web5; + +// describe('fan-club-vc', () => { +// beforeAll(async () => { +// await setUpWeb5(); +// web5 = globalThis.web5; +// did = globalThis.did; + +// vi.mock('@web5/api', () => { +// return { +// Web5: { +// connect: vi.fn(() => { +// return { +// web5, +// did, +// }; +// }), +// }, +// }; +// }); +// }); + +// test('createDidKeys creates an issuer DID and alice DID with did:key method', async () => { +// // :snippet-start: createDidKeys +// const fanClubIssuerDid = await DidKeyMethod.create(); +// const aliceDid = await DidKeyMethod.create(); +// // :snippet-end: + +// expect(aliceDid.did).toMatch(/^did:key:/); +// expect(fanClubIssuerDid.did).toMatch(/^did:key:/); +// }); + +// test('createSwiftieFanClubClass creates a class for a vc', async () => { +// // :snippet-start: createSwiftieFanClubClass +// class SwiftiesFanClub { +// constructor(level, legit) { +// // indicates the fan's dedication level +// this.level = level; + +// // indicates if the fan is a genuine Swiftie +// this.legit = legit; +// } +// } +// // :snippet-end: +// const fan = new SwiftiesFanClub('High', true); +// expect(fan.legit).toBe(true); +// expect(fan.level).toBe('High'); +// }); + +// test('createVerifiableCredential creates a vc', async () => { +// const fanClubIssuerDid = await DidKeyMethod.create(); +// const aliceDid = await DidKeyMethod.create(); + +// class SwiftiesFanClub { +// constructor(level, legit) { +// // indicates the fan's dedication level +// this.level = level; + +// // indicates if the fan is a genuine Swiftie +// this.legit = legit; +// } +// } +// // :snippet-start: createVerifiableCredential +// const vc = await VerifiableCredential.create({ +// type: 'SwiftiesFanClub', +// issuer: fanClubIssuerDid.did, +// subject: aliceDid.did, +// data: new SwiftiesFanClub('Stan', true) +// }); +// // :snippet-end: +// expect(vc).toHaveProperty('vcDataModel'); +// expect(vc.vcDataModel).toHaveProperty('@context'); +// expect(vc.vcDataModel).toHaveProperty('type'); +// expect(vc.vcDataModel).toHaveProperty('id'); +// expect(vc.vcDataModel).toHaveProperty('issuer'); +// expect(vc.vcDataModel).toHaveProperty('issuanceDate'); +// expect(vc.vcDataModel).toHaveProperty('credentialSubject'); +// expect(vc.vcDataModel.credentialSubject).toHaveProperty('id'); +// expect(vc.vcDataModel.credentialSubject).toHaveProperty('level'); +// expect(vc.vcDataModel.credentialSubject).toHaveProperty('legit'); +// }); + +// test('signVC creates a vc', async () => { +// const fanClubIssuerDid = await DidKeyMethod.create(); +// const aliceDid = await DidKeyMethod.create(); + +// class SwiftiesFanClub { +// constructor(level, legit) { +// // indicates the fan's dedication level +// this.level = level; + +// // indicates if the fan is a genuine Swiftie +// this.legit = legit; +// } +// } +// const vc = await VerifiableCredential.create({ +// type: 'SwiftiesFanClub', +// issuer: fanClubIssuerDid.did, +// subject: aliceDid.did, +// data: new SwiftiesFanClub('Stan', true) +// }); +// // :snippet-start: signVC +// const signedVcJwt = await vc.sign({ did: fanClubIssuerDid }); +// // :snippet-end: +// expect(typeof signedVcJwt).toBe('string'); +// expect(signedVcJwt).not.toBe(''); +// }); +// }); import { test, expect, vi, describe, beforeAll } from 'vitest'; import { DidKeyMethod } from '@web5/dids'; +import { VerifiableCredential } from '@web5/credentials'; import { setUpWeb5 } from '../../../setup-web5'; -let web5; - describe('fan-club-vc', () => { + let web5, did, fanClubIssuerDid, aliceDid, SwiftiesFanClub, vc; + beforeAll(async () => { await setUpWeb5(); web5 = globalThis.web5; did = globalThis.did; - vi.mock('@web5/api', () => { - return { - Web5: { - connect: vi.fn(() => { - return { - web5, - did, - }; - }), - }, - }; + fanClubIssuerDid = await DidKeyMethod.create(); + aliceDid = await DidKeyMethod.create(); + + SwiftiesFanClub = class { + constructor(level, legit) { + this.level = level; + this.legit = legit; + } + }; + vc = await VerifiableCredential.create({ + type: 'SwiftiesFanClub', + issuer: fanClubIssuerDid.did, + subject: aliceDid.did, + data: new SwiftiesFanClub('Stan', true) }); + + vi.mock('@web5/api', () => ({ + Web5: { + connect: vi.fn(() => ({ web5, did })), + }, + })); }); test('createDidKeys creates an issuer DID and alice DID with did:key method', async () => { @@ -29,8 +152,50 @@ describe('fan-club-vc', () => { const fanClubIssuerDid = await DidKeyMethod.create(); const aliceDid = await DidKeyMethod.create(); // :snippet-end: - expect(aliceDid.did).toMatch(/^did:key:/); expect(fanClubIssuerDid.did).toMatch(/^did:key:/); }); + + test('createSwiftieFanClubClass creates a class for a vc', async () => { + // :snippet-start: createSwiftieFanClubClass + class SwiftiesFanClub { + constructor(level, legit) { + this.level = level; + this.legit = legit; + } + } + // :snippet-end: + const fan = new SwiftiesFanClub('High', true); + expect(fan.legit).toBe(true); + expect(fan.level).toBe('High'); + }); + + test('createVerifiableCredential creates a vc', async () => { + // :snippet-start: createVerifiableCredential + const vc = await VerifiableCredential.create({ + type: 'SwiftiesFanClub', + issuer: fanClubIssuerDid.did, + subject: aliceDid.did, + data: new SwiftiesFanClub('Stan', true) + }); + // :snippet-end: + expect(vc).toHaveProperty('vcDataModel'); + expect(vc.vcDataModel).toHaveProperty('@context'); + expect(vc.vcDataModel).toHaveProperty('type'); + expect(vc.vcDataModel).toHaveProperty('id'); + expect(vc.vcDataModel).toHaveProperty('issuer'); + expect(vc.vcDataModel).toHaveProperty('issuanceDate'); + expect(vc.vcDataModel).toHaveProperty('credentialSubject'); + expect(vc.vcDataModel.credentialSubject).toHaveProperty('id'); + expect(vc.vcDataModel.credentialSubject).toHaveProperty('level'); + expect(vc.vcDataModel.credentialSubject).toHaveProperty('legit'); + }); + + test('signVC creates a vc', async () => { + // :snippet-start: signVC + const signedVcJwt = await vc.sign({ did: fanClubIssuerDid }); + // :snippet-end: + expect(typeof signedVcJwt).toBe('string'); + expect(signedVcJwt).not.toBe(''); + }); }); From e1a9863cba07885f6c0a95aa514e6d7e88812ab2 Mon Sep 17 00:00:00 2001 From: Rizel Scarlett Date: Fri, 2 Feb 2024 10:48:05 -0500 Subject: [PATCH 15/31] all js shnips are tested --- .../verifiable-credentials/fan-club-vc.mdx | 97 +++---- .../fan-club-vc.test.js | 241 +++++++++--------- 2 files changed, 149 insertions(+), 189 deletions(-) diff --git a/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx b/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx index 45988068f..120aa1d7a 100644 --- a/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx +++ b/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx @@ -8,6 +8,11 @@ import createDidKeys from '!!raw-loader!@site/snippets/testsuite-javascript/__te import createSwiftieFanClubClass from '!!raw-loader!@site/snippets/testsuite-javascript/__tests__/web5/build/verifiable-credentials/createSwiftieFanClubClass.snippet.js' import createVerifiableCredential from '!!raw-loader!@site/snippets/testsuite-javascript/__tests__/web5/build/verifiable-credentials/createVerifiableCredential.snippet.js' import signVC from '!!raw-loader!@site/snippets/testsuite-javascript/__tests__/web5/build/verifiable-credentials/signVC.snippet.js' +import createPresentationDefinition from '!!raw-loader!@site/snippets/testsuite-javascript/__tests__/web5/build/verifiable-credentials/createPresentationDefinition.snippet.js' +import satisfiesDefinition from '!!raw-loader!@site/snippets/testsuite-javascript/__tests__/web5/build/verifiable-credentials/satisfiesDefinition.snippet.js' +import createPresentationFromCredentials from '!!raw-loader!@site/snippets/testsuite-javascript/__tests__/web5/build/verifiable-credentials/createPresentationFromCredentials.snippet.js' +import verifyVC from '!!raw-loader!@site/snippets/testsuite-javascript/__tests__/web5/build/verifiable-credentials/verifyVC.snippet.js' +import parseSignedVcJwt from '!!raw-loader!@site/snippets/testsuite-javascript/__tests__/web5/build/verifiable-credentials/parseSignedVcJwt.snippet.js' @@ -287,37 +292,29 @@ Here's how the verifier can create the presentation definition, and validate tha { code: ` import { VerifiableCredential, PresentationExchange } from "@web5/credentials"; -const presentationDefinition = { - 'id' : 'presDefId123', - 'name' : 'Swifties Fan Club Presentation Definition', - 'purpose' : 'for proving membership in the fan club', - 'input_descriptors' : [ - { - 'id' : 'legitness', - 'purpose' : 'are you legit or not?', - 'constraints' : { - 'fields': [ - { - 'path': [ - '$.credentialSubject.legit', - ] - } - ] - } - } - ] -}; -const definitionValidation = PresentationExchange.validateDefinition({ presentationDefinition }); `, language: 'JavaScript', title: 'Verifier.js', - breakLineAt: [1, 21] }, { code: ` import web5.sdk.credentials.PresentationExchange import web5.sdk.credentials.VerifiableCredential import web5.sdk.credentials.model.* + `, + language: 'Kotlin', + title: 'Verifier.kt', + } + ]} +/> + + @@ -369,26 +366,16 @@ This can be done by passing the JWT(s) and the presentation definition to `satis Typically this step is done by the app that Alice is using to store and present her credentials: { -// beforeAll(async () => { -// await setUpWeb5(); -// web5 = globalThis.web5; -// did = globalThis.did; - -// vi.mock('@web5/api', () => { -// return { -// Web5: { -// connect: vi.fn(() => { -// return { -// web5, -// did, -// }; -// }), -// }, -// }; -// }); -// }); - -// test('createDidKeys creates an issuer DID and alice DID with did:key method', async () => { -// // :snippet-start: createDidKeys -// const fanClubIssuerDid = await DidKeyMethod.create(); -// const aliceDid = await DidKeyMethod.create(); -// // :snippet-end: - -// expect(aliceDid.did).toMatch(/^did:key:/); -// expect(fanClubIssuerDid.did).toMatch(/^did:key:/); -// }); - -// test('createSwiftieFanClubClass creates a class for a vc', async () => { -// // :snippet-start: createSwiftieFanClubClass -// class SwiftiesFanClub { -// constructor(level, legit) { -// // indicates the fan's dedication level -// this.level = level; - -// // indicates if the fan is a genuine Swiftie -// this.legit = legit; -// } -// } -// // :snippet-end: -// const fan = new SwiftiesFanClub('High', true); -// expect(fan.legit).toBe(true); -// expect(fan.level).toBe('High'); -// }); - -// test('createVerifiableCredential creates a vc', async () => { -// const fanClubIssuerDid = await DidKeyMethod.create(); -// const aliceDid = await DidKeyMethod.create(); - -// class SwiftiesFanClub { -// constructor(level, legit) { -// // indicates the fan's dedication level -// this.level = level; - -// // indicates if the fan is a genuine Swiftie -// this.legit = legit; -// } -// } -// // :snippet-start: createVerifiableCredential -// const vc = await VerifiableCredential.create({ -// type: 'SwiftiesFanClub', -// issuer: fanClubIssuerDid.did, -// subject: aliceDid.did, -// data: new SwiftiesFanClub('Stan', true) -// }); -// // :snippet-end: -// expect(vc).toHaveProperty('vcDataModel'); -// expect(vc.vcDataModel).toHaveProperty('@context'); -// expect(vc.vcDataModel).toHaveProperty('type'); -// expect(vc.vcDataModel).toHaveProperty('id'); -// expect(vc.vcDataModel).toHaveProperty('issuer'); -// expect(vc.vcDataModel).toHaveProperty('issuanceDate'); -// expect(vc.vcDataModel).toHaveProperty('credentialSubject'); -// expect(vc.vcDataModel.credentialSubject).toHaveProperty('id'); -// expect(vc.vcDataModel.credentialSubject).toHaveProperty('level'); -// expect(vc.vcDataModel.credentialSubject).toHaveProperty('legit'); -// }); - -// test('signVC creates a vc', async () => { -// const fanClubIssuerDid = await DidKeyMethod.create(); -// const aliceDid = await DidKeyMethod.create(); - -// class SwiftiesFanClub { -// constructor(level, legit) { -// // indicates the fan's dedication level -// this.level = level; - -// // indicates if the fan is a genuine Swiftie -// this.legit = legit; -// } -// } -// const vc = await VerifiableCredential.create({ -// type: 'SwiftiesFanClub', -// issuer: fanClubIssuerDid.did, -// subject: aliceDid.did, -// data: new SwiftiesFanClub('Stan', true) -// }); -// // :snippet-start: signVC -// const signedVcJwt = await vc.sign({ did: fanClubIssuerDid }); -// // :snippet-end: -// expect(typeof signedVcJwt).toBe('string'); -// expect(signedVcJwt).not.toBe(''); -// }); -// }); import { test, expect, vi, describe, beforeAll } from 'vitest'; import { DidKeyMethod } from '@web5/dids'; -import { VerifiableCredential } from '@web5/credentials'; +import { VerifiableCredential, PresentationExchange } from '@web5/credentials'; import { setUpWeb5 } from '../../../setup-web5'; describe('fan-club-vc', () => { - let web5, did, fanClubIssuerDid, aliceDid, SwiftiesFanClub, vc; + let web5, did, fanClubIssuerDid, aliceDid, SwiftiesFanClub, vc, signedVcJwt, presentationDefinition; beforeAll(async () => { await setUpWeb5(); @@ -133,6 +20,7 @@ describe('fan-club-vc', () => { this.legit = legit; } }; + vc = await VerifiableCredential.create({ type: 'SwiftiesFanClub', issuer: fanClubIssuerDid.did, @@ -140,6 +28,29 @@ describe('fan-club-vc', () => { data: new SwiftiesFanClub('Stan', true) }); + signedVcJwt = await vc.sign({ did: fanClubIssuerDid }); + + presentationDefinition = { + 'id': 'presDefId123', + 'name': 'Swifties Fan Club Presentation Definition', + 'purpose': 'for proving membership in the fan club', + 'input_descriptors': [ + { + 'id': 'legitness', + 'purpose': 'are you legit or not?', + 'constraints': { + 'fields': [ + { + 'path': [ + '$.credentialSubject.legit', + ] + } + ] + } + } + ] + }; + vi.mock('@web5/api', () => ({ Web5: { connect: vi.fn(() => ({ web5, did })), @@ -165,9 +76,9 @@ describe('fan-club-vc', () => { } } // :snippet-end: - const fan = new SwiftiesFanClub('High', true); + const fan = new SwiftiesFanClub('Stan', true); expect(fan.legit).toBe(true); - expect(fan.level).toBe('High'); + expect(fan.level).toBe('Stan'); }); test('createVerifiableCredential creates a vc', async () => { @@ -180,15 +91,9 @@ describe('fan-club-vc', () => { }); // :snippet-end: expect(vc).toHaveProperty('vcDataModel'); - expect(vc.vcDataModel).toHaveProperty('@context'); - expect(vc.vcDataModel).toHaveProperty('type'); - expect(vc.vcDataModel).toHaveProperty('id'); - expect(vc.vcDataModel).toHaveProperty('issuer'); - expect(vc.vcDataModel).toHaveProperty('issuanceDate'); expect(vc.vcDataModel).toHaveProperty('credentialSubject'); - expect(vc.vcDataModel.credentialSubject).toHaveProperty('id'); - expect(vc.vcDataModel.credentialSubject).toHaveProperty('level'); - expect(vc.vcDataModel.credentialSubject).toHaveProperty('legit'); + expect(vc.vcDataModel.credentialSubject.level).toBe('Stan'); + expect(vc.vcDataModel.credentialSubject.legit).toBe(true); }); test('signVC creates a vc', async () => { @@ -198,4 +103,90 @@ describe('fan-club-vc', () => { expect(typeof signedVcJwt).toBe('string'); expect(signedVcJwt).not.toBe(''); }); + + test('createPresentationDefinition creates a presentation definition', async () => { + // :snippet-start: createPresentationDefinition + const presentationDefinition = { + 'id': 'presDefId123', + 'name': 'Swifties Fan Club Presentation Definition', + 'purpose': 'for proving membership in the fan club', + 'input_descriptors': [ + { + 'id': 'legitness', + 'purpose': 'are you legit or not?', + 'constraints': { + 'fields': [ + { + 'path': [ + '$.credentialSubject.legit', + ] + } + ] + } + } + ] + }; + + const definitionValidation = PresentationExchange.validateDefinition({ presentationDefinition }); + // :snippet-end: + expect(definitionValidation).toHaveLength(1); + expect(definitionValidation[0]).toHaveProperty('message', 'ok'); + expect(definitionValidation[0]).toHaveProperty('status', 'info'); + expect(definitionValidation[0]).toHaveProperty('tag', 'root'); + }) + + test('satisfiesDefinition checks if VC satisfies the presentation definition', async () => { + const logSpy = vi.spyOn(console, 'log'); + // :snippet-start: satisfiesDefinition + // Does VC Satisfy the Presentation Definition + try { + PresentationExchange.satisfiesPresentationDefinition({ vcJwts: [signedVcJwt], presentationDefinition: presentationDefinition }); + console.log('VC Satisfies Presentation Definition!'); + } catch (err) { + console.log('VC does not satisfy Presentation Definition: ' + err.message); + } + // :snippet-end: + expect(logSpy).toHaveBeenCalledWith('VC Satisfies Presentation Definition!'); + logSpy.mockRestore(); + }); + + test('createPresentationFromCredentials creates presentation from credentials and checks the presentation result', async () => { + // :snippet-start: createPresentationFromCredentials + // Create Presentation Result that contains a Verifiable Presentation and Presentation Submission + const presentationResult = PresentationExchange.createPresentationFromCredentials({ vcJwts: [signedVcJwt], presentationDefinition: presentationDefinition }); + console.log('\nPresentation Result: ' + JSON.stringify(presentationResult)); + // :snippet-end: + + expect(presentationResult.presentation).toHaveProperty('@context'); + expect(presentationResult.presentation).toHaveProperty('type'); + expect(presentationResult.presentation).toHaveProperty('presentation_submission'); + expect(presentationResult).toHaveProperty('presentationSubmissionLocation'); + expect(presentationResult).toHaveProperty('presentationSubmission'); + }); + test('verify VC checks if VC verification is successful', async () => { + // :snippet-start: verifyVC + let result + + try { + result = await VerifiableCredential.verify({ vcJwt: signedVcJwt }); + console.log('VC Verification Successful!'); + } catch (err) { + console.log('VC Verification failed:' + err.message); + } + // :snippet-end: + expect(result).toHaveProperty('vc'); + expect(result.vc).toHaveProperty('credentialSubject'); + expect(result.vc.credentialSubject.level).toBe('Stan'); + expect(result.vc.credentialSubject.legit).toBe(true); + }); + + test('parseSignedVcJwt parses the signed VC JWT', async () => { + // :snippet-start: parseSignedVcJwt + const vc = VerifiableCredential.parseJwt({ vcJwt: signedVcJwt }); + // :snippet-end: + expect(vc).toHaveProperty('vcDataModel'); + expect(vc.vcDataModel).toHaveProperty('credentialSubject'); + expect(vc.vcDataModel.credentialSubject.level).toBe('Stan'); + expect(vc.vcDataModel.credentialSubject.legit).toBe(true); + }); }); From e87b251e1a9857a0be9c3e3e8f8aeb490b3fe509 Mon Sep 17 00:00:00 2001 From: Rizel Scarlett Date: Sun, 4 Feb 2024 12:09:23 -0500 Subject: [PATCH 16/31] kotlin shnips complete --- .../verifiable-credentials/fan-club-vc.mdx | 211 ++++++------------ .../fan-club-vc.test.js | 111 +++------ site/testsuites/testsuite-kotlin/pom.xml | 10 + .../verifiablecredentials/FanClubVcTest.kt | 134 +++++++++++ 4 files changed, 242 insertions(+), 224 deletions(-) create mode 100644 site/testsuites/testsuite-kotlin/src/test/kotlin/docs/web5/build/verifiablecredentials/FanClubVcTest.kt diff --git a/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx b/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx index 120aa1d7a..9aa97b31d 100644 --- a/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx +++ b/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx @@ -4,15 +4,19 @@ hide_title: true sidebar_position: 10 --- -import createDidKeys from '!!raw-loader!@site/snippets/testsuite-javascript/__tests__/web5/build/verifiable-credentials/createDidKeys.snippet.js' -import createSwiftieFanClubClass from '!!raw-loader!@site/snippets/testsuite-javascript/__tests__/web5/build/verifiable-credentials/createSwiftieFanClubClass.snippet.js' -import createVerifiableCredential from '!!raw-loader!@site/snippets/testsuite-javascript/__tests__/web5/build/verifiable-credentials/createVerifiableCredential.snippet.js' -import signVC from '!!raw-loader!@site/snippets/testsuite-javascript/__tests__/web5/build/verifiable-credentials/signVC.snippet.js' -import createPresentationDefinition from '!!raw-loader!@site/snippets/testsuite-javascript/__tests__/web5/build/verifiable-credentials/createPresentationDefinition.snippet.js' -import satisfiesDefinition from '!!raw-loader!@site/snippets/testsuite-javascript/__tests__/web5/build/verifiable-credentials/satisfiesDefinition.snippet.js' -import createPresentationFromCredentials from '!!raw-loader!@site/snippets/testsuite-javascript/__tests__/web5/build/verifiable-credentials/createPresentationFromCredentials.snippet.js' -import verifyVC from '!!raw-loader!@site/snippets/testsuite-javascript/__tests__/web5/build/verifiable-credentials/verifyVC.snippet.js' -import parseSignedVcJwt from '!!raw-loader!@site/snippets/testsuite-javascript/__tests__/web5/build/verifiable-credentials/parseSignedVcJwt.snippet.js' +import createFanClubVc from '!!raw-loader!@site/snippets/testsuite-javascript/__tests__/web5/build/verifiable-credentials/createFanClubVc.snippet.js' +import signFanClubVc from '!!raw-loader!@site/snippets/testsuite-javascript/__tests__/web5/build/verifiable-credentials/signFanClubVc.snippet.js' +import satisfiesPresentationDefinitionFanClubVc from '!!raw-loader!@site/snippets/testsuite-javascript/__tests__/web5/build/verifiable-credentials/satisfiesPresentationDefinitionFanClubVc.snippet.js' +import createPresentationFromCredentialsFanClubVc from '!!raw-loader!@site/snippets/testsuite-javascript/__tests__/web5/build/verifiable-credentials/createPresentationFromCredentialsFanClubVc.snippet.js' +import verifyFanClubVc from '!!raw-loader!@site/snippets/testsuite-javascript/__tests__/web5/build/verifiable-credentials/verifyFanClubVc.snippet.js' +import parseFanClubJwt from '!!raw-loader!@site/snippets/testsuite-javascript/__tests__/web5/build/verifiable-credentials/parseFanClubJwt.snippet.js' + +import createFanClubVcKt from '!!raw-loader!@site/snippets/testsuite-kotlin/src/test/kotlin/docs/web5/build/verifiablecredentials/createFanClubVcKt.snippet.kt' +import signFanClubVcKt from '!!raw-loader!@site/snippets/testsuite-kotlin/src/test/kotlin/docs/web5/build/verifiablecredentials/signFanClubVcKt.snippet.kt' +import satisfiesPresentationDefinitionFanClubVcKt from '!!raw-loader!@site/snippets/testsuite-kotlin/src/test/kotlin/docs/web5/build/verifiablecredentials/satisfiesPresentationDefinitionFanClubVcKt.snippet.kt' +import createPresentationFromCredentialsFanClubVcKt from '!!raw-loader!@site/snippets/testsuite-kotlin/src/test/kotlin/docs/web5/build/verifiablecredentials/createPresentationFromCredentialsFanClubVcKt.snippet.kt' +import verifyFanClubVcKt from '!!raw-loader!@site/snippets/testsuite-kotlin/src/test/kotlin/docs/web5/build/verifiablecredentials/verifyFanClubVcKt.snippet.kt' +import parseFanClubJwtKt from '!!raw-loader!@site/snippets/testsuite-kotlin/src/test/kotlin/docs/web5/build/verifiablecredentials/parseFanClubJwtKt.snippet.kt' @@ -24,7 +28,7 @@ In this tutorial, we'll learn how to use [verifiable credentials](/docs/web5/lea ![Fan Club Membership](/img/vc-fanclub.png) ## Setting the Stage -Before we start issuing and verifying credentials, let's set up our environment by installing the [@web5/credentials](https://www.npmjs.com/package/@web5/credentials) and [@web5/dids](https://www.npmjs.com/package/@web5/dids) packages: +Before we start issuing and verifying credentials, let's set up our environment by installing the and packages: - - - @@ -111,33 +105,29 @@ val aliceDid = DidKey.create(InMemoryKeyManager()) Now, let's create the **SwiftiesFanClub** credential. We'll first model it with a class with some basic properties, `level` and `legit`: + - - ### Credential Properties @@ -215,7 +192,6 @@ vcDataModel: { } `, language: 'JavaScript', - title: 'Issuer.js' }, { code: ` @@ -250,17 +226,9 @@ Last but not least, we must cryptographically sign the VC to make it official: @@ -289,32 +257,40 @@ Here's how the verifier can create the presentation definition, and validate tha - - @@ -367,23 +343,9 @@ Typically this step is done by the app that Alice is using to store and present ### Create Presentation @@ -392,19 +354,9 @@ Once Alice's app is confident that her credential satisfies the presentation def The result of the presentation: @@ -481,22 +433,9 @@ They can do this with `VerifiableCredential.verify()`. If verification is unsucc @@ -509,17 +448,9 @@ They can use `parseJwt()` to convert the JWT back into a `VerifiableCredential` diff --git a/site/testsuites/testsuite-javascript/__tests__/web5/build/verifiable-credentials/fan-club-vc.test.js b/site/testsuites/testsuite-javascript/__tests__/web5/build/verifiable-credentials/fan-club-vc.test.js index 1caa165ea..6b3b7c872 100644 --- a/site/testsuites/testsuite-javascript/__tests__/web5/build/verifiable-credentials/fan-club-vc.test.js +++ b/site/testsuites/testsuite-javascript/__tests__/web5/build/verifiable-credentials/fan-club-vc.test.js @@ -57,32 +57,8 @@ describe('fan-club-vc', () => { }, })); }); - - test('createDidKeys creates an issuer DID and alice DID with did:key method', async () => { - // :snippet-start: createDidKeys - const fanClubIssuerDid = await DidKeyMethod.create(); - const aliceDid = await DidKeyMethod.create(); - // :snippet-end: - expect(aliceDid.did).toMatch(/^did:key:/); - expect(fanClubIssuerDid.did).toMatch(/^did:key:/); - }); - - test('createSwiftieFanClubClass creates a class for a vc', async () => { - // :snippet-start: createSwiftieFanClubClass - class SwiftiesFanClub { - constructor(level, legit) { - this.level = level; - this.legit = legit; - } - } - // :snippet-end: - const fan = new SwiftiesFanClub('Stan', true); - expect(fan.legit).toBe(true); - expect(fan.level).toBe('Stan'); - }); - - test('createVerifiableCredential creates a vc', async () => { - // :snippet-start: createVerifiableCredential + test('createFanClubVc creates a vc for fan club', async () => { + // :snippet-start: createFanClubVc const vc = await VerifiableCredential.create({ type: 'SwiftiesFanClub', issuer: fanClubIssuerDid.did, @@ -96,97 +72,64 @@ describe('fan-club-vc', () => { expect(vc.vcDataModel.credentialSubject.legit).toBe(true); }); - test('signVC creates a vc', async () => { - // :snippet-start: signVC + test('signFanClubVc signs a vc for fan club and returns jwt', async () => { + // :snippet-start: signFanClubVc const signedVcJwt = await vc.sign({ did: fanClubIssuerDid }); // :snippet-end: expect(typeof signedVcJwt).toBe('string'); expect(signedVcJwt).not.toBe(''); }); - test('createPresentationDefinition creates a presentation definition', async () => { - // :snippet-start: createPresentationDefinition - const presentationDefinition = { - 'id': 'presDefId123', - 'name': 'Swifties Fan Club Presentation Definition', - 'purpose': 'for proving membership in the fan club', - 'input_descriptors': [ - { - 'id': 'legitness', - 'purpose': 'are you legit or not?', - 'constraints': { - 'fields': [ - { - 'path': [ - '$.credentialSubject.legit', - ] - } - ] - } - } - ] - }; - - const definitionValidation = PresentationExchange.validateDefinition({ presentationDefinition }); - // :snippet-end: - expect(definitionValidation).toHaveLength(1); - expect(definitionValidation[0]).toHaveProperty('message', 'ok'); - expect(definitionValidation[0]).toHaveProperty('status', 'info'); - expect(definitionValidation[0]).toHaveProperty('tag', 'root'); - }) - - test('satisfiesDefinition checks if VC satisfies the presentation definition', async () => { + test('satisfiesPresentationDefinitionFanClubVc checks if VC satisfies the presentation definition', async () => { const logSpy = vi.spyOn(console, 'log'); - // :snippet-start: satisfiesDefinition + // :snippet-start: satisfiesPresentationDefinitionFanClubVc // Does VC Satisfy the Presentation Definition try { PresentationExchange.satisfiesPresentationDefinition({ vcJwts: [signedVcJwt], presentationDefinition: presentationDefinition }); - console.log('VC Satisfies Presentation Definition!'); + console.log('\nVC Satisfies Presentation Definition!\n'); } catch (err) { console.log('VC does not satisfy Presentation Definition: ' + err.message); } // :snippet-end: - expect(logSpy).toHaveBeenCalledWith('VC Satisfies Presentation Definition!'); + expect(logSpy).toHaveBeenCalledWith('\nVC Satisfies Presentation Definition!\n'); logSpy.mockRestore(); }); - test('createPresentationFromCredentials creates presentation from credentials and checks the presentation result', async () => { - // :snippet-start: createPresentationFromCredentials + test('createPresentationFromCredentialsFanClubVc creates presentation from credentials and checks the presentation result', async () => { + // :snippet-start: createPresentationFromCredentialsFanClubVc // Create Presentation Result that contains a Verifiable Presentation and Presentation Submission const presentationResult = PresentationExchange.createPresentationFromCredentials({ vcJwts: [signedVcJwt], presentationDefinition: presentationDefinition }); console.log('\nPresentation Result: ' + JSON.stringify(presentationResult)); // :snippet-end: - + expect(presentationResult.presentation).toHaveProperty('@context'); expect(presentationResult.presentation).toHaveProperty('type'); expect(presentationResult.presentation).toHaveProperty('presentation_submission'); expect(presentationResult).toHaveProperty('presentationSubmissionLocation'); expect(presentationResult).toHaveProperty('presentationSubmission'); }); - test('verify VC checks if VC verification is successful', async () => { - // :snippet-start: verifyVC - let result - + test('verifyFanClubVc checks if VC verification is successful', async () => { + const logSpy = vi.spyOn(console, 'log'); + // :snippet-start: verifyFanClubVc try { - result = await VerifiableCredential.verify({ vcJwt: signedVcJwt }); - console.log('VC Verification Successful!'); + await VerifiableCredential.verify({ vcJwt: signedVcJwt }); + console.log('\nVC Verification successful!\n'); } catch (err) { - console.log('VC Verification failed:' + err.message); + console.log('\nVC Verification failed: ' + err.message + '\n'); } // :snippet-end: - expect(result).toHaveProperty('vc'); - expect(result.vc).toHaveProperty('credentialSubject'); - expect(result.vc.credentialSubject.level).toBe('Stan'); - expect(result.vc.credentialSubject.legit).toBe(true); + expect(logSpy).toHaveBeenCalledWith('\nVC Verification successful!\n'); + logSpy.mockRestore(); }); - test('parseSignedVcJwt parses the signed VC JWT', async () => { - // :snippet-start: parseSignedVcJwt - const vc = VerifiableCredential.parseJwt({ vcJwt: signedVcJwt }); + test('parseFanClubJwt parses the signed VC JWT', async () => { + // :snippet-start: parseFanClubJwt + const parsedVC = await VerifiableCredential.parseJwt({ vcJwt: signedVcJwt }); // :snippet-end: - expect(vc).toHaveProperty('vcDataModel'); - expect(vc.vcDataModel).toHaveProperty('credentialSubject'); - expect(vc.vcDataModel.credentialSubject.level).toBe('Stan'); - expect(vc.vcDataModel.credentialSubject.legit).toBe(true); + expect(parsedVC).toHaveProperty('vcDataModel'); + expect(parsedVC.vcDataModel).toHaveProperty('credentialSubject'); + expect(parsedVC.vcDataModel.credentialSubject.level).toBe('Stan'); + expect(parsedVC.vcDataModel.credentialSubject.legit).toBe(true); }); }); + diff --git a/site/testsuites/testsuite-kotlin/pom.xml b/site/testsuites/testsuite-kotlin/pom.xml index 302bdc25b..f2aa401e8 100644 --- a/site/testsuites/testsuite-kotlin/pom.xml +++ b/site/testsuites/testsuite-kotlin/pom.xml @@ -79,6 +79,16 @@ ${version.web5} test + + com.fasterxml.jackson.core + jackson-core + 2.12.1 + + + com.fasterxml.jackson.core + jackson-databind + 2.12.1 + diff --git a/site/testsuites/testsuite-kotlin/src/test/kotlin/docs/web5/build/verifiablecredentials/FanClubVcTest.kt b/site/testsuites/testsuite-kotlin/src/test/kotlin/docs/web5/build/verifiablecredentials/FanClubVcTest.kt new file mode 100644 index 000000000..975f236e3 --- /dev/null +++ b/site/testsuites/testsuite-kotlin/src/test/kotlin/docs/web5/build/verifiablecredentials/FanClubVcTest.kt @@ -0,0 +1,134 @@ +package website.tbd.developer.site.docs.web5.build.verifiablecredentials; + +import java.io.ByteArrayOutputStream +import java.io.PrintStream + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Assertions.* + +import web5.sdk.credentials.VerifiableCredential +import web5.sdk.credentials.PresentationExchange +import web5.sdk.credentials.model.* +import web5.sdk.crypto.InMemoryKeyManager +import web5.sdk.dids.methods.key.DidKey + +/** + * Tests backing the VC Fan Club Workflow + */ +internal class FanClubVcTest { + data class SwiftiesFanClub( + val level: String, + val legit: Boolean + ) + + val fanClubIssuerDid = DidKey.create(InMemoryKeyManager()) + val aliceDid = DidKey.create(InMemoryKeyManager()) + + val vc = VerifiableCredential.create( + type = "SwiftiesFanClub", + issuer = fanClubIssuerDid.uri, + subject = aliceDid.uri, + data = SwiftiesFanClub(level = "Stan", legit = true) + ) + + val signedVcJwt = vc.sign(fanClubIssuerDid) + + val presentationDefinition = PresentationDefinitionV2( + id = "presDefId123", + name = "Swifties Fan Club Presentation Definition", + purpose = "for proving membership in the fan club", + inputDescriptors = listOf( + InputDescriptorV2( + id = "legitness", + purpose = "are you legit or not?", + constraints = ConstraintsV2( + fields = listOf( + FieldV2( + path = listOf("$.vc.credentialSubject.legit") + ) + ) + ) + ) + ) + ) + + @Test + fun `createFanClubVcKt creates a vc for fan club`() { + // :snippet-start: createFanClubVcKt + val vc = VerifiableCredential.create( + type = "SwiftiesFanClub", + issuer = fanClubIssuerDid.uri, + subject = aliceDid.uri, + data = SwiftiesFanClub(level = "Stan", legit = true) + ) + // :snippet-end: + + assertEquals("SwiftiesFanClub", vc.type) + assertEquals("Stan", vc.vcDataModel.credentialSubject.claims["level"]) + assertEquals(true, vc.vcDataModel.credentialSubject.claims["legit"]) + } + + @Test + fun `signFanClubVcKt signs a vc for fan club and returns jwt`() { + // :snippet-start: signFanClubVcKt + val signedVcJwt = vc.sign(fanClubIssuerDid) + // :snippet-end: + + assertTrue(signedVcJwt is String, "signedVcJwt should be a String") + } + + @Test + fun `satisfiesPresentationDefinitionFanClubVcKt checks if VC satisfies the presentation definition`() { + val outContent = ByteArrayOutputStream() + System.setOut(PrintStream(outContent)) + + // :snippet-start: satisfiesPresentationDefinitionFanClubVcKt + // Does VC Satisfy the Presentation Definition + try { + PresentationExchange.satisfiesPresentationDefinition(listOf(signedVcJwt), presentationDefinition) + println("VC Satisfies Presentation Definition!") + } catch (err: Exception) { + println("VC does not satisfy Presentation Definition: " + err.message) + } + // :snippet-end: + + assertTrue(outContent.toString().contains("VC Satisfies Presentation Definition!")) + System.setOut(System.out) + } + + @Test + fun `createPresentationFromCredentialsFanClubVcKt creates presentation from credentials and checks the presentation result`() { + // :snippet-start: createPresentationFromCredentialsFanClubVcKt + // Create Presentation Result that contains a Verifiable Presentation and Presentation Submission + val presentationResult = PresentationExchange.createPresentationFromCredentials(listOf(signedVcJwt), presentationDefinition) + println("Presentation Result" + presentationResult) + // :snippet-end: + assertEquals("presDefId123", presentationResult.definitionId) + } + + @Test + fun `verifyFanClubVcKt checks if VC verification is successful`() { + val outContent = ByteArrayOutputStream() + System.setOut(PrintStream(outContent)) + + // :snippet-start: verifyFanClubVcKt + try { + VerifiableCredential.verify(signedVcJwt) + println("VC Verification successful!") + } catch (err: Exception) { + println("VC Verification failed:" + err.message) + } + // :snippet-end: + assertTrue(outContent.toString().contains("VC Verification successful!")) + System.setOut(System.out) + } + + @Test + fun `parseFanClubJwtKt parses the signed VC JWT`() { + // :snippet-start: parseFanClubJwtKt + val parsedVc = VerifiableCredential.parseJwt(signedVcJwt) + // :snippet-end: + assertEquals("Stan", parsedVc.vcDataModel.credentialSubject.claims["level"]) + assertEquals(true, parsedVc.vcDataModel.credentialSubject.claims["legit"]) + } +} From df0a506b57215518eed38361a00995261036f7d8 Mon Sep 17 00:00:00 2001 From: Rizel Scarlett Date: Mon, 5 Feb 2024 02:02:40 -0500 Subject: [PATCH 17/31] no more inline shnips --- .../verifiable-credentials/fan-club-vc.mdx | 65 ++++--------------- .../fan-club-vc.test.js | 28 ++++++++ .../verifiablecredentials/FanClubVcTest.kt | 33 ++++++++++ 3 files changed, 73 insertions(+), 53 deletions(-) diff --git a/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx b/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx index 9aa97b31d..a93c9483b 100644 --- a/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx +++ b/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx @@ -10,6 +10,9 @@ import satisfiesPresentationDefinitionFanClubVc from '!!raw-loader!@site/snippet import createPresentationFromCredentialsFanClubVc from '!!raw-loader!@site/snippets/testsuite-javascript/__tests__/web5/build/verifiable-credentials/createPresentationFromCredentialsFanClubVc.snippet.js' import verifyFanClubVc from '!!raw-loader!@site/snippets/testsuite-javascript/__tests__/web5/build/verifiable-credentials/verifyFanClubVc.snippet.js' import parseFanClubJwt from '!!raw-loader!@site/snippets/testsuite-javascript/__tests__/web5/build/verifiable-credentials/parseFanClubJwt.snippet.js' +import importAndCreateDids from '!!raw-loader!@site/snippets/testsuite-javascript/__tests__/web5/build/verifiable-credentials/importAndCreateDids.snippet.js' +import importAndCreateClassCredential from '!!raw-loader!@site/snippets/testsuite-javascript/__tests__/web5/build/verifiable-credentials/importAndCreateClassCredential.snippet.js' + import createFanClubVcKt from '!!raw-loader!@site/snippets/testsuite-kotlin/src/test/kotlin/docs/web5/build/verifiablecredentials/createFanClubVcKt.snippet.kt' import signFanClubVcKt from '!!raw-loader!@site/snippets/testsuite-kotlin/src/test/kotlin/docs/web5/build/verifiablecredentials/signFanClubVcKt.snippet.kt' @@ -17,6 +20,8 @@ import satisfiesPresentationDefinitionFanClubVcKt from '!!raw-loader!@site/snipp import createPresentationFromCredentialsFanClubVcKt from '!!raw-loader!@site/snippets/testsuite-kotlin/src/test/kotlin/docs/web5/build/verifiablecredentials/createPresentationFromCredentialsFanClubVcKt.snippet.kt' import verifyFanClubVcKt from '!!raw-loader!@site/snippets/testsuite-kotlin/src/test/kotlin/docs/web5/build/verifiablecredentials/verifyFanClubVcKt.snippet.kt' import parseFanClubJwtKt from '!!raw-loader!@site/snippets/testsuite-kotlin/src/test/kotlin/docs/web5/build/verifiablecredentials/parseFanClubJwtKt.snippet.kt' +import importAndCreateDidsKt from '!!raw-loader!@site/snippets/testsuite-kotlin/src/test/kotlin/docs/web5/build/verifiablecredentials/importAndCreateDidsKt.snippet.kt' +import importAndCreateClassCredentialKt from '!!raw-loader!@site/snippets/testsuite-kotlin/src/test/kotlin/docs/web5/build/verifiablecredentials/importAndCreateClassCredentialKt.snippet.kt' @@ -78,27 +83,10 @@ This is because verifiable credentials use DIDs to identify issuers and holders. If you need to create DIDs, you can do so with the [@web5/dids](https://www.npmjs.com/package/@web5/dids) package: ### Model Credential @@ -107,38 +95,9 @@ Now, let's create the **SwiftiesFanClub** credential. We'll first model it with a class with some basic properties, `level` and `legit`: diff --git a/site/testsuites/testsuite-javascript/__tests__/web5/build/verifiable-credentials/fan-club-vc.test.js b/site/testsuites/testsuite-javascript/__tests__/web5/build/verifiable-credentials/fan-club-vc.test.js index 6b3b7c872..94831eb0d 100644 --- a/site/testsuites/testsuite-javascript/__tests__/web5/build/verifiable-credentials/fan-club-vc.test.js +++ b/site/testsuites/testsuite-javascript/__tests__/web5/build/verifiable-credentials/fan-club-vc.test.js @@ -57,6 +57,34 @@ describe('fan-club-vc', () => { }, })); }); + test('import dids package and create dids', async () => { + const importAndCreateDids = ` + // :snippet-start: importAndCreateDids + import { DidKeyMethod } from '@web5/dids'; + + const fanClubIssuerDid = await DidKeyMethod.create(); + const aliceDid = await DidIonMethod.create(); + // :snippet-end: + ` + }); + + test('import credentials package and create class for credential', async () => { + const importAndCreateClassCredential = ` + // :snippet-start: importAndCreateClassCredential + import { VerifiableCredential } from '@web5/credentials'; + + class SwiftiesFanClub { + constructor(level, legit) { + // indicates the fan's dedication level + this.level = level; + + // indicates if the fan is a genuine Swiftie + this.legit = legit; + } + } + // :snippet-end: + ` + }); test('createFanClubVc creates a vc for fan club', async () => { // :snippet-start: createFanClubVc const vc = await VerifiableCredential.create({ diff --git a/site/testsuites/testsuite-kotlin/src/test/kotlin/docs/web5/build/verifiablecredentials/FanClubVcTest.kt b/site/testsuites/testsuite-kotlin/src/test/kotlin/docs/web5/build/verifiablecredentials/FanClubVcTest.kt index 975f236e3..a0592a2d6 100644 --- a/site/testsuites/testsuite-kotlin/src/test/kotlin/docs/web5/build/verifiablecredentials/FanClubVcTest.kt +++ b/site/testsuites/testsuite-kotlin/src/test/kotlin/docs/web5/build/verifiablecredentials/FanClubVcTest.kt @@ -52,6 +52,39 @@ internal class FanClubVcTest { ) ) + @Test + fun `import dids package and create dids`() { + val importAndCreateDidsKt = + """ + // :snippet-start: importAndCreateDidsKt + import web5.sdk.crypto.InMemoryKeyManager + import web5.sdk.dids.methods.key.DidKey + + val fanClubIssuerDid = DidKey.create(InMemoryKeyManager()) + val aliceDid = DidKey.create(InMemoryKeyManager()) + // :snippet-end: + """ + } + +@Test + fun `import credentials package and create class for credential`() { + val importAndCreateClassCredentialKt = + """ + // :snippet-start: importAndCreateClassCredentialKt + import web5.sdk.credentials.VerifiableCredential + import web5.sdk.credentials.PresentationExchange + + data class SwiftiesFanClub( + // indicates the fan's dedication level + val level: String, + + // indicates if the fan is a genuine Swiftie + val legit: Boolean + ) + // :snippet-end: + """ + } + @Test fun `createFanClubVcKt creates a vc for fan club`() { // :snippet-start: createFanClubVcKt From 564a5858c8dbe4e198aa895e7d90359d14c2d183 Mon Sep 17 00:00:00 2001 From: Rizel Scarlett Date: Mon, 5 Feb 2024 02:21:49 -0500 Subject: [PATCH 18/31] shnip presentation def --- .../verifiable-credentials/fan-club-vc.mdx | 81 +++---------------- .../fan-club-vc.test.js | 43 ++++++++-- .../verifiablecredentials/FanClubVcTest.kt | 45 +++++++++-- 3 files changed, 89 insertions(+), 80 deletions(-) diff --git a/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx b/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx index a93c9483b..9ae789e76 100644 --- a/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx +++ b/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx @@ -10,9 +10,9 @@ import satisfiesPresentationDefinitionFanClubVc from '!!raw-loader!@site/snippet import createPresentationFromCredentialsFanClubVc from '!!raw-loader!@site/snippets/testsuite-javascript/__tests__/web5/build/verifiable-credentials/createPresentationFromCredentialsFanClubVc.snippet.js' import verifyFanClubVc from '!!raw-loader!@site/snippets/testsuite-javascript/__tests__/web5/build/verifiable-credentials/verifyFanClubVc.snippet.js' import parseFanClubJwt from '!!raw-loader!@site/snippets/testsuite-javascript/__tests__/web5/build/verifiable-credentials/parseFanClubJwt.snippet.js' -import importAndCreateDids from '!!raw-loader!@site/snippets/testsuite-javascript/__tests__/web5/build/verifiable-credentials/importAndCreateDids.snippet.js' -import importAndCreateClassCredential from '!!raw-loader!@site/snippets/testsuite-javascript/__tests__/web5/build/verifiable-credentials/importAndCreateClassCredential.snippet.js' - +import createDids from '!!raw-loader!@site/snippets/testsuite-javascript/__tests__/web5/build/verifiable-credentials/createDids.snippet.js' +import createClassCredential from '!!raw-loader!@site/snippets/testsuite-javascript/__tests__/web5/build/verifiable-credentials/createClassCredential.snippet.js' +import createAndValidatePresentation from '!!raw-loader!@site/snippets/testsuite-javascript/__tests__/web5/build/verifiable-credentials/createAndValidatePresentation.snippet.js' import createFanClubVcKt from '!!raw-loader!@site/snippets/testsuite-kotlin/src/test/kotlin/docs/web5/build/verifiablecredentials/createFanClubVcKt.snippet.kt' import signFanClubVcKt from '!!raw-loader!@site/snippets/testsuite-kotlin/src/test/kotlin/docs/web5/build/verifiablecredentials/signFanClubVcKt.snippet.kt' @@ -20,8 +20,9 @@ import satisfiesPresentationDefinitionFanClubVcKt from '!!raw-loader!@site/snipp import createPresentationFromCredentialsFanClubVcKt from '!!raw-loader!@site/snippets/testsuite-kotlin/src/test/kotlin/docs/web5/build/verifiablecredentials/createPresentationFromCredentialsFanClubVcKt.snippet.kt' import verifyFanClubVcKt from '!!raw-loader!@site/snippets/testsuite-kotlin/src/test/kotlin/docs/web5/build/verifiablecredentials/verifyFanClubVcKt.snippet.kt' import parseFanClubJwtKt from '!!raw-loader!@site/snippets/testsuite-kotlin/src/test/kotlin/docs/web5/build/verifiablecredentials/parseFanClubJwtKt.snippet.kt' -import importAndCreateDidsKt from '!!raw-loader!@site/snippets/testsuite-kotlin/src/test/kotlin/docs/web5/build/verifiablecredentials/importAndCreateDidsKt.snippet.kt' -import importAndCreateClassCredentialKt from '!!raw-loader!@site/snippets/testsuite-kotlin/src/test/kotlin/docs/web5/build/verifiablecredentials/importAndCreateClassCredentialKt.snippet.kt' +import createDidsKt from '!!raw-loader!@site/snippets/testsuite-kotlin/src/test/kotlin/docs/web5/build/verifiablecredentials/createDidsKt.snippet.kt' +import createClassCredentialKt from '!!raw-loader!@site/snippets/testsuite-kotlin/src/test/kotlin/docs/web5/build/verifiablecredentials/createClassCredentialKt.snippet.kt' +import createAndValidatePresentationKt from '!!raw-loader!@site/snippets/testsuite-kotlin/src/test/kotlin/docs/web5/build/verifiablecredentials/createAndValidatePresentationKt.snippet.kt' @@ -84,8 +85,8 @@ If you need to create DIDs, you can do so with the [@web5/dids](https://www.npmj @@ -96,8 +97,8 @@ We'll first model it with a class with some basic properties, `level` and `legit @@ -215,65 +216,9 @@ To kick off the presentation exchange, the Swag Supplier (verifier) will send a Here's how the verifier can create the presentation definition, and validate that it is properly formed: diff --git a/site/testsuites/testsuite-javascript/__tests__/web5/build/verifiable-credentials/fan-club-vc.test.js b/site/testsuites/testsuite-javascript/__tests__/web5/build/verifiable-credentials/fan-club-vc.test.js index 94831eb0d..248d6704e 100644 --- a/site/testsuites/testsuite-javascript/__tests__/web5/build/verifiable-credentials/fan-club-vc.test.js +++ b/site/testsuites/testsuite-javascript/__tests__/web5/build/verifiable-credentials/fan-club-vc.test.js @@ -57,9 +57,9 @@ describe('fan-club-vc', () => { }, })); }); - test('import dids package and create dids', async () => { - const importAndCreateDids = ` - // :snippet-start: importAndCreateDids + test('ceateDids imports dids package and creates dids', async () => { + const ceateDids = ` + // :snippet-start: createDids import { DidKeyMethod } from '@web5/dids'; const fanClubIssuerDid = await DidKeyMethod.create(); @@ -68,9 +68,9 @@ describe('fan-club-vc', () => { ` }); - test('import credentials package and create class for credential', async () => { - const importAndCreateClassCredential = ` - // :snippet-start: importAndCreateClassCredential + test('createClassCredential imports credentials package and creates class for credential', async () => { + const createClassCredential = ` + // :snippet-start: createClassCredential import { VerifiableCredential } from '@web5/credentials'; class SwiftiesFanClub { @@ -108,6 +108,37 @@ describe('fan-club-vc', () => { expect(signedVcJwt).not.toBe(''); }); + test('createAndValidatePresentation creates and validates presentation definition', async () => { + const createAndValidatePresentation = ` + // :snippet-start: createAndValidatePresentation + import { VerifiableCredential, PresentationExchange } from "@web5/credentials"; + + const presentationDefinition = { + 'id': 'presDefId123', + 'name': 'Swifties Fan Club Presentation Definition', + 'purpose': 'for proving membership in the fan club', + 'input_descriptors': [ + { + 'id': 'legitness', + 'purpose': 'are you legit or not?', + 'constraints': { + 'fields': [ + { + 'path': [ + '$.credentialSubject.legit', + ] + } + ] + } + } + ] + }; + + const definitionValidation = PresentationExchange.validateDefinition({ presentationDefinition }); + // :snippet-end: + ` + }); + test('satisfiesPresentationDefinitionFanClubVc checks if VC satisfies the presentation definition', async () => { const logSpy = vi.spyOn(console, 'log'); // :snippet-start: satisfiesPresentationDefinitionFanClubVc diff --git a/site/testsuites/testsuite-kotlin/src/test/kotlin/docs/web5/build/verifiablecredentials/FanClubVcTest.kt b/site/testsuites/testsuite-kotlin/src/test/kotlin/docs/web5/build/verifiablecredentials/FanClubVcTest.kt index a0592a2d6..b50e81444 100644 --- a/site/testsuites/testsuite-kotlin/src/test/kotlin/docs/web5/build/verifiablecredentials/FanClubVcTest.kt +++ b/site/testsuites/testsuite-kotlin/src/test/kotlin/docs/web5/build/verifiablecredentials/FanClubVcTest.kt @@ -53,10 +53,10 @@ internal class FanClubVcTest { ) @Test - fun `import dids package and create dids`() { - val importAndCreateDidsKt = + fun `createDidsKt imports dids package and creates dids`() { + val createDidsKt = """ - // :snippet-start: importAndCreateDidsKt + // :snippet-start: createDidsKt import web5.sdk.crypto.InMemoryKeyManager import web5.sdk.dids.methods.key.DidKey @@ -67,10 +67,10 @@ internal class FanClubVcTest { } @Test - fun `import credentials package and create class for credential`() { - val importAndCreateClassCredentialKt = + fun `createClassCredentialKt imports credentials package and creates class for credential`() { + val createClassCredentialKt = """ - // :snippet-start: importAndCreateClassCredentialKt + // :snippet-start: createClassCredentialKt import web5.sdk.credentials.VerifiableCredential import web5.sdk.credentials.PresentationExchange @@ -110,6 +110,39 @@ internal class FanClubVcTest { assertTrue(signedVcJwt is String, "signedVcJwt should be a String") } + @Test + fun `createAndValidatePresentationKt creates and validates presentation definitionl`() { + val createAndValidatePresentationKt = + """ + // :snippet-start: createAndValidatePresentationKt + import web5.sdk.credentials.PresentationExchange + import web5.sdk.credentials.VerifiableCredential + import web5.sdk.credentials.model.* + + val presentationDefinition = PresentationDefinitionV2( + id = "presDefId123", + name = "Swifties Fan Club Presentation Definition", + purpose = "for proving membership in the fan club", + inputDescriptors = listOf( + InputDescriptorV2( + id = "legitness", + purpose = "are you legit or not?", + constraints = ConstraintsV2( + fields = listOf( + FieldV2( + path = listOf("$.vc.credentialSubject.legit") + ) + ) + ) + ) + ) + ) + + val definitionValidation = PresentationExchange.validateDefinition(presentationDefinition) + // :snippet-end: + """ + } + @Test fun `satisfiesPresentationDefinitionFanClubVcKt checks if VC satisfies the presentation definition`() { val outContent = ByteArrayOutputStream() From d1ffa1b3130d0d19dfb596c335803317278830fd Mon Sep 17 00:00:00 2001 From: Rizel Scarlett Date: Mon, 5 Feb 2024 07:08:51 -0500 Subject: [PATCH 19/31] verifiable presentation --- .../verifiable-credentials/fan-club-vc.mdx | 32 +++++++++++++------ .../verifiablecredentials/FanClubVcTest.kt | 11 ++++++- 2 files changed, 33 insertions(+), 10 deletions(-) diff --git a/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx b/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx index 9ae789e76..0933a119c 100644 --- a/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx +++ b/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx @@ -313,15 +313,29 @@ The result of the presentation: { code: ` { - "id": "kMqRP0zRKaiZNlbtbEIxd", - "definitionId": "presDefId123", - "descriptorMap": [ - { - "id": "legitness", - "format": "jwt_vc", - "path": "$.verifiableCredential[0]" - } - ] + "@context": [ + "https://www.w3.org/2018/credentials/v1" + ], + "type": [ + "VerifiablePresentation" + ], + "id": "urn:uuid:956875ff-18da-42fe-86ba-c228fa83affa", + "presentation_submission": { + "id": "kMqRP0zRKaiZNlbtbEIxd", + "definitionId": "presDefId123", + "descriptorMap": [ + { + "id": "legitness", + "format": "jwt_vc", + "path": "$.verifiableCredential[0]" + } + ] + }, + "verifiableCredential": [ + "eyJ0eXAiOipOSl...WndCJ9.eyJ2YyTk0MN2pDMzQhdG...UR1In0.rtlg8k9KU8_ENkrY06y..." + ], + "holder": "did:key:z6MkjGSeekPGE9QfczHWyW8v2ZzJU68kqSHzV7L2dmQyuyDu" +} `, language: 'Kotlin', codeLanguage: 'json' diff --git a/site/testsuites/testsuite-kotlin/src/test/kotlin/docs/web5/build/verifiablecredentials/FanClubVcTest.kt b/site/testsuites/testsuite-kotlin/src/test/kotlin/docs/web5/build/verifiablecredentials/FanClubVcTest.kt index b50e81444..3c6538822 100644 --- a/site/testsuites/testsuite-kotlin/src/test/kotlin/docs/web5/build/verifiablecredentials/FanClubVcTest.kt +++ b/site/testsuites/testsuite-kotlin/src/test/kotlin/docs/web5/build/verifiablecredentials/FanClubVcTest.kt @@ -11,6 +11,7 @@ import web5.sdk.credentials.PresentationExchange import web5.sdk.credentials.model.* import web5.sdk.crypto.InMemoryKeyManager import web5.sdk.dids.methods.key.DidKey +import web5.sdk.credentials.VerifiablePresentation /** * Tests backing the VC Fan Club Workflow @@ -117,6 +118,7 @@ internal class FanClubVcTest { // :snippet-start: createAndValidatePresentationKt import web5.sdk.credentials.PresentationExchange import web5.sdk.credentials.VerifiableCredential + import web5.sdk.credentials.VerifiablePresentation import web5.sdk.credentials.model.* val presentationDefinition = PresentationDefinitionV2( @@ -167,9 +169,16 @@ internal class FanClubVcTest { // :snippet-start: createPresentationFromCredentialsFanClubVcKt // Create Presentation Result that contains a Verifiable Presentation and Presentation Submission val presentationResult = PresentationExchange.createPresentationFromCredentials(listOf(signedVcJwt), presentationDefinition) - println("Presentation Result" + presentationResult) + + val vp = VerifiablePresentation.create( + vcJwts = listOf(signedVcJwt), + holder = aliceDid.uri, + additionalData = mapOf("presentation_submission" to presentationResult) + ) + println("Presentation Result and Verifiable Presentation" + vp) // :snippet-end: assertEquals("presDefId123", presentationResult.definitionId) + assertEquals("VerifiablePresentation", vp.vpDataModel.type) } @Test From 3f06b96b9348a2ce77ac2b45d3c3e83ecaa1a565 Mon Sep 17 00:00:00 2001 From: Rizel Scarlett Date: Mon, 5 Feb 2024 14:34:29 -0500 Subject: [PATCH 20/31] switching content --- .../verifiable-credentials/fan-club-vc.mdx | 7 ++- site/src/components/language/Shnip.jsx | 46 +++++++++---------- 2 files changed, 25 insertions(+), 28 deletions(-) diff --git a/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx b/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx index 0933a119c..b71a505d4 100644 --- a/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx +++ b/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx @@ -222,15 +222,14 @@ Here's how the verifier can create the presentation definition, and validate tha ]} /> -A successful validation would result in: + { // support line breaks for inline code snippets @@ -32,37 +33,34 @@ const addLineBreaks = (code, breakLines) => { {snippets && - snippets.map(({ snippetContent, language, title }) => ( -
- -
- ))} + snippets.map( + ({ snippetContent, language, title, content }, index) => ( +
+ {content && {content}} + +
+ ), + )} {inlineSnippets && inlineSnippets.map( - ({ code, language, codeLanguage, title, breakLineAt }, index) => ( + ({ content, code, language, codeLanguage, breakLineAt }, index) => (
- - {addLineBreaks(code, breakLineAt)} - + {content && {content}} + {code && ( + + {addLineBreaks(code, breakLineAt)} + + )}
), )} - - {inlineContent && - inlineContent.map(({ content, language }, index) => ( -
- {content} -
- ))}
); From 31d9c1acb7433087e542064196b5dd509b67701e Mon Sep 17 00:00:00 2001 From: Rizel Scarlett Date: Mon, 5 Feb 2024 15:28:13 -0500 Subject: [PATCH 21/31] updating to maven links --- site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx b/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx index b71a505d4..8af9792c1 100644 --- a/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx +++ b/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx @@ -34,7 +34,7 @@ In this tutorial, we'll learn how to use [verifiable credentials](/docs/web5/lea ![Fan Club Membership](/img/vc-fanclub.png) ## Setting the Stage -Before we start issuing and verifying credentials, let's set up our environment by installing the and packages: +Before we start issuing and verifying credentials, let's set up our environment by installing the and packages: Date: Mon, 5 Feb 2024 15:30:27 -0500 Subject: [PATCH 22/31] another language link --- site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx b/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx index 8af9792c1..9d0ceb31a 100644 --- a/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx +++ b/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx @@ -81,7 +81,7 @@ In this section, we'll walk through all of the steps required to create and issu As a prerequisite, both the Fan Club and Alice need [decentralized identitifiers](/docs/web5/learn/decentralized-identifiers). This is because verifiable credentials use DIDs to identify issuers and holders. -If you need to create DIDs, you can do so with the [@web5/dids](https://www.npmjs.com/package/@web5/dids) package: +If you need to create DIDs, you can do so with the package: Date: Mon, 5 Feb 2024 16:31:25 -0500 Subject: [PATCH 23/31] separate imports so I can test snippets better --- .../verifiable-credentials/fan-club-vc.mdx | 83 ++++++++++++++++-- .../fan-club-vc.test.js | 87 ++++++++----------- .../verifiablecredentials/FanClubVcTest.kt | 27 ++---- 3 files changed, 119 insertions(+), 78 deletions(-) diff --git a/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx b/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx index 9d0ceb31a..c45c93547 100644 --- a/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx +++ b/site/docs/web5/build/verifiable-credentials/fan-club-vc.mdx @@ -11,7 +11,6 @@ import createPresentationFromCredentialsFanClubVc from '!!raw-loader!@site/snip import verifyFanClubVc from '!!raw-loader!@site/snippets/testsuite-javascript/__tests__/web5/build/verifiable-credentials/verifyFanClubVc.snippet.js' import parseFanClubJwt from '!!raw-loader!@site/snippets/testsuite-javascript/__tests__/web5/build/verifiable-credentials/parseFanClubJwt.snippet.js' import createDids from '!!raw-loader!@site/snippets/testsuite-javascript/__tests__/web5/build/verifiable-credentials/createDids.snippet.js' -import createClassCredential from '!!raw-loader!@site/snippets/testsuite-javascript/__tests__/web5/build/verifiable-credentials/createClassCredential.snippet.js' import createAndValidatePresentation from '!!raw-loader!@site/snippets/testsuite-javascript/__tests__/web5/build/verifiable-credentials/createAndValidatePresentation.snippet.js' import createFanClubVcKt from '!!raw-loader!@site/snippets/testsuite-kotlin/src/test/kotlin/docs/web5/build/verifiablecredentials/createFanClubVcKt.snippet.kt' @@ -21,7 +20,6 @@ import createPresentationFromCredentialsFanClubVcKt from '!!raw-loader!@site/sni import verifyFanClubVcKt from '!!raw-loader!@site/snippets/testsuite-kotlin/src/test/kotlin/docs/web5/build/verifiablecredentials/verifyFanClubVcKt.snippet.kt' import parseFanClubJwtKt from '!!raw-loader!@site/snippets/testsuite-kotlin/src/test/kotlin/docs/web5/build/verifiablecredentials/parseFanClubJwtKt.snippet.kt' import createDidsKt from '!!raw-loader!@site/snippets/testsuite-kotlin/src/test/kotlin/docs/web5/build/verifiablecredentials/createDidsKt.snippet.kt' -import createClassCredentialKt from '!!raw-loader!@site/snippets/testsuite-kotlin/src/test/kotlin/docs/web5/build/verifiablecredentials/createClassCredentialKt.snippet.kt' import createAndValidatePresentationKt from '!!raw-loader!@site/snippets/testsuite-kotlin/src/test/kotlin/docs/web5/build/verifiablecredentials/createAndValidatePresentationKt.snippet.kt' @@ -66,6 +64,28 @@ dependencies { ]} /> +### Import packages + +After installing the packages, import them into your project as shown below: + + + ## The Cast There are a few characters involved in our story: @@ -76,7 +96,7 @@ There are a few characters involved in our story: ## Act 1: Issuing the Credential In this section, we'll walk through all of the steps required to create and issue a verifiable credential. - + ### Create DIDs As a prerequisite, both the Fan Club and Alice need [decentralized identitifiers](/docs/web5/learn/decentralized-identifiers). This is because verifiable credentials use DIDs to identify issuers and holders. @@ -96,9 +116,38 @@ Now, let's create the **SwiftiesFanClub** credential. We'll first model it with a class with some basic properties, `level` and `legit`: @@ -213,6 +262,28 @@ A presentation exchange is the process where the holder of VCs presents them to ### Create Presentation Definition To kick off the presentation exchange, the Swag Supplier (verifier) will send a request to Alice, which includes a presentation definition, specifying what credentials or claims are needed. + + +To create and validate this presentation definition, the verifier first needs to import packages from the library. + + + Here's how the verifier can create the presentation definition, and validate that it is properly formed: { }, })); }); - test('ceateDids imports dids package and creates dids', async () => { - const ceateDids = ` - // :snippet-start: createDids - import { DidKeyMethod } from '@web5/dids'; - - const fanClubIssuerDid = await DidKeyMethod.create(); - const aliceDid = await DidIonMethod.create(); - // :snippet-end: - ` + test('createDids creates an issuer DID and alice DID with did:key method', async () => { + // :snippet-start: createDids + const fanClubIssuerDid = await DidKeyMethod.create(); + const aliceDid = await DidKeyMethod.create(); + // :snippet-end: + expect(aliceDid.did).toMatch(/^did:key:/); + expect(fanClubIssuerDid.did).toMatch(/^did:key:/); }); - test('createClassCredential imports credentials package and creates class for credential', async () => { - const createClassCredential = ` - // :snippet-start: createClassCredential - import { VerifiableCredential } from '@web5/credentials'; - - class SwiftiesFanClub { - constructor(level, legit) { - // indicates the fan's dedication level - this.level = level; - - // indicates if the fan is a genuine Swiftie - this.legit = legit; - } - } - // :snippet-end: - ` - }); test('createFanClubVc creates a vc for fan club', async () => { // :snippet-start: createFanClubVc const vc = await VerifiableCredential.create({ @@ -109,34 +90,34 @@ describe('fan-club-vc', () => { }); test('createAndValidatePresentation creates and validates presentation definition', async () => { - const createAndValidatePresentation = ` - // :snippet-start: createAndValidatePresentation - import { VerifiableCredential, PresentationExchange } from "@web5/credentials"; - - const presentationDefinition = { - 'id': 'presDefId123', - 'name': 'Swifties Fan Club Presentation Definition', - 'purpose': 'for proving membership in the fan club', - 'input_descriptors': [ - { - 'id': 'legitness', - 'purpose': 'are you legit or not?', - 'constraints': { - 'fields': [ - { - 'path': [ - '$.credentialSubject.legit', - ] - } - ] + // :snippet-start: createAndValidatePresentation + const presentationDefinition = { + 'id': 'presDefId123', + 'name': 'Swifties Fan Club Presentation Definition', + 'purpose': 'for proving membership in the fan club', + 'input_descriptors': [ + { + 'id': 'legitness', + 'purpose': 'are you legit or not?', + 'constraints': { + 'fields': [ + { + 'path': [ + '$.credentialSubject.legit', + ] + } + ] + } } - } - ] - }; - - const definitionValidation = PresentationExchange.validateDefinition({ presentationDefinition }); - // :snippet-end: - ` + ] + }; + + const definitionValidation = PresentationExchange.validateDefinition({ presentationDefinition }); + // :snippet-end: + + expect(Array.isArray(definitionValidation)).toBe(true); + expect.soft(definitionValidation[0]).toHaveProperty('status', 'info'); + expect.soft(definitionValidation[0]).toHaveProperty('message', 'ok'); }); test('satisfiesPresentationDefinitionFanClubVc checks if VC satisfies the presentation definition', async () => { diff --git a/site/testsuites/testsuite-kotlin/src/test/kotlin/docs/web5/build/verifiablecredentials/FanClubVcTest.kt b/site/testsuites/testsuite-kotlin/src/test/kotlin/docs/web5/build/verifiablecredentials/FanClubVcTest.kt index 3c6538822..6394a461b 100644 --- a/site/testsuites/testsuite-kotlin/src/test/kotlin/docs/web5/build/verifiablecredentials/FanClubVcTest.kt +++ b/site/testsuites/testsuite-kotlin/src/test/kotlin/docs/web5/build/verifiablecredentials/FanClubVcTest.kt @@ -55,16 +55,12 @@ internal class FanClubVcTest { @Test fun `createDidsKt imports dids package and creates dids`() { - val createDidsKt = - """ - // :snippet-start: createDidsKt - import web5.sdk.crypto.InMemoryKeyManager - import web5.sdk.dids.methods.key.DidKey - - val fanClubIssuerDid = DidKey.create(InMemoryKeyManager()) - val aliceDid = DidKey.create(InMemoryKeyManager()) - // :snippet-end: - """ + // :snippet-start: createDidsKt + val fanClubIssuerDid = DidKey.create(InMemoryKeyManager()) + val aliceDid = DidKey.create(InMemoryKeyManager()) + // :snippet-end: + assertTrue(fanClubIssuerDid.uri.startsWith("did:key:"), "fanClubIssuerDid should start with 'did:key:'") + assertTrue(aliceDid.uri.startsWith("did:key:"), "aliceDid should start with 'did:key:'") } @Test @@ -113,14 +109,7 @@ internal class FanClubVcTest { @Test fun `createAndValidatePresentationKt creates and validates presentation definitionl`() { - val createAndValidatePresentationKt = - """ - // :snippet-start: createAndValidatePresentationKt - import web5.sdk.credentials.PresentationExchange - import web5.sdk.credentials.VerifiableCredential - import web5.sdk.credentials.VerifiablePresentation - import web5.sdk.credentials.model.* - + // :snippet-start: createAndValidatePresentationKt val presentationDefinition = PresentationDefinitionV2( id = "presDefId123", name = "Swifties Fan Club Presentation Definition", @@ -142,7 +131,7 @@ internal class FanClubVcTest { val definitionValidation = PresentationExchange.validateDefinition(presentationDefinition) // :snippet-end: - """ + assertDoesNotThrow {PresentationExchange.validateDefinition(presentationDefinition)} } @Test From e1e4e79048509af896f8258999b62322c6dc7cdc Mon Sep 17 00:00:00 2001 From: Angie Jones Date: Tue, 6 Feb 2024 14:03:08 -0600 Subject: [PATCH 24/31] Kotlin: PFI Allowlist (#1208) * Kotlin: PFI Allowlist * dont publish test dids * ocd --- package.json | 2 +- site/docs/tbdex/wallet/allowlist-pfis.mdx | 16 ++++++-- .../tbdex/wallet/allowListPfi.test.js | 25 ++++++++++++ .../docs/tbdex/wallet/PfiAllowListTest.kt | 39 +++++++++++++++++++ 4 files changed, 78 insertions(+), 4 deletions(-) create mode 100644 site/testsuites/testsuite-javascript/__tests__/tbdex/wallet/allowListPfi.test.js create mode 100644 site/testsuites/testsuite-kotlin/src/test/kotlin/docs/tbdex/wallet/PfiAllowListTest.kt diff --git a/package.json b/package.json index 12ccc5af2..44acc6ece 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "start:widget": "pnpm --filter web5-quickstart-widgets start", "build": "pnpm run shnip && pnpm --filter site run build", "clear": "pnpm --filter site run clear", - "test": "pnpm run shnip && pnpm vitest run --config vite.config.ts --no-threads && pnpm test:browser && pnpm test:kotlin", + "test": "pnpm run shnip && pnpm vitest run --config vite.config.ts --no-threads && pnpm test:kotlin && pnpm test:browser", "test:watch": "pnpm run shnip && pnpm vitest --config vite.config.ts --watch", "test:browser": "pnpm -r test:browser", "test:versions": "node check-versions.js", diff --git a/site/docs/tbdex/wallet/allowlist-pfis.mdx b/site/docs/tbdex/wallet/allowlist-pfis.mdx index d7ac3066a..833555491 100644 --- a/site/docs/tbdex/wallet/allowlist-pfis.mdx +++ b/site/docs/tbdex/wallet/allowlist-pfis.mdx @@ -1,7 +1,14 @@ --- +title: Allowlisting PFIs +hide_title: true sidebar_position: 4 --- +import isPFIJs from '!!raw-loader!@site/snippets/testsuite-javascript/__tests__/tbdex/wallet/isPFIJs.snippet.js' +import isPFIKt from '!!raw-loader!@site/snippets/testsuite-kotlin/src/test/kotlin/docs/tbdex/wallet/isPFIKt.snippet.kt' + + + # Allowlisting PFIs While tbDEX is a permissionless network where any PFI can participate, you may want to curate your own list of PFIs in which you engage with. We refer to this as **allowlisting**. @@ -18,9 +25,12 @@ Consider factors like transaction fees, currency pairs offered, and reputation. To determine if a PFI is part of the tbDEX network, you can check their [DID document](/docs/web5/learn/did_document) for the `PFI` service type: -```js -const isPFI = pfiDid.document.service.some(service => service.type === 'PFI'); -``` + ## Verify PFI Credentials diff --git a/site/testsuites/testsuite-javascript/__tests__/tbdex/wallet/allowListPfi.test.js b/site/testsuites/testsuite-javascript/__tests__/tbdex/wallet/allowListPfi.test.js new file mode 100644 index 000000000..47975a377 --- /dev/null +++ b/site/testsuites/testsuite-javascript/__tests__/tbdex/wallet/allowListPfi.test.js @@ -0,0 +1,25 @@ +import { test, expect, describe, beforeAll } from 'vitest'; +import { DidDhtMethod } from '@web5/dids'; + +let pfiDid; + +describe('allowlist PFIs', () => { + beforeAll(async () => { + pfiDid = await DidDhtMethod.create({ + publish: false, + services: [{ + id: 'pfi', + type: 'PFI', + serviceEndpoint: 'tbdex-pfi.tbddev.org' + }] + }) + }); + + test('PFI DID has PFI service', async () => { + // :snippet-start: isPFIJs + const isPFI = pfiDid.document.service.some(service => service.type === 'PFI'); + // :snippet-end: + expect(isPFI).toBe(true) + }); + +}); \ No newline at end of file diff --git a/site/testsuites/testsuite-kotlin/src/test/kotlin/docs/tbdex/wallet/PfiAllowListTest.kt b/site/testsuites/testsuite-kotlin/src/test/kotlin/docs/tbdex/wallet/PfiAllowListTest.kt new file mode 100644 index 000000000..14d35b0a1 --- /dev/null +++ b/site/testsuites/testsuite-kotlin/src/test/kotlin/docs/tbdex/wallet/PfiAllowListTest.kt @@ -0,0 +1,39 @@ + +package website.tbd.developer.site.docs.tbdex.wallet + +import foundation.identity.did.Service +import web5.sdk.crypto.InMemoryKeyManager +import web5.sdk.dids.methods.dht.CreateDidDhtOptions +import web5.sdk.dids.methods.dht.DidDht +import java.net.URI + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Assertions.* + +/** + * Tests for Wallet AllowList guide + */ +class PfiAllowListTest { + + @Test + fun `check if DID has PFI service`() { + val serviceToAdd = Service.builder() + .id(URI("pfi")) + .type("PFI") + .serviceEndpoint("tbdex-pfi.tbddev.org") + .build() + + val options = CreateDidDhtOptions( + publish = false, + services = listOf(serviceToAdd), + ) + + val pfiDid = DidDht.create(InMemoryKeyManager(), options) + + // :snippet-start: isPFIKt + val isPFI = pfiDid.didDocument?.services?.any { it.type == "PFI" } ?: false + // :snippet-end: + + assertTrue(isPFI, "DID should have a PFI service") + } +} From 897b9fe404cf380db08a11b6d7f1d01ae3dafd75 Mon Sep 17 00:00:00 2001 From: Rizel Scarlett Date: Tue, 6 Feb 2024 16:42:23 -0500 Subject: [PATCH 25/31] Added Kotlin Shnips for PEX (#1199) * kotlin shnips * adding new line * kotlin shnip wasnt generating * removing extra code snippet * enabling switch content * adding clarity for presentation submission with Kotlin * showing language switcher at the top * adding back title * adding back title * hardcode imports * make verifiable presentation more obvious * put language switcher at the top * remove unnnecessary import * possible note for missing method * PR #1199 - Fix jackson.core to a more compatible version * handle all imports with model.* * add in as snippet --------- Co-authored-by: Andrew Lee Rubinger --- .../presentation-exchange.mdx | 145 ++++++++++- .../presentation-exchange.test.js | 229 ++++++++++++++---- site/testsuites/testsuite-kotlin/pom.xml | 2 +- .../PresentationExchangeTest.kt | 168 +++++++++++++ 4 files changed, 486 insertions(+), 58 deletions(-) create mode 100644 site/testsuites/testsuite-kotlin/src/test/kotlin/docs/web5/build/verifiablecredentials/PresentationExchangeTest.kt diff --git a/site/docs/web5/build/verifiable-credentials/presentation-exchange.mdx b/site/docs/web5/build/verifiable-credentials/presentation-exchange.mdx index e1462bc8b..e4e151275 100644 --- a/site/docs/web5/build/verifiable-credentials/presentation-exchange.mdx +++ b/site/docs/web5/build/verifiable-credentials/presentation-exchange.mdx @@ -1,8 +1,25 @@ --- +title: Presentation Exchange +hide_title: true sidebar_position: 3 --- -import CodeSnippet from '@site/src/components/CodeSnippet'; + +import getLoanAppPresentationDefinition from '!!raw-loader!@site/snippets/testsuite-javascript/__tests__/web5/build/verifiable-credentials/getLoanAppPresentationDefinition.snippet.js' +import satisfiesPresentationDefinitionForPex from '!!raw-loader!@site/snippets/testsuite-javascript/__tests__/web5/build/verifiable-credentials/satisfiesPresentationDefinitionForPex.snippet.js' +import selectCredentialsForPex from '!!raw-loader!@site/snippets/testsuite-javascript/__tests__/web5/build/verifiable-credentials/selectCredentialsForPex.snippet.js' +import createPresentationFromCredentialsForPex from '!!raw-loader!@site/snippets/testsuite-javascript/__tests__/web5/build/verifiable-credentials/createPresentationFromCredentialsForPex.snippet.js' +import validVerifiablePresentationForPex from '!!raw-loader!@site/snippets/testsuite-javascript/__tests__/web5/build/verifiable-credentials/validVerifiablePresentationForPex.snippet.js' +import validPresentationSubmissionForPex from '!!raw-loader!@site/snippets/testsuite-javascript/__tests__/web5/build/verifiable-credentials/validPresentationSubmissionForPex.snippet.js' + + +import getLoanAppPresentationDefinitionKt from '!!raw-loader!@site/snippets/testsuite-kotlin/src/test/kotlin/docs/web5/build/verifiablecredentials/getLoanAppPresentationDefinitionKt.snippet.kt' +import satisfiesPresentationDefinitionForPexKt from '!!raw-loader!@site/snippets/testsuite-kotlin/src/test/kotlin/docs/web5/build/verifiablecredentials/satisfiesPresentationDefinitionForPexKt.snippet.kt' +import selectCredentialsForPexKt from '!!raw-loader!@site/snippets/testsuite-kotlin/src/test/kotlin/docs/web5/build/verifiablecredentials/selectCredentialsForPexKt.snippet.kt' +import createPresentationFromCredentialsForPexKt from '!!raw-loader!@site/snippets/testsuite-kotlin/src/test/kotlin/docs/web5/build/verifiablecredentials/createPresentationFromCredentialsForPexKt.snippet.kt' +import validVerifiablePresentationForPexKt from '!!raw-loader!@site/snippets/testsuite-kotlin/src/test/kotlin/docs/web5/build/verifiablecredentials/validVerifiablePresentationForPexKt.snippet.kt' + + # Presentation Exchange @@ -26,7 +43,12 @@ Assume a lender has an existing Presentation Definition specifying that applican
Presentation Definition - +
@@ -37,9 +59,24 @@ We'll use the Presentation Definition above to present credentials that meet its All methods needed to perform a PEX are in the `PresentationExchange` class. You can import this class from the `@web5/credentials` package: -```js + ## Select Credentials @@ -47,13 +84,23 @@ A user may possess multiple credentials. To preserve the user's privacy, when creating a Presentation, you'll want to present only the VCs that match the Presentation Definition requirements. This is done with the `selectCredentials()` method: - + ## Satisfy Presentation Definition To ensure that the selected credentials collectively satisfy all of the Presentation Definition's requirements, call the `satisfiesPresentationDefinition()` method: - + This method will throw an error if all requirements of the Presentation Definition are not satisfied. @@ -61,11 +108,20 @@ This method will throw an error if all requirements of the Presentation Definiti Once you've confirmed that the VCs successfully satisfy the Presentation Definition, you can create a presentation using the `createPresentationFromCredentials()` method: - + -This method returns a `PresentationResult` which contains the presentation: -```js + + + ## Validate Presentation Submission Before submitting the presentation to a lender, you can validate the Presentation via the `validateSubmission()` method: - + This method checks the presentation submission for any errors, returns an array of `Checked` objects representing the validation checks performed on the presentation submission: @@ -125,6 +238,12 @@ Each `Checked` object contains: ## Verifiable Presentation -Once the [Presentation](/docs/glossary#verifiable-presentation) is error-free and has passed the validation checks, you can submit the Verifiable Presentation by providing the lender with the `presentation` JSON object: - + + + diff --git a/site/testsuites/testsuite-javascript/__tests__/web5/build/verifiable-credentials/presentation-exchange.test.js b/site/testsuites/testsuite-javascript/__tests__/web5/build/verifiable-credentials/presentation-exchange.test.js index 32ef2ba3a..e46f89ba2 100644 --- a/site/testsuites/testsuite-javascript/__tests__/web5/build/verifiable-credentials/presentation-exchange.test.js +++ b/site/testsuites/testsuite-javascript/__tests__/web5/build/verifiable-credentials/presentation-exchange.test.js @@ -1,24 +1,148 @@ import { test, describe, expect } from 'vitest'; import { - pex_checkPresentationDefinitionSatisfaction, pex_createPresentationFromCredentials, pex_getLoanAppPresentationDefinition, - pex_getPresentationFromResult, - pex_selectCredentials, pex_submissionCheck, } from '../../../../../../code-snippets/web5/build/verifiable-credentials/presentation-exchange'; +import { PresentationExchange } from '@web5/credentials'; -const signedEmploymentVcJwt = - 'eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCIsImtpZCI6ImRpZDprZXk6ejZNa2VyNDlDbnVnN2hzdkhEZ3Y0NHl2cGR2dE1oNHlMaURYeFM2N2huclVodHQyI3o2TWtlcjQ5Q251Zzdoc3ZIRGd2NDR5dnBkdnRNaDR5TGlEWHhTNjdobnJVaHR0MiJ9.eyJpc3MiOiJkaWQ6a2V5Ono2TWtlcjQ5Q251Zzdoc3ZIRGd2NDR5dnBkdnRNaDR5TGlEWHhTNjdobnJVaHR0MiIsInZjIjp7IkBjb250ZXh0IjpbImh0dHBzOi8vd3d3LnczLm9yZy8yMDE4L2NyZWRlbnRpYWxzL3YxIl0sInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiLCJFbXBsb3ltZW50Q3JlZGVudGlhbCJdLCJpZCI6InVybjp1dWlkOjcyNDhiOTkyLTkwOTYtNDk2NS1hMGVjLTc3ZDhhODNhMWRmYiIsImlzc3VlciI6ImRpZDprZXk6ejZNa2VyNDlDbnVnN2hzdkhEZ3Y0NHl2cGR2dE1oNHlMaURYeFM2N2huclVodHQyIiwiaXNzdWFuY2VEYXRlIjoiMjAyMy0xMi0yMVQyMDoxMToyNVoiLCJjcmVkZW50aWFsU3ViamVjdCI6eyJpZCI6ImRpZDppb246RWlEMTR4UmY0cTJNWlh1ZWY2X2ZXYnBGbVlTUG94dGFxTkp1SmdEMG96Wl84UTpleUprWld4MFlTSTZleUp3WVhSamFHVnpJanBiZXlKaFkzUnBiMjRpT2lKeVpYQnNZV05sSWl3aVpHOWpkVzFsYm5RaU9uc2ljSFZpYkdsalMyVjVjeUk2VzNzaWFXUWlPaUprZDI0dGMybG5JaXdpY0hWaWJHbGpTMlY1U25kcklqcDdJbU55ZGlJNklrVmtNalUxTVRraUxDSnJkSGtpT2lKUFMxQWlMQ0o0SWpvaWVubGFNbVYzTlhKeVVXdFVjbUV3WlZsVk16WlBTblJzTURCbFJWZHhhalZhV0dkNmNEZFpSVTVKUVNKOUxDSndkWEp3YjNObGN5STZXeUpoZFhSb1pXNTBhV05oZEdsdmJpSmRMQ0owZVhCbElqb2lTbk52YmxkbFlrdGxlVEl3TWpBaWZTeDdJbWxrSWpvaVpIZHVMV1Z1WXlJc0luQjFZbXhwWTB0bGVVcDNheUk2ZXlKamNuWWlPaUp6WldOd01qVTJhekVpTENKcmRIa2lPaUpGUXlJc0luZ2lPaUpQZDJZMFQyMUViamxKWm5SNFdYWnBkRTFHWm1jMVVXeDVMVVV6VWs1b1dsUkdPVlpFTWtnNVQzVjNJaXdpZVNJNkltUnZjVmxtV2s1c1NtRlRNVll4U201bU9HdEZObEF6VkRsd2QzaDNla3hFVTJWc1ZqTlRUa2s1U2xFaWZTd2ljSFZ5Y0c5elpYTWlPbHNpYTJWNVFXZHlaV1Z0Wlc1MElsMHNJblI1Y0dVaU9pSktjMjl1VjJWaVMyVjVNakF5TUNKOVhTd2ljMlZ5ZG1salpYTWlPbHQ3SW1sa0lqb2laSGR1SWl3aWMyVnlkbWxqWlVWdVpIQnZhVzUwSWpwN0ltVnVZM0o1Y0hScGIyNUxaWGx6SWpwYklpTmtkMjR0Wlc1aklsMHNJbTV2WkdWeklqcGJJbWgwZEhCek9pOHZaSGR1TG5SaVpHUmxkaTV2Y21jdlpIZHVOaUlzSW1oMGRIQnpPaTh2WkhkdUxuUmlaR1JsZGk1dmNtY3ZaSGR1TUNKZExDSnphV2R1YVc1blMyVjVjeUk2V3lJalpIZHVMWE5wWnlKZGZTd2lkSGx3WlNJNklrUmxZMlZ1ZEhKaGJHbDZaV1JYWldKT2IyUmxJbjFkZlgxZExDSjFjR1JoZEdWRGIyMXRhWFJ0Wlc1MElqb2lSV2xEWm05bVFUQkpVbU5uY2tWdVVHZHdRbU5RV1ZsV2VFWlliR0pTYjJRd2RVNWZRVkJwTkVrNUxVRmZRU0o5TENKemRXWm1hWGhFWVhSaElqcDdJbVJsYkhSaFNHRnphQ0k2SWtWcFFtd3pWWG80VldGT2REZGxlREJKYjJJMFJFNXNhbFJGVmpaelQwTmtjbFJ3TWxvNE5FTkJPVFJPUWtFaUxDSnlaV052ZG1WeWVVTnZiVzFwZEcxbGJuUWlPaUpGYVVOWk9WRldZbWRKYkUxemRraEZYMVJtTld4a1MxQjBkR3d3WVV4blNrdHNSbmt6Vms0d2QzQTJhVFpSSW4xOSIsImVtcGxveW1lbnRTdGF0dXMiOiJlbXBsb3llZCJ9fX0.Sazc8Ndhs-NKjxvtVMKeC9dxjEkI26fVsp2kFNWM-SYLtxMzKvl5ffeWd81ysHgPmBBSk2ar4dMqGgUsyM4gAQ'; -const signedNameAndDobVcJwt = - 'eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCIsImtpZCI6ImRpZDprZXk6ejZNa2pwUzRHVUFoYmdCSmg2azJnZTZvWTQ0UUxyRXA3NXJadHNqYVRLb3JSRGR0I3o2TWtqcFM0R1VBaGJnQkpoNmsyZ2U2b1k0NFFMckVwNzVyWnRzamFUS29yUkRkdCJ9.eyJpc3MiOiJkaWQ6a2V5Ono2TWtqcFM0R1VBaGJnQkpoNmsyZ2U2b1k0NFFMckVwNzVyWnRzamFUS29yUkRkdCIsInZjIjp7IkBjb250ZXh0IjpbImh0dHBzOi8vd3d3LnczLm9yZy8yMDE4L2NyZWRlbnRpYWxzL3YxIl0sInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiLCJOYW1lQW5kRG9iQ3JlZGVudGlhbCJdLCJpZCI6InVybjp1dWlkOjliZjM2YzY5LTI0ODAtNDllZC1iMTYyLTRlZDEwOWE3MTc3NyIsImlzc3VlciI6ImRpZDprZXk6ejZNa2pwUzRHVUFoYmdCSmg2azJnZTZvWTQ0UUxyRXA3NXJadHNqYVRLb3JSRGR0IiwiaXNzdWFuY2VEYXRlIjoiMjAyMy0xMi0yMVQyMDowNjowMVoiLCJjcmVkZW50aWFsU3ViamVjdCI6eyJpZCI6ImRpZDppb246RWlDS2o2M0FyZlBGcEpsb2lTd3gxQUhxVWtpWlNoSDZGdnZoSzRaTl9fZDFtQTpleUprWld4MFlTSTZleUp3WVhSamFHVnpJanBiZXlKaFkzUnBiMjRpT2lKeVpYQnNZV05sSWl3aVpHOWpkVzFsYm5RaU9uc2ljSFZpYkdsalMyVjVjeUk2VzNzaWFXUWlPaUprZDI0dGMybG5JaXdpY0hWaWJHbGpTMlY1U25kcklqcDdJbU55ZGlJNklrVmtNalUxTVRraUxDSnJkSGtpT2lKUFMxQWlMQ0o0SWpvaWNscFdXbTVJVkVrNWFEWkJUVmxVV0dwT01HcFhTVkYwTTI5ak4xTnJTeTF4Y2kxcVVuSTBUalEzUlNKOUxDSndkWEp3YjNObGN5STZXeUpoZFhSb1pXNTBhV05oZEdsdmJpSmRMQ0owZVhCbElqb2lTbk52YmxkbFlrdGxlVEl3TWpBaWZTeDdJbWxrSWpvaVpIZHVMV1Z1WXlJc0luQjFZbXhwWTB0bGVVcDNheUk2ZXlKamNuWWlPaUp6WldOd01qVTJhekVpTENKcmRIa2lPaUpGUXlJc0luZ2lPaUpaVDFwRE5WSmlUMHQ1T0dadVVUWTJVWEZPUkc5aldFMXZPVXhUZEdNNVYyOWthMHd0ZFZCZlExQnZJaXdpZVNJNklsWnZZM0UxVERodFozQlhXVTFrYjFwS1JrWlJUa1ZDT0hsR0xXTndkRWQzZFdkcFRWVm5hR2t6Y21jaWZTd2ljSFZ5Y0c5elpYTWlPbHNpYTJWNVFXZHlaV1Z0Wlc1MElsMHNJblI1Y0dVaU9pSktjMjl1VjJWaVMyVjVNakF5TUNKOVhTd2ljMlZ5ZG1salpYTWlPbHQ3SW1sa0lqb2laSGR1SWl3aWMyVnlkbWxqWlVWdVpIQnZhVzUwSWpwN0ltVnVZM0o1Y0hScGIyNUxaWGx6SWpwYklpTmtkMjR0Wlc1aklsMHNJbTV2WkdWeklqcGJJbWgwZEhCek9pOHZaSGR1TG5SaVpHUmxkaTV2Y21jdlpIZHVOaUlzSW1oMGRIQnpPaTh2WkhkdUxuUmlaR1JsZGk1dmNtY3ZaSGR1TUNKZExDSnphV2R1YVc1blMyVjVjeUk2V3lJalpIZHVMWE5wWnlKZGZTd2lkSGx3WlNJNklrUmxZMlZ1ZEhKaGJHbDZaV1JYWldKT2IyUmxJbjFkZlgxZExDSjFjR1JoZEdWRGIyMXRhWFJ0Wlc1MElqb2lSV2xCTXpSMlMzb3llVmswZVV4dGRDMUdabkJuYWpWbGFFRm1ZWFI1YzFOa2MwNVNWbVpMYkhwUWRqTjVkeUo5TENKemRXWm1hWGhFWVhSaElqcDdJbVJsYkhSaFNHRnphQ0k2SWtWcFF6ZGZjMXBzTW1wMVVXNUdhRVJIV1RSb2NFVTRiMlF4YVU5MWRuZG1PVFJ5TVVkbk9HMWFWbVJCVmxFaUxDSnlaV052ZG1WeWVVTnZiVzFwZEcxbGJuUWlPaUpGYVVKdU5sTnJiSEpWYzNKdVFuaFJPVXBqVXkxTlNVaGtWelYwTXpRM1MxWjNaMXBwVEZwMFQwcDRRVkYzSW4xOSIsIm5hbWUiOiJhbGljZSBib2IiLCJkYXRlT2ZCaXJ0aCI6IjEwLTAxLTE5OTAifX19.mNCDv_JntH-wZpYONKNL58UbOWaYXCYJO_HPI_WVlSgwzo6dhYmV_9qtpFKd_exFb-aaEYPeSE43twWlrJeSBg'; -const credentials = [signedEmploymentVcJwt, signedNameAndDobVcJwt]; const pd = await pex_getLoanAppPresentationDefinition(); describe('Presentation Exchange Process', () => { - test('selectCredentials() selects VCs that match presentation defintion', async () => { - const selectedCredentials = await pex_selectCredentials(credentials, pd); + const signedEmploymentVcJwt = + 'eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCIsImtpZCI6ImRpZDprZXk6ejZNa2VyNDlDbnVnN2hzdkhEZ3Y0NHl2cGR2dE1oNHlMaURYeFM2N2huclVodHQyI3o2TWtlcjQ5Q251Zzdoc3ZIRGd2NDR5dnBkdnRNaDR5TGlEWHhTNjdobnJVaHR0MiJ9.eyJpc3MiOiJkaWQ6a2V5Ono2TWtlcjQ5Q251Zzdoc3ZIRGd2NDR5dnBkdnRNaDR5TGlEWHhTNjdobnJVaHR0MiIsInZjIjp7IkBjb250ZXh0IjpbImh0dHBzOi8vd3d3LnczLm9yZy8yMDE4L2NyZWRlbnRpYWxzL3YxIl0sInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiLCJFbXBsb3ltZW50Q3JlZGVudGlhbCJdLCJpZCI6InVybjp1dWlkOjcyNDhiOTkyLTkwOTYtNDk2NS1hMGVjLTc3ZDhhODNhMWRmYiIsImlzc3VlciI6ImRpZDprZXk6ejZNa2VyNDlDbnVnN2hzdkhEZ3Y0NHl2cGR2dE1oNHlMaURYeFM2N2huclVodHQyIiwiaXNzdWFuY2VEYXRlIjoiMjAyMy0xMi0yMVQyMDoxMToyNVoiLCJjcmVkZW50aWFsU3ViamVjdCI6eyJpZCI6ImRpZDppb246RWlEMTR4UmY0cTJNWlh1ZWY2X2ZXYnBGbVlTUG94dGFxTkp1SmdEMG96Wl84UTpleUprWld4MFlTSTZleUp3WVhSamFHVnpJanBiZXlKaFkzUnBiMjRpT2lKeVpYQnNZV05sSWl3aVpHOWpkVzFsYm5RaU9uc2ljSFZpYkdsalMyVjVjeUk2VzNzaWFXUWlPaUprZDI0dGMybG5JaXdpY0hWaWJHbGpTMlY1U25kcklqcDdJbU55ZGlJNklrVmtNalUxTVRraUxDSnJkSGtpT2lKUFMxQWlMQ0o0SWpvaWVubGFNbVYzTlhKeVVXdFVjbUV3WlZsVk16WlBTblJzTURCbFJWZHhhalZhV0dkNmNEZFpSVTVKUVNKOUxDSndkWEp3YjNObGN5STZXeUpoZFhSb1pXNTBhV05oZEdsdmJpSmRMQ0owZVhCbElqb2lTbk52YmxkbFlrdGxlVEl3TWpBaWZTeDdJbWxrSWpvaVpIZHVMV1Z1WXlJc0luQjFZbXhwWTB0bGVVcDNheUk2ZXlKamNuWWlPaUp6WldOd01qVTJhekVpTENKcmRIa2lPaUpGUXlJc0luZ2lPaUpQZDJZMFQyMUViamxKWm5SNFdYWnBkRTFHWm1jMVVXeDVMVVV6VWs1b1dsUkdPVlpFTWtnNVQzVjNJaXdpZVNJNkltUnZjVmxtV2s1c1NtRlRNVll4U201bU9HdEZObEF6VkRsd2QzaDNla3hFVTJWc1ZqTlRUa2s1U2xFaWZTd2ljSFZ5Y0c5elpYTWlPbHNpYTJWNVFXZHlaV1Z0Wlc1MElsMHNJblI1Y0dVaU9pSktjMjl1VjJWaVMyVjVNakF5TUNKOVhTd2ljMlZ5ZG1salpYTWlPbHQ3SW1sa0lqb2laSGR1SWl3aWMyVnlkbWxqWlVWdVpIQnZhVzUwSWpwN0ltVnVZM0o1Y0hScGIyNUxaWGx6SWpwYklpTmtkMjR0Wlc1aklsMHNJbTV2WkdWeklqcGJJbWgwZEhCek9pOHZaSGR1TG5SaVpHUmxkaTV2Y21jdlpIZHVOaUlzSW1oMGRIQnpPaTh2WkhkdUxuUmlaR1JsZGk1dmNtY3ZaSGR1TUNKZExDSnphV2R1YVc1blMyVjVjeUk2V3lJalpIZHVMWE5wWnlKZGZTd2lkSGx3WlNJNklrUmxZMlZ1ZEhKaGJHbDZaV1JYWldKT2IyUmxJbjFkZlgxZExDSjFjR1JoZEdWRGIyMXRhWFJ0Wlc1MElqb2lSV2xEWm05bVFUQkpVbU5uY2tWdVVHZHdRbU5RV1ZsV2VFWlliR0pTYjJRd2RVNWZRVkJwTkVrNUxVRmZRU0o5TENKemRXWm1hWGhFWVhSaElqcDdJbVJsYkhSaFNHRnphQ0k2SWtWcFFtd3pWWG80VldGT2REZGxlREJKYjJJMFJFNXNhbFJGVmpaelQwTmtjbFJ3TWxvNE5FTkJPVFJPUWtFaUxDSnlaV052ZG1WeWVVTnZiVzFwZEcxbGJuUWlPaUpGYVVOWk9WRldZbWRKYkUxemRraEZYMVJtTld4a1MxQjBkR3d3WVV4blNrdHNSbmt6Vms0d2QzQTJhVFpSSW4xOSIsImVtcGxveW1lbnRTdGF0dXMiOiJlbXBsb3llZCJ9fX0.Sazc8Ndhs-NKjxvtVMKeC9dxjEkI26fVsp2kFNWM-SYLtxMzKvl5ffeWd81ysHgPmBBSk2ar4dMqGgUsyM4gAQ'; + const signedNameAndDobVcJwt = + 'eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCIsImtpZCI6ImRpZDprZXk6ejZNa2pwUzRHVUFoYmdCSmg2azJnZTZvWTQ0UUxyRXA3NXJadHNqYVRLb3JSRGR0I3o2TWtqcFM0R1VBaGJnQkpoNmsyZ2U2b1k0NFFMckVwNzVyWnRzamFUS29yUkRkdCJ9.eyJpc3MiOiJkaWQ6a2V5Ono2TWtqcFM0R1VBaGJnQkpoNmsyZ2U2b1k0NFFMckVwNzVyWnRzamFUS29yUkRkdCIsInZjIjp7IkBjb250ZXh0IjpbImh0dHBzOi8vd3d3LnczLm9yZy8yMDE4L2NyZWRlbnRpYWxzL3YxIl0sInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiLCJOYW1lQW5kRG9iQ3JlZGVudGlhbCJdLCJpZCI6InVybjp1dWlkOjliZjM2YzY5LTI0ODAtNDllZC1iMTYyLTRlZDEwOWE3MTc3NyIsImlzc3VlciI6ImRpZDprZXk6ejZNa2pwUzRHVUFoYmdCSmg2azJnZTZvWTQ0UUxyRXA3NXJadHNqYVRLb3JSRGR0IiwiaXNzdWFuY2VEYXRlIjoiMjAyMy0xMi0yMVQyMDowNjowMVoiLCJjcmVkZW50aWFsU3ViamVjdCI6eyJpZCI6ImRpZDppb246RWlDS2o2M0FyZlBGcEpsb2lTd3gxQUhxVWtpWlNoSDZGdnZoSzRaTl9fZDFtQTpleUprWld4MFlTSTZleUp3WVhSamFHVnpJanBiZXlKaFkzUnBiMjRpT2lKeVpYQnNZV05sSWl3aVpHOWpkVzFsYm5RaU9uc2ljSFZpYkdsalMyVjVjeUk2VzNzaWFXUWlPaUprZDI0dGMybG5JaXdpY0hWaWJHbGpTMlY1U25kcklqcDdJbU55ZGlJNklrVmtNalUxTVRraUxDSnJkSGtpT2lKUFMxQWlMQ0o0SWpvaWNscFdXbTVJVkVrNWFEWkJUVmxVV0dwT01HcFhTVkYwTTI5ak4xTnJTeTF4Y2kxcVVuSTBUalEzUlNKOUxDSndkWEp3YjNObGN5STZXeUpoZFhSb1pXNTBhV05oZEdsdmJpSmRMQ0owZVhCbElqb2lTbk52YmxkbFlrdGxlVEl3TWpBaWZTeDdJbWxrSWpvaVpIZHVMV1Z1WXlJc0luQjFZbXhwWTB0bGVVcDNheUk2ZXlKamNuWWlPaUp6WldOd01qVTJhekVpTENKcmRIa2lPaUpGUXlJc0luZ2lPaUpaVDFwRE5WSmlUMHQ1T0dadVVUWTJVWEZPUkc5aldFMXZPVXhUZEdNNVYyOWthMHd0ZFZCZlExQnZJaXdpZVNJNklsWnZZM0UxVERodFozQlhXVTFrYjFwS1JrWlJUa1ZDT0hsR0xXTndkRWQzZFdkcFRWVm5hR2t6Y21jaWZTd2ljSFZ5Y0c5elpYTWlPbHNpYTJWNVFXZHlaV1Z0Wlc1MElsMHNJblI1Y0dVaU9pSktjMjl1VjJWaVMyVjVNakF5TUNKOVhTd2ljMlZ5ZG1salpYTWlPbHQ3SW1sa0lqb2laSGR1SWl3aWMyVnlkbWxqWlVWdVpIQnZhVzUwSWpwN0ltVnVZM0o1Y0hScGIyNUxaWGx6SWpwYklpTmtkMjR0Wlc1aklsMHNJbTV2WkdWeklqcGJJbWgwZEhCek9pOHZaSGR1TG5SaVpHUmxkaTV2Y21jdlpIZHVOaUlzSW1oMGRIQnpPaTh2WkhkdUxuUmlaR1JsZGk1dmNtY3ZaSGR1TUNKZExDSnphV2R1YVc1blMyVjVjeUk2V3lJalpIZHVMWE5wWnlKZGZTd2lkSGx3WlNJNklrUmxZMlZ1ZEhKaGJHbDZaV1JYWldKT2IyUmxJbjFkZlgxZExDSjFjR1JoZEdWRGIyMXRhWFJ0Wlc1MElqb2lSV2xCTXpSMlMzb3llVmswZVV4dGRDMUdabkJuYWpWbGFFRm1ZWFI1YzFOa2MwNVNWbVpMYkhwUWRqTjVkeUo5TENKemRXWm1hWGhFWVhSaElqcDdJbVJsYkhSaFNHRnphQ0k2SWtWcFF6ZGZjMXBzTW1wMVVXNUdhRVJIV1RSb2NFVTRiMlF4YVU5MWRuZG1PVFJ5TVVkbk9HMWFWbVJCVmxFaUxDSnlaV052ZG1WeWVVTnZiVzFwZEcxbGJuUWlPaUpGYVVKdU5sTnJiSEpWYzNKdVFuaFJPVXBqVXkxTlNVaGtWelYwTXpRM1MxWjNaMXBwVEZwMFQwcDRRVkYzSW4xOSIsIm5hbWUiOiJhbGljZSBib2IiLCJkYXRlT2ZCaXJ0aCI6IjEwLTAxLTE5OTAifX19.mNCDv_JntH-wZpYONKNL58UbOWaYXCYJO_HPI_WVlSgwzo6dhYmV_9qtpFKd_exFb-aaEYPeSE43twWlrJeSBg'; + const credentials = [signedEmploymentVcJwt, signedNameAndDobVcJwt]; + + + const presentationDefinition = { + id: 'presDefIdloanAppVerification123', + name: 'Loan Application Employment Verification', + purpose: 'To verify applicant’s employment, date of birth, and name', + input_descriptors: [ + // Employment Verification + { + id: 'employmentVerification', + purpose: 'Confirm current employment status', + constraints: { + fields: [ + { + path: ['$.credentialSubject.employmentStatus'], + filter: { + type: 'string', + pattern: 'employed', + }, + }, + ], + }, + }, + // Date of Birth Verification + { + id: 'dobVerification', + purpose: 'Confirm the applicant’s date of birth', + constraints: { + fields: [ + { + path: ['$.credentialSubject.dateOfBirth'], + filter: { + type: 'string', + format: 'date', + }, + }, + ], + }, + }, + // Name Verification + { + id: 'nameVerification', + purpose: 'Confirm the applicant’s legal name', + constraints: { + fields: [ + { + path: ['$.credentialSubject.name'], + filter: { + type: 'string' + } + } + ] + } + } + ] + }; + + test('getLoanAppPresentationDefinition returns a presentation definition', async () => { + // :snippet-start: getLoanAppPresentationDefinition + const presentationDefinition = { + id: 'presDefIdloanAppVerification123', + name: 'Loan Application Employment Verification', + purpose: 'To verify applicant’s employment, date of birth, and name', + input_descriptors: [ + // Employment Verification + { + id: 'employmentVerification', + purpose: 'Confirm current employment status', + constraints: { + fields: [ + { + path: ['$.credentialSubject.employmentStatus'], + filter: { + type: 'string', + pattern: 'employed', + }, + }, + ], + }, + }, + // Date of Birth Verification + { + id: 'dobVerification', + purpose: 'Confirm the applicant’s date of birth', + constraints: { + fields: [ + { + path: ['$.credentialSubject.dateOfBirth'], + filter: { + type: 'string', + format: 'date', + }, + }, + ], + }, + }, + // Name Verification + { + id: 'nameVerification', + purpose: 'Confirm the applicant’s legal name', + constraints: { + fields: [ + { + path: ['$.credentialSubject.name'], + filter: { + type: 'string' + } + } + ] + } + } + ] + }; + // :snippet-end: + expect(presentationDefinition).toBeDefined(); + expect(presentationDefinition).toHaveProperty('input_descriptors'); + expect(presentationDefinition.input_descriptors).toBeInstanceOf(Array); + expect(presentationDefinition.input_descriptors.length).toBe(3); + }); + test('selectCredentialsForPex selects VCs that match presentation defintion', async () => { + const allCredentials = credentials + // :snippet-start: selectCredentialsForPex + const selectedCredentials = PresentationExchange.selectCredentials({ + vcJwts: allCredentials, + presentationDefinition: presentationDefinition + }); + // :snippet-end: + expect(selectedCredentials).toBeDefined(); expect(selectedCredentials).toBeInstanceOf(Array); expect.soft(selectedCredentials.length).toBe(2); @@ -26,47 +150,64 @@ describe('Presentation Exchange Process', () => { expect.soft(selectedCredentials).toContain(signedNameAndDobVcJwt); }); - test('satisfiesPresentationDefinition() checks if VCs satisfy PD', async () => { - const satisfied = await pex_checkPresentationDefinitionSatisfaction( - credentials, - pd, - ); - expect(satisfied).toBe(true); + test('satisfiesPresentationDefinitionForPex checks if VCs satisfy PD', async () => { + const selectedCredentials = credentials + expect(() => { + // :snippet-start: satisfiesPresentationDefinitionForPex + try { + PresentationExchange.satisfiesPresentationDefinition({ + vcJwts: selectedCredentials, + presentationDefinition: presentationDefinition + }); + } catch (err) { + //Handle errors here + + } + // :snippet-end: + }).not.toThrow(); }); - test('createPresentationFromCredentials() creates a presentation result', async () => { - const presentationResult = await pex_createPresentationFromCredentials( - credentials, - pd, - ); + test('createPresentationFromCredentialsForPex creates a presentation result', async () => { + const selectedCredentials = credentials + // :snippet-start: createPresentationFromCredentialsForPex + const presentationResult = PresentationExchange.createPresentationFromCredentials({ + vcJwts: selectedCredentials, + presentationDefinition: presentationDefinition + }); + // :snippet-end: expect(presentationResult).toBeDefined(); - expect.soft(presentationResult).toHaveProperty('presentation'); - expect - .soft(presentationResult.presentation) - .toHaveProperty('presentation_submission'); - expect - .soft(presentationResult.presentation) - .toHaveProperty('verifiableCredential'); - expect - .soft(presentationResult.presentation.type) - .toContain('VerifiablePresentation'); - }); + expect(presentationResult).toHaveProperty('presentation'); + expect(presentationResult.presentation).toHaveProperty('presentation_submission'); + expect(presentationResult.presentation).toHaveProperty('verifiableCredential'); + expect(presentationResult.presentation.type).toContain('VerifiablePresentation'); + } + ); - test('validateSubmission() checks if the presentation submission is valid', async () => { - const pr = await pex_createPresentationFromCredentials(credentials, pd); - const validationResult = await pex_submissionCheck(pr); - expect(validationResult).toBeDefined(); - expect(validationResult).toBeInstanceOf(Array); - expect(validationResult.length).toBe(1); - expect.soft(validationResult[0]).toHaveProperty('tag', 'root'); - expect.soft(validationResult[0]).toHaveProperty('status', 'info'); - expect.soft(validationResult[0]).toHaveProperty('message', 'ok'); + test('validPresentationSubmissionForPex check if the presention submission is valid', async () => { + const presentationResult = await pex_createPresentationFromCredentials(credentials, pd); + // :snippet-start: validPresentationSubmissionForPex + const submissionCheck = PresentationExchange.validateSubmission({ + presentationSubmission: presentationResult.presentationSubmission + }); + // :snippet-end: + expect(submissionCheck.length).toBe(1); + expect.soft(submissionCheck[0]).toHaveProperty('tag', 'root'); + expect.soft(submissionCheck[0]).toHaveProperty('status', 'info'); + expect.soft(submissionCheck[0]).toHaveProperty('message', 'ok'); }); - test('presentationResult.presentation is a valid VP', async () => { - const pr = await pex_createPresentationFromCredentials(credentials, pd); - const presentation = await pex_getPresentationFromResult(pr); + test('validVerifiablePresentationForPex creates a valid VP', async () => { + const selectedCredentials = credentials + const presentationResult = PresentationExchange.createPresentationFromCredentials({ + vcJwts: selectedCredentials, + presentationDefinition: presentationDefinition + }); + // :snippet-start: validVerifiablePresentationForPex + const presentation = presentationResult.presentation; + // :snippet-end: + expect(presentation).toBeDefined(); expect(presentation.type).contains('VerifiablePresentation'); }); + }); diff --git a/site/testsuites/testsuite-kotlin/pom.xml b/site/testsuites/testsuite-kotlin/pom.xml index e050e9172..72bea8bf3 100644 --- a/site/testsuites/testsuite-kotlin/pom.xml +++ b/site/testsuites/testsuite-kotlin/pom.xml @@ -32,7 +32,7 @@ Will eventually go bye-bye once the underlying dep trees are fixed up --> - 2.9.8 + 2.12.6 diff --git a/site/testsuites/testsuite-kotlin/src/test/kotlin/docs/web5/build/verifiablecredentials/PresentationExchangeTest.kt b/site/testsuites/testsuite-kotlin/src/test/kotlin/docs/web5/build/verifiablecredentials/PresentationExchangeTest.kt new file mode 100644 index 000000000..f75804024 --- /dev/null +++ b/site/testsuites/testsuite-kotlin/src/test/kotlin/docs/web5/build/verifiablecredentials/PresentationExchangeTest.kt @@ -0,0 +1,168 @@ +package website.tbd.developer.site.docs.web5.build.decentralizedidentifiers; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Assertions.* +import web5.sdk.crypto.InMemoryKeyManager +import web5.sdk.credentials.PresentationExchange +import web5.sdk.credentials.VerifiableCredential +import web5.sdk.credentials.VerifiablePresentation +import web5.sdk.credentials.model.* + +/** + * Tests backing the Presentation Exchange Guide + */ +internal class PresentationExchangeTest { + val signedEmploymentVcJwt = "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCIsImtpZCI6ImRpZDprZXk6ejZNa2VyNDlDbnVnN2hzdkhEZ3Y0NHl2cGR2dE1oNHlMaURYeFM2N2huclVodHQyI3o2TWtlcjQ5Q251Zzdoc3ZIRGd2NDR5dnBkdnRNaDR5TGlEWHhTNjdobnJVaHR0MiJ9.eyJpc3MiOiJkaWQ6a2V5Ono2TWtlcjQ5Q251Zzdoc3ZIRGd2NDR5dnBkdnRNaDR5TGlEWHhTNjdobnJVaHR0MiIsInZjIjp7IkBjb250ZXh0IjpbImh0dHBzOi8vd3d3LnczLm9yZy8yMDE4L2NyZWRlbnRpYWxzL3YxIl0sInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiLCJFbXBsb3ltZW50Q3JlZGVudGlhbCJdLCJpZCI6InVybjp1dWlkOjcyNDhiOTkyLTkwOTYtNDk2NS1hMGVjLTc3ZDhhODNhMWRmYiIsImlzc3VlciI6ImRpZDprZXk6ejZNa2VyNDlDbnVnN2hzdkhEZ3Y0NHl2cGR2dE1oNHlMaURYeFM2N2huclVodHQyIiwiaXNzdWFuY2VEYXRlIjoiMjAyMy0xMi0yMVQyMDoxMToyNVoiLCJjcmVkZW50aWFsU3ViamVjdCI6eyJpZCI6ImRpZDppb246RWlEMTR4UmY0cTJNWlh1ZWY2X2ZXYnBGbVlTUG94dGFxTkp1SmdEMG96Wl84UTpleUprWld4MFlTSTZleUp3WVhSamFHVnpJanBiZXlKaFkzUnBiMjRpT2lKeVpYQnNZV05sSWl3aVpHOWpkVzFsYm5RaU9uc2ljSFZpYkdsalMyVjVjeUk2VzNzaWFXUWlPaUprZDI0dGMybG5JaXdpY0hWaWJHbGpTMlY1U25kcklqcDdJbU55ZGlJNklrVmtNalUxTVRraUxDSnJkSGtpT2lKUFMxQWlMQ0o0SWpvaWVubGFNbVYzTlhKeVVXdFVjbUV3WlZsVk16WlBTblJzTURCbFJWZHhhalZhV0dkNmNEZFpSVTVKUVNKOUxDSndkWEp3YjNObGN5STZXeUpoZFhSb1pXNTBhV05oZEdsdmJpSmRMQ0owZVhCbElqb2lTbk52YmxkbFlrdGxlVEl3TWpBaWZTeDdJbWxrSWpvaVpIZHVMV1Z1WXlJc0luQjFZbXhwWTB0bGVVcDNheUk2ZXlKamNuWWlPaUp6WldOd01qVTJhekVpTENKcmRIa2lPaUpGUXlJc0luZ2lPaUpQZDJZMFQyMUViamxKWm5SNFdYWnBkRTFHWm1jMVVXeDVMVVV6VWs1b1dsUkdPVlpFTWtnNVQzVjNJaXdpZVNJNkltUnZjVmxtV2s1c1NtRlRNVll4U201bU9HdEZObEF6VkRsd2QzaDNla3hFVTJWc1ZqTlRUa2s1U2xFaWZTd2ljSFZ5Y0c5elpYTWlPbHNpYTJWNVFXZHlaV1Z0Wlc1MElsMHNJblI1Y0dVaU9pSktjMjl1VjJWaVMyVjVNakF5TUNKOVhTd2ljMlZ5ZG1salpYTWlPbHQ3SW1sa0lqb2laSGR1SWl3aWMyVnlkbWxqWlVWdVpIQnZhVzUwSWpwN0ltVnVZM0o1Y0hScGIyNUxaWGx6SWpwYklpTmtkMjR0Wlc1aklsMHNJbTV2WkdWeklqcGJJbWgwZEhCek9pOHZaSGR1TG5SaVpHUmxkaTV2Y21jdlpIZHVOaUlzSW1oMGRIQnpPaTh2WkhkdUxuUmlaR1JsZGk1dmNtY3ZaSGR1TUNKZExDSnphV2R1YVc1blMyVjVjeUk2V3lJalpIZHVMWE5wWnlKZGZTd2lkSGx3WlNJNklrUmxZMlZ1ZEhKaGJHbDZaV1JYWldKT2IyUmxJbjFkZlgxZExDSjFjR1JoZEdWRGIyMXRhWFJ0Wlc1MElqb2lSV2xEWm05bVFUQkpVbU5uY2tWdVVHZHdRbU5RV1ZsV2VFWlliR0pTYjJRd2RVNWZRVkJwTkVrNUxVRmZRU0o5TENKemRXWm1hWGhFWVhSaElqcDdJbVJsYkhSaFNHRnphQ0k2SWtWcFFtd3pWWG80VldGT2REZGxlREJKYjJJMFJFNXNhbFJGVmpaelQwTmtjbFJ3TWxvNE5FTkJPVFJPUWtFaUxDSnlaV052ZG1WeWVVTnZiVzFwZEcxbGJuUWlPaUpGYVVOWk9WRldZbWRKYkUxemRraEZYMVJtTld4a1MxQjBkR3d3WVV4blNrdHNSbmt6Vms0d2QzQTJhVFpSSW4xOSIsImVtcGxveW1lbnRTdGF0dXMiOiJlbXBsb3llZCJ9fX0.Sazc8Ndhs-NKjxvtVMKeC9dxjEkI26fVsp2kFNWM-SYLtxMzKvl5ffeWd81ysHgPmBBSk2ar4dMqGgUsyM4gAQ" + val signedNameAndDobVcJwt = "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCIsImtpZCI6ImRpZDprZXk6ejZNa2pwUzRHVUFoYmdCSmg2azJnZTZvWTQ0UUxyRXA3NXJadHNqYVRLb3JSRGR0I3o2TWtqcFM0R1VBaGJnQkpoNmsyZ2U2b1k0NFFMckVwNzVyWnRzamFUS29yUkRkdCJ9.eyJpc3MiOiJkaWQ6a2V5Ono2TWtqcFM0R1VBaGJnQkpoNmsyZ2U2b1k0NFFMckVwNzVyWnRzamFUS29yUkRkdCIsInZjIjp7IkBjb250ZXh0IjpbImh0dHBzOi8vd3d3LnczLm9yZy8yMDE4L2NyZWRlbnRpYWxzL3YxIl0sInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiLCJOYW1lQW5kRG9iQ3JlZGVudGlhbCJdLCJpZCI6InVybjp1dWlkOjliZjM2YzY5LTI0ODAtNDllZC1iMTYyLTRlZDEwOWE3MTc3NyIsImlzc3VlciI6ImRpZDprZXk6ejZNa2pwUzRHVUFoYmdCSmg2azJnZTZvWTQ0UUxyRXA3NXJadHNqYVRLb3JSRGR0IiwiaXNzdWFuY2VEYXRlIjoiMjAyMy0xMi0yMVQyMDowNjowMVoiLCJjcmVkZW50aWFsU3ViamVjdCI6eyJpZCI6ImRpZDppb246RWlDS2o2M0FyZlBGcEpsb2lTd3gxQUhxVWtpWlNoSDZGdnZoSzRaTl9fZDFtQTpleUprWld4MFlTSTZleUp3WVhSamFHVnpJanBiZXlKaFkzUnBiMjRpT2lKeVpYQnNZV05sSWl3aVpHOWpkVzFsYm5RaU9uc2ljSFZpYkdsalMyVjVjeUk2VzNzaWFXUWlPaUprZDI0dGMybG5JaXdpY0hWaWJHbGpTMlY1U25kcklqcDdJbU55ZGlJNklrVmtNalUxTVRraUxDSnJkSGtpT2lKUFMxQWlMQ0o0SWpvaWNscFdXbTVJVkVrNWFEWkJUVmxVV0dwT01HcFhTVkYwTTI5ak4xTnJTeTF4Y2kxcVVuSTBUalEzUlNKOUxDSndkWEp3YjNObGN5STZXeUpoZFhSb1pXNTBhV05oZEdsdmJpSmRMQ0owZVhCbElqb2lTbk52YmxkbFlrdGxlVEl3TWpBaWZTeDdJbWxrSWpvaVpIZHVMV1Z1WXlJc0luQjFZbXhwWTB0bGVVcDNheUk2ZXlKamNuWWlPaUp6WldOd01qVTJhekVpTENKcmRIa2lPaUpGUXlJc0luZ2lPaUpaVDFwRE5WSmlUMHQ1T0dadVVUWTJVWEZPUkc5aldFMXZPVXhUZEdNNVYyOWthMHd0ZFZCZlExQnZJaXdpZVNJNklsWnZZM0UxVERodFozQlhXVTFrYjFwS1JrWlJUa1ZDT0hsR0xXTndkRWQzZFdkcFRWVm5hR2t6Y21jaWZTd2ljSFZ5Y0c5elpYTWlPbHNpYTJWNVFXZHlaV1Z0Wlc1MElsMHNJblI1Y0dVaU9pSktjMjl1VjJWaVMyVjVNakF5TUNKOVhTd2ljMlZ5ZG1salpYTWlPbHQ3SW1sa0lqb2laSGR1SWl3aWMyVnlkbWxqWlVWdVpIQnZhVzUwSWpwN0ltVnVZM0o1Y0hScGIyNUxaWGx6SWpwYklpTmtkMjR0Wlc1aklsMHNJbTV2WkdWeklqcGJJbWgwZEhCek9pOHZaSGR1TG5SaVpHUmxkaTV2Y21jdlpIZHVOaUlzSW1oMGRIQnpPaTh2WkhkdUxuUmlaR1JsZGk1dmNtY3ZaSGR1TUNKZExDSnphV2R1YVc1blMyVjVjeUk2V3lJalpIZHVMWE5wWnlKZGZTd2lkSGx3WlNJNklrUmxZMlZ1ZEhKaGJHbDZaV1JYWldKT2IyUmxJbjFkZlgxZExDSjFjR1JoZEdWRGIyMXRhWFJ0Wlc1MElqb2lSV2xCTXpSMlMzb3llVmswZVV4dGRDMUdabkJuYWpWbGFFRm1ZWFI1YzFOa2MwNVNWbVpMYkhwUWRqTjVkeUo5TENKemRXWm1hWGhFWVhSaElqcDdJbVJsYkhSaFNHRnphQ0k2SWtWcFF6ZGZjMXBzTW1wMVVXNUdhRVJIV1RSb2NFVTRiMlF4YVU5MWRuZG1PVFJ5TVVkbk9HMWFWbVJCVmxFaUxDSnlaV052ZG1WeWVVTnZiVzFwZEcxbGJuUWlPaUpGYVVKdU5sTnJiSEpWYzNKdVFuaFJPVXBqVXkxTlNVaGtWelYwTXpRM1MxWjNaMXBwVEZwMFQwcDRRVkYzSW4xOSIsIm5hbWUiOiJhbGljZSBib2IiLCJkYXRlT2ZCaXJ0aCI6IjEwLTAxLTE5OTAifX19.mNCDv_JntH-wZpYONKNL58UbOWaYXCYJO_HPI_WVlSgwzo6dhYmV_9qtpFKd_exFb-aaEYPeSE43twWlrJeSBg" + val allCredentials = listOf(signedEmploymentVcJwt, signedNameAndDobVcJwt) + + val presentationDefinition = PresentationDefinitionV2( + id = "presDefIdloanAppVerification123", + name = "Loan Application Employment Verification", + purpose = "To verify applicant’s employment, date of birth, and name", + inputDescriptors = listOf( + // Employment Verification + InputDescriptorV2( + id = "employmentVerification", + purpose = "Confirm current employment status", + constraints = ConstraintsV2( + fields = listOf(FieldV2(path = listOf("$.vc.credentialSubject.employmentStatus"))) + ) + ), + // Date of Birth Verification + InputDescriptorV2( + id = "dobVerification", + purpose = "Confirm the applicant’s date of birth", + constraints = ConstraintsV2( + fields = listOf(FieldV2(path = listOf("$.vc.credentialSubject.dateOfBirth"))) + ) + ), + // Name Verification + InputDescriptorV2( + id = "nameVerification", + purpose = "Confirm the applicant’s legal name", + constraints = ConstraintsV2( + fields = listOf(FieldV2(path = listOf("$.vc.credentialSubject.name"))) + ) + ) + ) +) + + @Test + fun `getLoanAppPresentationDefinitionKt `() { + // :snippet-start: getLoanAppPresentationDefinitionKt + val presentationDefinition = PresentationDefinitionV2( + id = "presDefIdloanAppVerification123", + name = "Loan Application Employment Verification", + purpose = "To verify applicant’s employment, date of birth, and name", + inputDescriptors = listOf( + // Employment Verification + InputDescriptorV2( + id = "employmentVerification", + purpose = "Confirm current employment status", + constraints = ConstraintsV2( + fields = listOf(FieldV2(path = listOf("$.vc.credentialSubject.employmentStatus"))) + ) + ), + // Date of Birth Verification + InputDescriptorV2( + id = "dobVerification", + purpose = "Confirm the applicant’s date of birth", + constraints = ConstraintsV2( + fields = listOf(FieldV2(path = listOf("$.vc.credentialSubject.dateOfBirth"))) + ) + ), + // Name Verification + InputDescriptorV2( + id = "nameVerification", + purpose = "Confirm the applicant’s legal name", + constraints = ConstraintsV2( + fields = listOf(FieldV2(path = listOf("$.vc.credentialSubject.name"))) + ) + ) + ) + ) + // :snippet-end: + + assertEquals("presDefIdloanAppVerification123", presentationDefinition.id) + assertEquals("Loan Application Employment Verification", presentationDefinition.name) + assertEquals("To verify applicant’s employment, date of birth, and name", presentationDefinition.purpose) + assertEquals(3, presentationDefinition.inputDescriptors.size) + } + + @Test + fun `selectCredentialsForPexKt selects VCs that match presentation defintion`() { + // :snippet-start: selectCredentialsForPexKt + val selectedCredentials = PresentationExchange.selectCredentials( + vcJwts = allCredentials, + presentationDefinition = presentationDefinition + ) + // :snippet-end: + assertNotNull(selectedCredentials, "Selected credentials should not be null") + assertTrue(selectedCredentials is List<*>, "Selected credentials should be a list") + assertEquals(2, selectedCredentials.size, "Selected credentials should contain 2 items") + assertTrue(signedEmploymentVcJwt in selectedCredentials, "Selected credentials should contain the employment VC JWT") + assertTrue(signedNameAndDobVcJwt in selectedCredentials, "Selected credentials should contain the name and DOB VC JWT") + } + + @Test + fun `satisfiesPresentationDefinitionForPexKt checks if VCs satisfy PD`() { + val selectedCredentials = allCredentials + assertDoesNotThrow { + // :snippet-start: satisfiesPresentationDefinitionForPexKt + try { + PresentationExchange.satisfiesPresentationDefinition( + vcJwts = selectedCredentials, + presentationDefinition = presentationDefinition + ) + } catch (e: Exception) { + // Handle errors here + } + // :snippet-end: + } + } + + @Test + fun `createPresentationFromCredentialsForPexKt creates a presentation result`() { + val holderDid = "did:key:zQ3shXrAnbgfytQYQjifUm2EcBBbRAeAeGfgC4TZrjw4X71iZ" + val selectedCredentials = allCredentials + // :snippet-start: createPresentationFromCredentialsForPexKt + val presentationResult = PresentationExchange.createPresentationFromCredentials( + vcJwts = selectedCredentials, + presentationDefinition = presentationDefinition + ) + + val verifiablePresentation = VerifiablePresentation.create( + vcJwts = selectedCredentials, + holder = holderDid, + additionalData = mapOf("presentation_submission" to presentationResult) + ) + // :snippet-end: + assertNotNull(verifiablePresentation, "Verifiable Presentation should not be null") + assertEquals(holderDid, verifiablePresentation.holder, "Holder DID should match") + } + + @Test + fun `validVerifiablePresentationForPexKt creates a valid VP`() { + val holderDid = "did:key:zQ3shXrAnbgfytQYQjifUm2EcBBbRAeAeGfgC4TZrjw4X71iZ" + val selectedCredentials = allCredentials + val presentationResult = PresentationExchange.createPresentationFromCredentials( + vcJwts = selectedCredentials, + presentationDefinition = presentationDefinition + ) + val verifiablePresentation = VerifiablePresentation.create( + vcJwts = selectedCredentials, + holder = holderDid, + additionalData = mapOf("presentation_submission" to presentationResult) + ) + // :snippet-start: validVerifiablePresentationForPexKt + val verifiablePresentationDataModelMap = verifiablePresentation.vpDataModel.toMap() + val mappedPresentationSubmission = verifiablePresentationDataModelMap["presentation_submission"] as? PresentationSubmission + // :snippet-end: + + assertNotNull(mappedPresentationSubmission, "Mapped Presentation Submission should not be null") + assertEquals(presentationResult.definitionId, mappedPresentationSubmission?.definitionId, "Definition ID should match") + } +} + + From 0f73914a9eeed73be35970c8a19d1abf6c285716 Mon Sep 17 00:00:00 2001 From: Angie Jones Date: Tue, 6 Feb 2024 16:40:55 -0600 Subject: [PATCH 26/31] Removing sidebar link to JS API Guide (#1211) --- site/docs/web5/api_guide.mdx | 10 ---------- 1 file changed, 10 deletions(-) delete mode 100644 site/docs/web5/api_guide.mdx diff --git a/site/docs/web5/api_guide.mdx b/site/docs/web5/api_guide.mdx deleted file mode 100644 index 7c9d44044..000000000 --- a/site/docs/web5/api_guide.mdx +++ /dev/null @@ -1,10 +0,0 @@ ---- -sidebar_position: 1 -title: API Reference ---- - -import {Redirect} from '@docusaurus/router'; - -const Home = () => { - return ; -}; From cd81cf0a406c29bb11a61f9fa14f898c313beed4 Mon Sep 17 00:00:00 2001 From: Andrew Lee Rubinger Date: Tue, 6 Feb 2024 15:25:31 -0800 Subject: [PATCH 27/31] Issue #1197 - Update to locked tbdex-kt:0.9.0-beta off former SNAPSHOT --- site/testsuites/testsuite-kotlin/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/testsuites/testsuite-kotlin/pom.xml b/site/testsuites/testsuite-kotlin/pom.xml index 72bea8bf3..826c6865f 100644 --- a/site/testsuites/testsuite-kotlin/pom.xml +++ b/site/testsuites/testsuite-kotlin/pom.xml @@ -25,7 +25,7 @@ These need to be uniformly updated as part of the single dependency script from Nick --> - 0.9.0-SNAPSHOT + 0.9.0-beta