Skip to content

Commit

Permalink
feat: rendering process to handle credentials using enveloping proof (#…
Browse files Browse the repository at this point in the history
…218)

<!--
  For Work In Progress Pull Requests, please use the Draft PR feature,
see https://github.blog/2019-02-14-introducing-draft-pull-requests/ for
further details.
  
  For a timely review/response, please avoid force-pushing additional
  commits if your PR already received reviews or comments.
  
Before submitting a Pull Request, please ensure you've done the
following:
- 📖 Read the [Contributing
Guide](https://github.com/uncefact/project-vckit/blob/main/CONTRIBUTING.md).
- 📖 Read the [Code of
Conduct](https://github.com/uncefact/project-vckit/blob/main/CODE_OF_CONDUCT.md).
  - 👷‍♀️ Create small PRs. In most cases, this will be possible.
  - ✅ Provide tests for your changes.
- 📝 Use descriptive commit messages following [conventional
commits](https://www.conventionalcommits.org/en/v1.0.0/).
- 📗 Update any related documentation and include any relevant
screenshots.
-->

## What type of PR is this? (check all applicable)

- [x] 🍕 Feature
- [ ] 🐛 Bug Fix
- [ ] 📝 Documentation Update
- [ ] 🎨 Style
- [ ] 🧑‍💻 Code Refactor
- [ ] 🔥 Performance Improvements
- [ ] ✅ Test
- [ ] 🤖 Build
- [ ] 🔁 CI
- [ ] 📦 Chore (Release)
- [ ] ⏩ Revert

## Description

<!-- 
Please do not leave this blank 
This PR [adds/removes/fixes/replaces] the [feature/bug/etc]. 
-->

## Related Tickets & Documents
<!-- 
Please use this format link issue numbers: Fixes #123

https://docs.github.com/en/free-pro-team@latest/github/managing-your-work-on-github/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword
-->
<img width="878" alt="image"
src="https://github.com/user-attachments/assets/c1ccdf6e-4820-47c2-a471-c76f8f642c11">
<img width="880" alt="image"
src="https://github.com/user-attachments/assets/e754112c-80ff-4458-bcb3-ebcfee91573f">

## Mobile & Desktop Screenshots/Recordings

<!-- Visual changes require screenshots -->


## Added tests?

- [ ] 👍 yes
- [ ] 🙅 no, because they aren't needed
- [ ] 🙋 no, because I need help

## Added to documentation?

- [ ] 📜 README.md
- [ ] 📓 [vc-kit doc site](https://uncefact.github.io/vckit/)
- [ ] 📕 storybook
- [ ] 🙅 no documentation needed

## [optional] Are there any post-deployment tasks we need to perform?


<!-- note: PRs with deleted sections will be marked invalid -->
  • Loading branch information
ldhyen99 authored Oct 1, 2024
1 parent 2527fdb commit 54d6dfb
Show file tree
Hide file tree
Showing 8 changed files with 107 additions and 12 deletions.
2 changes: 2 additions & 0 deletions packages/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@
"@veramo/url-handler": "5.5.3",
"@veramo/utils": "5.5.3",
"blessed": "^0.1.81",
"body-parser": "^1.20.3",
"commander": "^11.1.0",
"console-table-printer": "^2.12.0",
"cors": "^2.8.5",
Expand Down Expand Up @@ -110,6 +111,7 @@
"yaml": "^2.3.4"
},
"devDependencies": {
"@types/body-parser": "^1.19.5",
"@types/debug": "4.1.12",
"@types/express": "4.17.21",
"@types/inquirer": "9.0.7",
Expand Down
3 changes: 3 additions & 0 deletions packages/cli/src/server.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import express from 'express'
import { Command } from 'commander'
import bodyParser from 'body-parser'
import { getConfig } from './setup.js'
import { createObjects } from './lib/objectCreator.js'

Expand All @@ -8,6 +9,8 @@ const server = new Command('server')
.option('-p, --port <number>', 'Optionally set port to override config')
.action(async (opts: { port: number }, cmd: Command) => {
const app = express()
app.use(bodyParser.json({ limit: '50mb' }));
app.use(bodyParser.urlencoded({ limit: '50mb', extended: true }));

let server: any

Expand Down
17 changes: 16 additions & 1 deletion packages/core-types/src/plugin.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -6020,7 +6020,7 @@
"credential": {
"anyOf": [
{
"$ref": "#/components/schemas/VerifiableCredential"
"$ref": "#/components/schemas/W3CVerifiableCredential"
},
{
"$ref": "#/components/schemas/UnsignedCredential"
Expand All @@ -6033,6 +6033,17 @@
],
"description": "Arguments for rendering a verifiable credential."
},
"W3CVerifiableCredential": {
"anyOf": [
{
"$ref": "#/components/schemas/VerifiableCredential"
},
{
"$ref": "#/components/schemas/CompactJWT"
}
],
"description": "Represents a signed Verifiable Credential (includes proof), in either JSON or compact JWT format. See {@link https://www.w3.org/TR/vc-data-model/#credentials | VC data model } See {@link https://www.w3.org/TR/vc-data-model/#proof-formats | proof formats }"
},
"VerifiableCredential": {
"type": "object",
"properties": {
Expand Down Expand Up @@ -6160,6 +6171,10 @@
],
"description": "Used for the discovery of information about the current status of a verifiable credential, such as whether it is suspended or revoked. The precise contents of the credential status information is determined by the specific `credentialStatus` type definition, and varies depending on factors such as whether it is simple to implement or if it is privacy-enhancing.\n\nSee {@link https://www.w3.org/TR/vc-data-model/#status | Credential Status }"
},
"CompactJWT": {
"type": "string",
"description": "Represents a Json Web Token in compact form. \"header.payload.signature\""
},
"UnsignedCredential": {
"type": "object",
"properties": {
Expand Down
6 changes: 3 additions & 3 deletions packages/core-types/src/types/IRender.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ import { IDIDManager } from './IDIDManager';
import { IDataStore } from './IDataStore';
import { IKeyManager } from './IKeyManager';
import { IResolver } from './IResolver';
import { UnsignedCredential, VerifiableCredential } from './vc-data-model';
import { UnsignedCredential, W3CVerifiableCredential } from './vc-data-model';

/**
* Arguments for rendering a verifiable credential.
* @public
*/
export interface IRenderCredentialArgs {
credential: VerifiableCredential | UnsignedCredential;
credential: W3CVerifiableCredential | UnsignedCredential;
}

/**
Expand All @@ -32,7 +32,7 @@ export type IRendererContext = IAgentContext<
* Result of rendering a verifiable credential.
* @beta
*/
export interface IRenderDocument{
export interface IRenderDocument {
type: string;
renderedTemplate: string;
name?: string;
Expand Down
25 changes: 25 additions & 0 deletions packages/renderer/__tests__/renderer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -335,4 +335,29 @@ describe('Renderer', () => {
},
]);
});

it('should render a verifiable credential with JWT - Enveloping Proof Jose', async () => {
// Mock data
const args: IRenderCredentialArgs = {
credential:
'eyJhbGciOiJFZERTQSIsImlzcyI6ImRpZDp3ZWI6ZDVmNi0xMTYtMTA2LTE5Mi0yMTUubmdyb2stZnJlZS5hcHAiLCJ0eXAiOiJ2Yy1sZCtqd3QifQ.eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvbnMvY3JlZGVudGlhbHMvdjIiLCJodHRwczovL3d3dy53My5vcmcvbnMvY3JlZGVudGlhbHMvZXhhbXBsZXMvdjIiLCJodHRwczovL2Rldi1yZW5kZXItbWV0aG9kLWNvbnRleHQuczMuYXAtc291dGhlYXN0LTEuYW1hem9uYXdzLmNvbS9kZXYtcmVuZGVyLW1ldGhvZC1jb250ZXh0Lmpzb24iXSwiaWQiOiJodHRwOi8vdW5pdmVyc2l0eS5leGFtcGxlL2NyZWRlbnRpYWxzLzE4NzIiLCJ0eXBlIjpbIlZlcmlmaWFibGVDcmVkZW50aWFsIiwiRXhhbXBsZUFsdW1uaUNyZWRlbnRpYWwiXSwiaXNzdWVyIjoiZGlkOndlYjpkNWY2LTExNi0xMDYtMTkyLTIxNS5uZ3Jvay1mcmVlLmFwcCIsInZhbGlkRnJvbSI6IjIwMTAtMDEtMDFUMTk6MjM6MjRaIiwiY3JlZGVudGlhbFNjaGVtYSI6eyJpZCI6Imh0dHBzOi8vZXhhbXBsZS5vcmcvZXhhbXBsZXMvZGVncmVlLmpzb24iLCJ0eXBlIjoiSnNvblNjaGVtYSJ9LCJjcmVkZW50aWFsU3ViamVjdCI6eyJpZCI6ImRpZDpleGFtcGxlOjEyMyIsImRlZ3JlZSI6eyJ0eXBlIjoiQmFjaGVsb3JEZWdyZWUiLCJuYW1lIjoiQmFjaGVsb3Igb2YgU2NpZW5jZSBhbmQgQXJ0cyJ9fSwicmVuZGVyIjpbeyJ0ZW1wbGF0ZSI6IlBHUnBkaUJ6ZEhsc1pUMGlkMmxrZEdnNk16QXdjSGc3SUdobGFXZG9kRG94TURCd2VEc2dZbTl5WkdWeU9pQXljSGdnYzI5c2FXUWdZbXhoWTJzN0lIUmxlSFF0WVd4cFoyNDZZMlZ1ZEdWeUlqNEtJQ0E4WkdsMlBnb2dJQ0FnVkdocGN5QkNZV05vWld4dmNpQnZaaUJUWTJsbGJtTmxJR0Z1WkNCQmNuUnpJR2x6SUdOdmJtWmxjbkpsWkNCMGJ3b2dJRHd2WkdsMlBnb2dJRHh6ZEhKdmJtY2djM1I1YkdVOUltWnZiblF0YzJsNlpUb2dNVFp3ZUNJK0NpQWdJQ0JLWVc1bElGTnRhWFJvQ2lBZ1BDOXpkSEp2Ym1jK0NpQWdQR1JwZGo0S0lDQWdJR0o1SUVWNFlXMXdiR1VnVlc1cGRtVnljMmwwZVM0S0lDQThMMlJwZGo0S1BDOWthWFkrIiwiQHR5cGUiOiJXZWJSZW5kZXJpbmdUZW1wbGF0ZTIwMjIifV0sImlzc3VhbmNlRGF0ZSI6IjIwMjQtMDktMzBUMDg6MzE6MTYuODg4WiJ9.UFC7Zxk3sAqef5Rs7oJxDwv304TTNPQHV1xBr2sgWg-xpZBAfmFpXcxoYvxEf80I__c3TwI95GnFH9C7qJzIAg',
};

const context = {};

// Call the renderCredential method
const result: IRenderResult = await renderer.renderCredential(
args,
context as IRendererContext,
);

// Verify the result
expect(result.documents).toEqual([
{
renderedTemplate:
'UEdScGRpQnpkSGxzWlQwaWQybGtkR2c2TXpBd2NIZzdJR2hsYVdkb2REb3hNREJ3ZURzZ1ltOXlaR1Z5T2lBeWNIZ2djMjlzYVdRZ1lteGhZMnM3SUhSbGVIUXRZV3hwWjI0NlkyVnVkR1Z5SWo0S0lDQThaR2wyUGdvZ0lDQWdWR2hwY3lCQ1lXTm9aV3h2Y2lCdlppQlRZMmxsYm1ObElHRnVaQ0JCY25SeklHbHpJR052Ym1abGNuSmxaQ0IwYndvZ0lEd3ZaR2wyUGdvZ0lEeHpkSEp2Ym1jZ2MzUjViR1U5SW1admJuUXRjMmw2WlRvZ01UWndlQ0krQ2lBZ0lDQktZVzVsSUZOdGFYUm9DaUFnUEM5emRISnZibWMrQ2lBZ1BHUnBkajRLSUNBZ0lHSjVJRVY0WVcxd2JHVWdWVzVwZG1WeWMybDBlUzRLSUNBOEwyUnBkajRLUEM5a2FYWSs=',
type: 'WebRenderingTemplate2022',
},
]);
});
});
3 changes: 2 additions & 1 deletion packages/renderer/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@
"dependencies": {
"@digitalcredentials/jsonld": "5.2.1",
"@vckit/core-types": "workspace:^",
"handlebars": "^4.7.8"
"handlebars": "^4.7.8",
"jose": "^5.9.3"
},
"type": "module",
"moduleDirectories": [
Expand Down
21 changes: 15 additions & 6 deletions packages/renderer/src/renderer.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import jsonld from '@digitalcredentials/jsonld';
import { JsonLdObj } from 'jsonld/jsonld-spec';
import { Buffer } from 'buffer';

import {
VerifiableCredential,
RenderMethodPayload,
IRendererProvider,
IAgentPlugin,
Expand All @@ -12,9 +10,11 @@ import {
IRenderResult,
UnsignedCredential,
IRenderer,
VerifiableCredential,
} from '@vckit/core-types';
import { RenderDefaultContexts } from './render-default-contexts.js';
import schema from '@vckit/core-types/build/plugin.schema.json' assert { type: 'json' };
import * as jose from 'jose';

export const RENDER_METHOD = 'https://www.w3.org/2018/credentials#renderMethod';

Expand Down Expand Up @@ -73,9 +73,14 @@ export class Renderer implements IAgentPlugin {
context?: IRendererContext,
): Promise<IRenderResult> {
try {
const [expandedDocument] = await expandVerifiableCredential(
args.credential,
);
let credential: VerifiableCredential | UnsignedCredential;
if (typeof args.credential === 'string') {
credential = decodeJWTJose(args.credential);
} else {
credential = { ...args.credential };
}

const [expandedDocument] = await expandVerifiableCredential(credential);

if (!expandedDocument) {
throw new Error('Error expanding the verifiable credential');
Expand All @@ -94,7 +99,7 @@ export class Renderer implements IAgentPlugin {
const document = await rendererProvider.renderCredential({
data: renderMethod.data,
context,
document: args.credential,
document: credential,
});
const responseDocument = {
type: renderMethod.type,
Expand Down Expand Up @@ -193,3 +198,7 @@ function documentLoader(url: string, options: any) {
}
return documentLoaderFn(url);
}

function decodeJWTJose(jwt: string): UnsignedCredential {
return jose.decodeJwt(jwt);
}
42 changes: 41 additions & 1 deletion pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 54d6dfb

Please sign in to comment.