From 90486563917cb1e64d441079f9824cfda4cadf54 Mon Sep 17 00:00:00 2001 From: "Lukas.J.Han" Date: Mon, 26 Feb 2024 07:28:21 +0900 Subject: [PATCH 01/19] wip: sd-jwt Signed-off-by: Lukas --- jest.config.mjs | 2 +- packages/sd-jwt/LICENSE | 201 +++++++ packages/sd-jwt/README.md | 3 + packages/sd-jwt/api-extractor.json | 18 + packages/sd-jwt/package.json | 67 +++ .../__tests__/validate-presentation.test.ts | 143 +++++ packages/sd-jwt/src/action-handler.ts | 196 +++++++ packages/sd-jwt/src/index.ts | 13 + packages/sd-jwt/src/message-handler.ts | 89 +++ packages/sd-jwt/src/plugin.schema.ts | 538 ++++++++++++++++++ packages/sd-jwt/src/types.ts | 239 ++++++++ packages/sd-jwt/tsconfig.json | 21 + pnpm-lock.yaml | 160 +++++- 13 files changed, 1662 insertions(+), 28 deletions(-) create mode 100644 packages/sd-jwt/LICENSE create mode 100644 packages/sd-jwt/README.md create mode 100644 packages/sd-jwt/api-extractor.json create mode 100644 packages/sd-jwt/package.json create mode 100644 packages/sd-jwt/src/__tests__/validate-presentation.test.ts create mode 100644 packages/sd-jwt/src/action-handler.ts create mode 100644 packages/sd-jwt/src/index.ts create mode 100644 packages/sd-jwt/src/message-handler.ts create mode 100644 packages/sd-jwt/src/plugin.schema.ts create mode 100644 packages/sd-jwt/src/types.ts create mode 100644 packages/sd-jwt/tsconfig.json diff --git a/jest.config.mjs b/jest.config.mjs index abc3ad6fe..0cbfb0ec6 100644 --- a/jest.config.mjs +++ b/jest.config.mjs @@ -18,7 +18,7 @@ const config = { coverageReporters: ['json'], coverageDirectory: './coverage', coverageProvider: 'v8', - testMatch: ['**/__tests__/**/*.test.ts'], + testMatch: ['**/sd-jwt/**/__tests__/**/*.test.ts'], automock: false, // // typescript 5 removes the need to specify relative imports as .js, so we should no longer need this workaround // // but webpack still requires .js specifiers, so we are keeping it for now diff --git a/packages/sd-jwt/LICENSE b/packages/sd-jwt/LICENSE new file mode 100644 index 000000000..fd815d7f8 --- /dev/null +++ b/packages/sd-jwt/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2019 Consensys AG + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/packages/sd-jwt/README.md b/packages/sd-jwt/README.md new file mode 100644 index 000000000..9e3f1de8e --- /dev/null +++ b/packages/sd-jwt/README.md @@ -0,0 +1,3 @@ +# Veramo selective disclosure JWT plugin + +This package provides a Veramo plugin that can create, present and verify selective disclosure JWTs. diff --git a/packages/sd-jwt/api-extractor.json b/packages/sd-jwt/api-extractor.json new file mode 100644 index 000000000..409d7f16c --- /dev/null +++ b/packages/sd-jwt/api-extractor.json @@ -0,0 +1,18 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", + "apiReport": { + "enabled": true, + "reportFolder": "./api", + "reportTempFolder": "./api" + }, + + "docModel": { + "enabled": true, + "apiJsonFilePath": "./api/.api.json" + }, + + "dtsRollup": { + "enabled": false + }, + "mainEntryPointFilePath": "/build/index.d.ts" +} diff --git a/packages/sd-jwt/package.json b/packages/sd-jwt/package.json new file mode 100644 index 000000000..b04718bd3 --- /dev/null +++ b/packages/sd-jwt/package.json @@ -0,0 +1,67 @@ +{ + "name": "@veramo/sd-jwt", + "description": "Veramo plugin to enable SD-JWT", + "version": "5.6.0", + "main": "build/index.js", + "exports": { + ".": "./build/index.js" + }, + "types": "build/index.d.ts", + "scripts": { + "build": "tsc", + "generate-plugin-schema": "node ../cli/bin/veramo.js dev generate-plugin-schema" + }, + "veramo": { + "pluginInterfaces": { + "ISelectiveDisclosure": "./src/types.ts" + } + }, + "dependencies": { + "@sd-jwt/core": "next", + "@sd-jwt/crypto-nodejs": "0.3.2-next.63", + "@sd-jwt/types": "0.3.2-next.63", + "@sd-jwt/utils": "next", + "@veramo/core-types": "workspace:^", + "@veramo/message-handler": "workspace:^", + "@veramo/utils": "workspace:^", + "debug": "^4.3.3", + "did-jwt": "^8.0.0", + "uuid": "^9.0.0" + }, + "devDependencies": { + "@types/debug": "4.1.8", + "@types/uuid": "9.0.2", + "typescript": "5.3.3" + }, + "files": [ + "build/**/*", + "src/**/*", + "README.md", + "LICENSE" + ], + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "https://github.com/decentralized-identity/veramo.git", + "directory": "packages/selective-disclosure" + }, + "author": "Consensys Mesh R&D ", + "contributors": [ + "Simonas Karuzas ", + "Mircea Nistor " + ], + "keywords": [ + "Veramo", + "DID", + "Verifiable Credential", + "veramo-plugin" + ], + "license": "Apache-2.0", + "type": "module", + "moduleDirectories": [ + "node_modules", + "src" + ] +} diff --git a/packages/sd-jwt/src/__tests__/validate-presentation.test.ts b/packages/sd-jwt/src/__tests__/validate-presentation.test.ts new file mode 100644 index 000000000..ac5705e3d --- /dev/null +++ b/packages/sd-jwt/src/__tests__/validate-presentation.test.ts @@ -0,0 +1,143 @@ +import { IAgentContext, VerifiableCredential, VerifiablePresentation } from '../../../core-types/src' +import { ISelectiveDisclosureRequest } from '../types.js' +import { SelectiveDisclosure } from '../action-handler.js' +import { jest } from '@jest/globals' + +const actionHandler = new SelectiveDisclosure() + +const context = { + agent: { + execute: jest.fn(), + availableMethods: jest.fn(), + getSchema: jest.fn(), + emit: jest.fn(), + }, +} as IAgentContext + +describe('@veramo/selective-disclosure-helper', () => { + it('should validate presentation for sdr', async () => { + const sdr: ISelectiveDisclosureRequest = { + issuer: 'did:example:123', + replyUrl: 'https://example.com/didcomm', + tag: 'session-123', + claims: [ + { + reason: 'We are required by law to collect this information', + claimType: 'firstName', + essential: true, + }, + { + reason: 'You can get %30 discount if you are a member of the club', + credentialContext: 'https://www.w3.org/2018/credentials/v1', + credentialType: 'ClubMembership', + claimType: 'status', + claimValue: 'member', + issuers: [ + { + did: 'did:ethr:567', + url: 'https://join-the-club.partner1.com', + }, + { + did: 'did:ethr:659', + url: 'https://ecosystem.io', + }, + ], + }, + ], + credentials: ['JWT-public-profile...'], + } + + const did1 = 'did:example:555' + const did2 = 'did:ethr:659' + + const credential1: VerifiableCredential = { + '@context': ['https://www.w3.org/2018/credentials/v1'], + type: ['VerifiableCredential'], + issuer: { id: did1 }, + issuanceDate: '2012-12-19T06:01:17.171Z', + credentialSubject: { + id: did1, + firstName: 'Alice', + lastName: 'Smith', + }, + proof: { + jwt: 'mock', + }, + } + + const credential2: VerifiableCredential = { + '@context': ['https://www.w3.org/2018/credentials/v1'], + type: ['VerifiableCredential', 'ClubMembership'], + issuer: { id: did2 }, + issuanceDate: '2012-12-19T06:01:17.171Z', + credentialSubject: { + id: did1, + status: 'member', + }, + proof: { + jwt: 'mock', + }, + } + + const presentation: VerifiablePresentation = { + holder: did1, + verifier: [did1], + type: ['VerifiablePresentation'], + '@context': ['https://www.w3.org/2018/credentials/v1'], + verifiableCredential: [credential1, credential2], + proof: { + jwt: 'mock', + }, + } + + const result = await actionHandler.validatePresentationAgainstSdr({ presentation, sdr }, context) + + expect(result.claims[0].credentials[0].verifiableCredential.credentialSubject['firstName']).toEqual( + 'Alice', + ) + expect(result.valid).toEqual(true) + }) + + it('should invalidate presentation for sdr', async () => { + const sdr: ISelectiveDisclosureRequest = { + issuer: 'did:example:123', + claims: [ + { + reason: 'We are required by law to collect this information', + claimType: 'firstName', + essential: true, + }, + ], + } + + const did1 = 'did:example:555' + + const credential1: VerifiableCredential = { + '@context': ['https://www.w3.org/2018/credentials/v1'], + type: ['VerifiableCredential'], + issuer: { id: did1 }, + issuanceDate: '2012-12-19T06:01:17.171Z', + credentialSubject: { + id: did1, + lastName: 'Smith', + }, + proof: { + jwt: 'mock', + }, + } + + const presentation: VerifiablePresentation = { + holder: did1, + verifier: [did1], + type: ['VerifiablePresentation'], + '@context': ['https://www.w3.org/2018/credentials/v1'], + verifiableCredential: [credential1], + proof: { + jwt: 'mock', + }, + } + const result = await actionHandler.validatePresentationAgainstSdr({ presentation, sdr }, context) + + expect(result.valid).toEqual(false) + }) +}) diff --git a/packages/sd-jwt/src/action-handler.ts b/packages/sd-jwt/src/action-handler.ts new file mode 100644 index 000000000..ea7d30e6f --- /dev/null +++ b/packages/sd-jwt/src/action-handler.ts @@ -0,0 +1,196 @@ +import { Jwt, SDJwt, SDJwtInstance } from '@sd-jwt/core' +import { Signer, Verifier } from '@sd-jwt/types' +import { IAgentPlugin, IIdentifier, IKey } from '@veramo/core-types' +import { extractIssuer } from '@veramo/utils' +import schema from '../plugin.schema.json' assert { type: 'json' } +import { SdJWTImplementation } from '../types/ISDJwtPlugin' +import { + ICreateVerifiableCredentialSDJwtArgs, + ICreateVerifiableCredentialSDJwtResult, + ICreateVerifiablePresentationSDJwtArgs, + ICreateVerifiablePresentationSDJwtResult, + IRequiredContext, + ISDJwtPlugin, + IVerifyVerifiableCredentialSDJwtArgs, + IVerifyVerifiableCredentialSDJwtResult, + IVerifyVerifiablePresentationSDJwtArgs, + IVerifyVerifiablePresentationSDJwtResult, +} from '../types/ISDJwtPlugin.js' + +/** + * SD-JWT plugin for Veramo + */ +export class SDJwtPlugin implements IAgentPlugin { + readonly schema = schema.ISDJwtPlugin + + constructor(private algorithms: SdJWTImplementation) {} + + // map the methods your plugin is declaring to their implementation + readonly methods: ISDJwtPlugin = { + createVerifiableCredentialSDJwt: this.createVerifiableCredentialSDJwt.bind(this), + createVerifiablePresentationSDJwt: this.createVerifiablePresentationSDJwt.bind(this), + verifyVerifiableCredentialSDJwt: this.verifyVerifiableCredentialSDJwt.bind(this), + verifyVerifiablePresentationSDJwt: this.verifyVerifiablePresentationSDJwt.bind(this), + } + + /** + * Create a signed SD-JWT credential. + * @param args - Arguments necessary for the creation of a SD-JWT credential. + * @param context - This reserved param is automatically added and handled by the framework, *do not override* + * @returns A signed SD-JWT credential. + */ + async createVerifiableCredentialSDJwt( + args: ICreateVerifiableCredentialSDJwtArgs, + context: IRequiredContext, + ): Promise { + const issuer = extractIssuer(args.credentialPayload, { + removeParameters: true, + }) + if (!issuer) { + throw new Error('invalid_argument: credential.issuer must not be empty') + } + if (issuer.split('#').length === 1) { + throw new Error( + 'invalid_argument: credential.issuer must contain a did id with key reference like did:exmaple.com#key-1', + ) + } + const identifier = await context.agent.didManagerGet({ + did: issuer.split('#')[0], + }) + //TODO: how to make sure it is getting the correct key? Right now it's looping over it, but without checking the key reference. + const { key, alg } = SDJwtPlugin.getSigningKey(identifier) + //TODO: let the user also insert a method to sign the data + const signer: Signer = async (data: string) => context.agent.keyManagerSign({ keyRef: key.kid, data }) + + const sdjwt = new SDJwtInstance({ + signer, + hasher: this.algorithms.hasher, + saltGenerator: this.algorithms.salltGenerator, + signAlg: alg, + hashAlg: 'SHA-256', + }) + + const credential = await sdjwt.issue(args.credentialPayload, args.disclosureFrame) + return { credential } + } + + /** + * Create a signed SD-JWT presentation. + * @param args - Arguments necessary for the creation of a SD-JWT presentation. + * @param context - This reserved param is automatically added and handled by the framework, *do not override* + * @returns A signed SD-JWT presentation. + */ + async createVerifiablePresentationSDJwt( + args: ICreateVerifiablePresentationSDJwtArgs, + context: IRequiredContext, + ): Promise { + const cred = await SDJwt.fromEncode(args.presentation, this.algorithms.hasher) + //get the key based on the credential + const identifier = await context.agent.didManagerFind({ alias: 'holder' }) + const { key, alg } = SDJwtPlugin.getSigningKey(identifier[0]) + + const signer: Signer = async (data: string) => context.agent.keyManagerSign({ keyRef: key.kid, data }) + + const sdjwt = new SDJwtInstance({ + hasher: this.algorithms.hasher, + saltGenerator: this.algorithms.salltGenerator, + signAlg: alg, + signer, + }) + const credential = await sdjwt.present(args.presentation, args.presentationKeys) + return { presentation: credential } + } + + /** + * Verify a signed SD-JWT credential. + * @param args + * @param context + * @returns + */ + async verifyVerifiableCredentialSDJwt( + args: IVerifyVerifiableCredentialSDJwtArgs, + context: IRequiredContext, + ): Promise { + // biome-ignore lint/style/useConst: + let sdjwt: SDJwtInstance + const verifier: Verifier = async (data: string, signature: string) => + this.verify(sdjwt, context, data, signature) + + sdjwt = new SDJwtInstance({ verifier, hasher: this.algorithms.hasher }) + const verifiedPayloads = await sdjwt.verify(args.credential) + + return { verifiedPayloads } + } + + /** + * Validates the signature of a SD-JWT + * @param sdjwt + * @param context + * @param data + * @param signature + * @returns + */ + async verify(sdjwt: SDJwtInstance, context: IRequiredContext, data: string, signature: string) { + const decodedVC = await sdjwt.decode(`${data}.${signature}`) + const issuer: string = ((decodedVC.jwt as Jwt).payload as Record).issuer as string + //check if the issuer is a did + if (!issuer.startsWith('did:')) { + throw new Error('invalid_issuer: issuer must be a did') + } + const didDoc = await context.agent.resolveDid({ didUrl: issuer }) + if (!didDoc) { + throw new Error('invalid_issuer: issuer did not resolve to a did document') + } + const didDocumentKey = didDoc.didDocument?.verificationMethod?.find((key) => key.id) + if (!didDocumentKey) { + throw new Error('invalid_issuer: issuer did document does not include referenced key') + } + //TODO: in case it's another did method, the value of the key can be also encoded as a base64url + const key = didDocumentKey.publicKeyJwk as JsonWebKey + return this.algorithms.verifySignature(data, signature, key) + } + + /** + * Verify a signed SD-JWT presentation. + * @param args + * @param context + * @returns + */ + async verifyVerifiablePresentationSDJwt( + args: IVerifyVerifiablePresentationSDJwtArgs, + context: IRequiredContext, + ): Promise { + // biome-ignore lint/style/useConst: + let sdjwt: SDJwtInstance + const verifier: Verifier = async (data: string, signature: string) => + this.verify(sdjwt, context, data, signature) + sdjwt = new SDJwtInstance({ verifier, hasher: this.algorithms.hasher }) + const verifiedPayloads = await sdjwt.verify(args.presentation) + + return { verifiedPayloads } + } + + /** + * Get the signing key for a given identifier + * @param identifier + * @returns + */ + private static getSigningKey(identifier: IIdentifier): { + key: IKey + alg: string + } { + for (const key of identifier.keys) { + if (key.type === 'Ed25519') { + return { key, alg: 'EdDSA' } + } + if (key.type === 'Secp256k1') { + return { key, alg: 'ES256K' } + } + if (key.type === 'Secp256r1') { + return { key, alg: 'ES256' } + } + } + + throw Error(`key_not_found: No signing key for ${identifier.did}`) + } +} diff --git a/packages/sd-jwt/src/index.ts b/packages/sd-jwt/src/index.ts new file mode 100644 index 000000000..574ae924d --- /dev/null +++ b/packages/sd-jwt/src/index.ts @@ -0,0 +1,13 @@ +/** + * Provides a {@link @veramo/selective-disclosure#ISelectiveDisclosure | plugin} for the {@link @veramo/core#Agent} + * that implements {@link @veramo/selective-disclosure#SelectiveDisclosure} interface. + * + * Provides a {@link @veramo/selective-disclosure#SdrMessageHandler | plugin} for the + * {@link @veramo/message-handler#MessageHandler} that detects Selective Disclosure Request in a message + * + * @packageDocumentation + */ +export { SdrMessageHandler, MessageTypes } from './message-handler.js' +export { SelectiveDisclosure } from './action-handler.js' +export * from './types.js' +export { schema } from './plugin.schema.js' diff --git a/packages/sd-jwt/src/message-handler.ts b/packages/sd-jwt/src/message-handler.ts new file mode 100644 index 000000000..a9d992c7d --- /dev/null +++ b/packages/sd-jwt/src/message-handler.ts @@ -0,0 +1,89 @@ +import { IAgentContext, IMessageHandler } from '@veramo/core-types' +import { Message, AbstractMessageHandler } from '@veramo/message-handler' +import { v4 as uuidv4 } from 'uuid' + +import Debug from 'debug' +import { asArray, computeEntryHash } from '@veramo/utils' + +const debug = Debug('veramo:selective-disclosure:message-handler') + +/** + * Identifies a {@link @veramo/core-types#IMessage} that represents a Selective Disclosure Request + * + * @remarks See + * {@link https://github.com/uport-project/specs/blob/develop/messages/sharereq.md | uPort Selective Disclosure Request} + * @beta This API may change without a BREAKING CHANGE notice. + */ +export const MessageTypes = { + sdr: 'sdr', +} + +/** + * A Veramo message handler plugin that can decode an incoming Selective Disclosure Response + * into the internal Message representation. + * + * @beta This API may change without a BREAKING CHANGE notice. + * + * @deprecated This plugin is deprecated as it implements a non-standard protocol created for the uPort project. It + * will be removed in a future release. + */ +export class SdrMessageHandler extends AbstractMessageHandler { + async handle(message: Message, context: IAgentContext): Promise { + const meta = message.getLastMetaData() + + if (message?.data?.type == MessageTypes.sdr && message?.data?.claims) { + debug('Message type is', MessageTypes.sdr) + + message.id = computeEntryHash(message.raw || message.id || uuidv4()) + message.type = MessageTypes.sdr + message.from = message.data.iss + + if (message.data.replyTo) { + message.replyTo = asArray(message.data.replyTo) + } + + if (message.data.replyUrl) { + message.replyUrl = message.data.replyUrl + } + + if (message.data.subject) { + message.to = message.data.subject + } + + if (message.data.tag) { + message.threadId = message.data.tag + } + message.createdAt = this.timestampToDate(message.data.nbf || message.data.iat).toISOString() + + if ( + message.data.credentials && + Array.isArray(message.data.credentials) && + message.data.credentials.length > 0 + ) { + debug('Verifying included credentials') + // FIXME + // message.credentials = [] + // for (const raw of message.data.credentials) { + // try { + // const tmpMessage = await context.agent.handleMessage({ raw, save: false }) + // if (tmpMessage.credentials) { + // message.credentials = [...message.credentials, ...tmpMessage.credentials] + // } + // } catch (e) { + // // Unsupported message type, or some other error + // debug(e) + // } + // } + } + return message + } + + return super.handle(message, context) + } + + private timestampToDate(timestamp: number): Date { + const date = new Date(0) + date.setUTCSeconds(timestamp) + return date + } +} diff --git a/packages/sd-jwt/src/plugin.schema.ts b/packages/sd-jwt/src/plugin.schema.ts new file mode 100644 index 000000000..2f1af65f4 --- /dev/null +++ b/packages/sd-jwt/src/plugin.schema.ts @@ -0,0 +1,538 @@ +export const schema = { + "ISelectiveDisclosure": { + "components": { + "schemas": { + "ICreateProfileCredentialsArgs": { + "type": "object", + "properties": { + "holder": { + "type": "string", + "description": "Holder DID" + }, + "verifier": { + "type": "string", + "description": "Optional. Verifier DID" + }, + "name": { + "type": "string", + "description": "Optional. Name" + }, + "picture": { + "type": "string", + "description": "Optional. Picture URL" + }, + "url": { + "type": "string", + "description": "Optional. URL" + }, + "save": { + "type": "boolean", + "description": "Save presentation" + }, + "send": { + "type": "boolean", + "description": "Send presentation" + } + }, + "required": [ + "holder", + "save", + "send" + ], + "description": "Profile data" + }, + "VerifiablePresentation": { + "type": "object", + "properties": { + "proof": { + "$ref": "#/components/schemas/ProofType" + }, + "holder": { + "type": "string" + }, + "verifiableCredential": { + "type": "array", + "items": { + "$ref": "#/components/schemas/W3CVerifiableCredential" + } + }, + "type": { + "anyOf": [ + { + "type": "array", + "items": { + "type": "string" + } + }, + { + "type": "string" + } + ] + }, + "@context": { + "$ref": "#/components/schemas/ContextType" + }, + "verifier": { + "type": "array", + "items": { + "type": "string" + } + }, + "issuanceDate": { + "type": "string" + }, + "expirationDate": { + "type": "string" + }, + "id": { + "type": "string" + } + }, + "required": [ + "@context", + "holder", + "proof" + ], + "description": "Represents a signed Verifiable Presentation (includes proof), using a JSON representation. See {@link https://www.w3.org/TR/vc-data-model/#presentations | VP data model }" + }, + "ProofType": { + "type": "object", + "properties": { + "type": { + "type": "string" + } + }, + "description": "A proof property of a {@link VerifiableCredential } or {@link VerifiablePresentation }" + }, + "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": { + "proof": { + "$ref": "#/components/schemas/ProofType" + }, + "issuer": { + "$ref": "#/components/schemas/IssuerType" + }, + "credentialSubject": { + "$ref": "#/components/schemas/CredentialSubject" + }, + "type": { + "anyOf": [ + { + "type": "array", + "items": { + "type": "string" + } + }, + { + "type": "string" + } + ] + }, + "@context": { + "$ref": "#/components/schemas/ContextType" + }, + "issuanceDate": { + "type": "string" + }, + "expirationDate": { + "type": "string" + }, + "credentialStatus": { + "$ref": "#/components/schemas/CredentialStatusReference" + }, + "id": { + "type": "string" + } + }, + "required": [ + "@context", + "credentialSubject", + "issuanceDate", + "issuer", + "proof" + ], + "description": "Represents a signed Verifiable Credential payload (includes proof), using a JSON representation. See {@link https://www.w3.org/TR/vc-data-model/#credentials | VC data model }" + }, + "IssuerType": { + "anyOf": [ + { + "type": "object", + "properties": { + "id": { + "type": "string" + } + }, + "required": [ + "id" + ] + }, + { + "type": "string" + } + ], + "description": "The issuer of a {@link VerifiableCredential } or the holder of a {@link VerifiablePresentation } .\n\nThe value of the issuer property MUST be either a URI or an object containing an id property. It is RECOMMENDED that the URI in the issuer or its id be one which, if de-referenced, results in a document containing machine-readable information about the issuer that can be used to verify the information expressed in the credential.\n\nSee {@link https://www.w3.org/TR/vc-data-model/#issuer | Issuer data model }" + }, + "CredentialSubject": { + "type": "object", + "properties": { + "id": { + "type": "string" + } + }, + "description": "The value of the credentialSubject property is defined as a set of objects that contain one or more properties that are each related to a subject of the verifiable credential. Each object MAY contain an id.\n\nSee {@link https://www.w3.org/TR/vc-data-model/#credential-subject | Credential Subject }" + }, + "ContextType": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "object" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "object" + } + ] + } + } + ], + "description": "The data type for `@context` properties of credentials, presentations, etc." + }, + "CredentialStatusReference": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string" + } + }, + "required": [ + "id", + "type" + ], + "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\"" + }, + "ICreateSelectiveDisclosureRequestArgs": { + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/ISelectiveDisclosureRequest" + } + }, + "required": [ + "data" + ], + "description": "Contains the parameters of a Selective Disclosure Request." + }, + "ISelectiveDisclosureRequest": { + "type": "object", + "properties": { + "issuer": { + "type": "string", + "description": "The issuer of the request" + }, + "subject": { + "type": "string", + "description": "The target of the request" + }, + "replyUrl": { + "type": "string", + "description": "The URL where the response should be sent back" + }, + "tag": { + "type": "string" + }, + "claims": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ICredentialRequestInput" + }, + "description": "A list of claims that are being requested" + }, + "credentials": { + "type": "array", + "items": { + "type": "string" + }, + "description": "A list of issuer credentials that the target will use to establish trust" + } + }, + "required": [ + "issuer", + "claims" + ], + "description": "Represents the Selective Disclosure request parameters." + }, + "ICredentialRequestInput": { + "type": "object", + "properties": { + "reason": { + "type": "string", + "description": "Motive for requiring this credential." + }, + "essential": { + "type": "boolean", + "description": "If it is essential. A response that does not include this credential is not sufficient." + }, + "credentialType": { + "type": "string", + "description": "The credential type. See {@link https://www.w3.org/TR/vc-data-model/#types | W3C Credential Types }" + }, + "credentialContext": { + "type": "string", + "description": "The credential context. See {@link https://www.w3.org/TR/vc-data-model/#contexts | W3C Credential Context }" + }, + "claimType": { + "type": "string", + "description": "The name of the claim property that the credential should express." + }, + "claimValue": { + "type": "string", + "description": "The value of the claim that the credential should express." + }, + "issuers": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Issuer" + }, + "description": "A list of accepted Issuers for this credential." + } + }, + "required": [ + "claimType" + ], + "description": "Describes a particular credential that is being requested" + }, + "Issuer": { + "type": "object", + "properties": { + "did": { + "type": "string", + "description": "The DID of the issuer of a requested credential." + }, + "url": { + "type": "string", + "description": "A URL where a credential of that type can be obtained." + } + }, + "required": [ + "did", + "url" + ], + "description": "Used for requesting Credentials using Selective Disclosure. Represents an accepted issuer of a credential." + }, + "IGetVerifiableCredentialsForSdrArgs": { + "type": "object", + "properties": { + "sdr": { + "type": "object", + "properties": { + "subject": { + "type": "string", + "description": "The target of the request" + }, + "replyUrl": { + "type": "string", + "description": "The URL where the response should be sent back" + }, + "tag": { + "type": "string" + }, + "claims": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ICredentialRequestInput" + }, + "description": "A list of claims that are being requested" + }, + "credentials": { + "type": "array", + "items": { + "type": "string" + }, + "description": "A list of issuer credentials that the target will use to establish trust" + } + }, + "required": [ + "claims" + ], + "description": "The Selective Disclosure Request (issuer is omitted)" + }, + "did": { + "type": "string", + "description": "The DID of the subject" + } + }, + "required": [ + "sdr" + ], + "description": "Encapsulates the params needed to gather credentials to fulfill a Selective disclosure request." + }, + "ICredentialsForSdr": { + "type": "object", + "properties": { + "reason": { + "type": "string", + "description": "Motive for requiring this credential." + }, + "essential": { + "type": "boolean", + "description": "If it is essential. A response that does not include this credential is not sufficient." + }, + "credentialType": { + "type": "string", + "description": "The credential type. See {@link https://www.w3.org/TR/vc-data-model/#types | W3C Credential Types }" + }, + "credentialContext": { + "type": "string", + "description": "The credential context. See {@link https://www.w3.org/TR/vc-data-model/#contexts | W3C Credential Context }" + }, + "claimType": { + "type": "string", + "description": "The name of the claim property that the credential should express." + }, + "claimValue": { + "type": "string", + "description": "The value of the claim that the credential should express." + }, + "issuers": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Issuer" + }, + "description": "A list of accepted Issuers for this credential." + }, + "credentials": { + "type": "array", + "items": { + "$ref": "#/components/schemas/UniqueVerifiableCredential" + } + } + }, + "required": [ + "claimType", + "credentials" + ], + "description": "The credentials that make up a response of a Selective Disclosure" + }, + "UniqueVerifiableCredential": { + "type": "object", + "properties": { + "hash": { + "type": "string" + }, + "verifiableCredential": { + "$ref": "#/components/schemas/VerifiableCredential" + } + }, + "required": [ + "hash", + "verifiableCredential" + ], + "description": "Represents the result of a Query for {@link VerifiableCredential } s\n\nSee {@link IDataStoreORM.dataStoreORMGetVerifiableCredentials } See {@link IDataStoreORM.dataStoreORMGetVerifiableCredentialsByClaims }" + }, + "IValidatePresentationAgainstSdrArgs": { + "type": "object", + "properties": { + "presentation": { + "$ref": "#/components/schemas/VerifiablePresentation" + }, + "sdr": { + "$ref": "#/components/schemas/ISelectiveDisclosureRequest" + } + }, + "required": [ + "presentation", + "sdr" + ], + "description": "A tuple used to verify a Selective Disclosure Response. Encapsulates the response(`presentation`) and the corresponding request (`sdr`) that made it." + }, + "IPresentationValidationResult": { + "type": "object", + "properties": { + "valid": { + "type": "boolean" + }, + "claims": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ICredentialsForSdr" + } + } + }, + "required": [ + "valid", + "claims" + ], + "description": "The result of a selective disclosure response validation." + } + }, + "methods": { + "createProfilePresentation": { + "description": "", + "arguments": { + "$ref": "#/components/schemas/ICreateProfileCredentialsArgs" + }, + "returnType": { + "$ref": "#/components/schemas/VerifiablePresentation" + } + }, + "createSelectiveDisclosureRequest": { + "description": "", + "arguments": { + "$ref": "#/components/schemas/ICreateSelectiveDisclosureRequestArgs" + }, + "returnType": { + "type": "string" + } + }, + "getVerifiableCredentialsForSdr": { + "description": "", + "arguments": { + "$ref": "#/components/schemas/IGetVerifiableCredentialsForSdrArgs" + }, + "returnType": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ICredentialsForSdr" + } + } + }, + "validatePresentationAgainstSdr": { + "description": "", + "arguments": { + "$ref": "#/components/schemas/IValidatePresentationAgainstSdrArgs" + }, + "returnType": { + "$ref": "#/components/schemas/IPresentationValidationResult" + } + } + } + } + } +} \ No newline at end of file diff --git a/packages/sd-jwt/src/types.ts b/packages/sd-jwt/src/types.ts new file mode 100644 index 000000000..283d4ae5d --- /dev/null +++ b/packages/sd-jwt/src/types.ts @@ -0,0 +1,239 @@ +import { + IAgentContext, + ICredentialIssuer, + IDataStoreORM, + IDIDManager, + IKeyManager, + IPluginMethodMap, + UniqueVerifiableCredential, + VerifiablePresentation, +} from '@veramo/core-types' + +/** + * Used for requesting Credentials using Selective Disclosure. + * Represents an accepted issuer of a credential. + * + * @beta This API may change without a BREAKING CHANGE notice. + */ +export interface Issuer { + /** + * The DID of the issuer of a requested credential. + */ + did: string + + /** + * A URL where a credential of that type can be obtained. + */ + url: string +} + +/** + * Represents the Selective Disclosure request parameters. + * + * @remarks See + * {@link https://github.com/uport-project/specs/blob/develop/messages/sharereq.md | Selective Disclosure Request} + * + * @beta This API may change without a BREAKING CHANGE notice. */ +export interface ISelectiveDisclosureRequest { + /** + * The issuer of the request + */ + issuer: string + /** + * The target of the request + */ + subject?: string + /** + * The URL where the response should be sent back + */ + replyUrl?: string + + tag?: string + + /** + * A list of claims that are being requested + */ + claims: ICredentialRequestInput[] + + /** + * A list of issuer credentials that the target will use to establish trust + */ + credentials?: string[] +} + +/** + * Describes a particular credential that is being requested + * + * @remarks See + * {@link https://github.com/uport-project/specs/blob/develop/messages/sharereq.md | Selective Disclosure Request} + * + * @beta This API may change without a BREAKING CHANGE notice. */ +export interface ICredentialRequestInput { + /** + * Motive for requiring this credential. + */ + reason?: string + + /** + * If it is essential. A response that does not include this credential is not sufficient. + */ + essential?: boolean + + /** + * The credential type. See {@link https://www.w3.org/TR/vc-data-model/#types | W3C Credential Types} + */ + credentialType?: string + + /** + * The credential context. See {@link https://www.w3.org/TR/vc-data-model/#contexts | W3C Credential Context} + */ + credentialContext?: string + + /** + * The name of the claim property that the credential should express. + */ + claimType: string + + /** + * The value of the claim that the credential should express. + */ + claimValue?: string + + /** + * A list of accepted Issuers for this credential. + */ + issuers?: Issuer[] +} + +/** + * The credentials that make up a response of a Selective Disclosure + * + * @remarks See + * {@link https://github.com/uport-project/specs/blob/develop/messages/sharereq.md | Selective Disclosure Request} + * + * @beta This API may change without a BREAKING CHANGE notice. + */ +export interface ICredentialsForSdr extends ICredentialRequestInput { + credentials: UniqueVerifiableCredential[] +} + +/** + * The result of a selective disclosure response validation. + * + * @beta This API may change without a BREAKING CHANGE notice. + */ +export interface IPresentationValidationResult { + valid: boolean + claims: ICredentialsForSdr[] +} + +/** + * Contains the parameters of a Selective Disclosure Request. + * + * @remarks See + * {@link https://github.com/uport-project/specs/blob/develop/messages/sharereq.md | Selective Disclosure Request} + * specs + * + * @beta This API may change without a BREAKING CHANGE notice. + */ +export interface ICreateSelectiveDisclosureRequestArgs { + data: ISelectiveDisclosureRequest +} + +/** + * Encapsulates the params needed to gather credentials to fulfill a Selective disclosure request. + * + * @remarks See + * {@link https://github.com/uport-project/specs/blob/develop/messages/sharereq.md | Selective Disclosure Request} + * specs + * + * @beta This API may change without a BREAKING CHANGE notice. + */ +export interface IGetVerifiableCredentialsForSdrArgs { + /** + * The Selective Disclosure Request (issuer is omitted) + */ + sdr: Omit + + /** + * The DID of the subject + */ + did?: string +} + +/** + * A tuple used to verify a Selective Disclosure Response. + * Encapsulates the response(`presentation`) and the corresponding request (`sdr`) that made it. + * + * @beta This API may change without a BREAKING CHANGE notice. + */ +export interface IValidatePresentationAgainstSdrArgs { + presentation: VerifiablePresentation + sdr: ISelectiveDisclosureRequest +} + +/** + * Profile data + * + * @beta This API may change without a BREAKING CHANGE notice. + */ +export interface ICreateProfileCredentialsArgs { + /** + * Holder DID + */ + holder: string + /** + * Optional. Verifier DID + */ + verifier?: string + /** + * Optional. Name + */ + name?: string + /** + * Optional. Picture URL + */ + picture?: string + /** + * Optional. URL + */ + url?: string + /** + * Save presentation + */ + save: boolean + /** + * Send presentation + */ + send: boolean +} + +/** + * Describes the interface of a Selective Disclosure plugin. + * + * @remarks See + * {@link https://github.com/uport-project/specs/blob/develop/messages/sharereq.md | Selective Disclosure Request} + * + * @beta This API may change without a BREAKING CHANGE notice. + */ +export interface ISelectiveDisclosure extends IPluginMethodMap { + createSelectiveDisclosureRequest( + args: ICreateSelectiveDisclosureRequestArgs, + context: IAgentContext, + ): Promise + + getVerifiableCredentialsForSdr( + args: IGetVerifiableCredentialsForSdrArgs, + context: IAgentContext, + ): Promise> + + validatePresentationAgainstSdr( + args: IValidatePresentationAgainstSdrArgs, + context: IAgentContext<{}>, + ): Promise + + createProfilePresentation( + args: ICreateProfileCredentialsArgs, + context: IAgentContext, + ): Promise +} diff --git a/packages/sd-jwt/tsconfig.json b/packages/sd-jwt/tsconfig.json new file mode 100644 index 000000000..7dff4d76e --- /dev/null +++ b/packages/sd-jwt/tsconfig.json @@ -0,0 +1,21 @@ +{ + "extends": "../tsconfig.settings.json", + "compilerOptions": { + "rootDir": "src", + "outDir": "build", + "declarationDir": "build", + "skipLibCheck": true + }, + "references": [ + { + "path": "../core-types" + }, + { + "path": "../message-handler" + }, + { + "path": "../utils" + } + ], + "include": ["./**/*.ts"] +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9ed8ba375..59d36187c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -128,7 +128,7 @@ importers: version: 10.9.2(@types/node@20.11.19)(typescript@5.3.3) typeorm: specifier: 0.3.17 - version: 0.3.17(sqlite3@5.1.6)(ts-node@10.9.2) + version: 0.3.17(pg@8.11.3)(sqlite3@5.1.7)(ts-node@10.9.2) typescript: specifier: 5.3.3 version: 5.3.3 @@ -1140,7 +1140,7 @@ importers: version: 3.0.1 typeorm: specifier: ^0.3.17 - version: 0.3.17(sqlite3@5.1.6)(ts-node@10.9.2) + version: 0.3.17(pg@8.11.3)(sqlite3@5.1.7)(ts-node@10.9.2) uint8arrays: specifier: ^4.0.6 version: 4.0.6 @@ -1300,6 +1300,49 @@ importers: specifier: 5.3.3 version: 5.3.3 + packages/sd-jwt: + dependencies: + '@sd-jwt/core': + specifier: next + version: 0.3.2-next.66 + '@sd-jwt/crypto-nodejs': + specifier: 0.3.2-next.63 + version: 0.3.2-next.63 + '@sd-jwt/types': + specifier: 0.3.2-next.63 + version: 0.3.2-next.63 + '@sd-jwt/utils': + specifier: next + version: 0.3.2-next.66 + '@veramo/core-types': + specifier: workspace:^ + version: link:../core-types + '@veramo/message-handler': + specifier: workspace:^ + version: link:../message-handler + '@veramo/utils': + specifier: workspace:^ + version: link:../utils + debug: + specifier: ^4.3.3 + version: 4.3.4 + did-jwt: + specifier: ^8.0.0 + version: 8.0.0 + uuid: + specifier: ^9.0.0 + version: 9.0.1 + devDependencies: + '@types/debug': + specifier: 4.1.8 + version: 4.1.8 + '@types/uuid': + specifier: 9.0.2 + version: 9.0.2 + typescript: + specifier: 5.3.3 + version: 5.3.3 + packages/selective-disclosure: dependencies: '@veramo/core-types': @@ -1434,7 +1477,7 @@ importers: version: /stream-browserify@3.0.0 typeorm: specifier: ^0.3.17 - version: 0.3.17(sqlite3@5.1.6)(ts-node@10.9.2) + version: 0.3.17(pg@8.11.3)(sqlite3@5.1.7)(ts-node@10.9.2) util: specifier: npm:util version: 0.12.5 @@ -9435,6 +9478,40 @@ packages: '@noble/hashes': 1.3.3 '@scure/base': 1.1.3 + /@sd-jwt/core@0.3.2-next.66: + resolution: {integrity: sha512-eaD2hMNfnfxjGtGzXTYfFXJ3iRa/juH7Bv7uAHpfcYP25tSUhAnXEhVaW+rtB4GjNm0xYUwvI6CB78DaNmhSsQ==} + dependencies: + '@sd-jwt/decode': 0.3.2-next.66 + '@sd-jwt/types': 0.3.2-next.66 + '@sd-jwt/utils': 0.3.2-next.66 + dev: false + + /@sd-jwt/crypto-nodejs@0.3.2-next.63: + resolution: {integrity: sha512-6W3u6nXYcl0Ivaim9v4s2atohJYpnZCRgHopCuMtDQwNglPPRKrDY2oZBHDyc52O3/XY1zPxY2s7y0ZA0obx1w==} + dev: false + + /@sd-jwt/decode@0.3.2-next.66: + resolution: {integrity: sha512-xrOA91GdiCAWE8whU/wU+J/n3/Gns1sP6VJa24yU99B6/v8UW2qtBj3aFBmqfFwEXw6webgdP+Bnd9ssKqnSYw==} + dependencies: + '@sd-jwt/types': 0.3.2-next.66 + '@sd-jwt/utils': 0.3.2-next.66 + dev: false + + /@sd-jwt/types@0.3.2-next.63: + resolution: {integrity: sha512-6FG9n/RYJK5YRU8GI/61rBYPZ/0N+nq1CJ2MAUyv9jHX3FzVHACVoyIwxPaAXHgRFGGgn5WwwL1uqC2c/8Arnw==} + dev: false + + /@sd-jwt/types@0.3.2-next.66: + resolution: {integrity: sha512-lENdXY0scVrkNby1RoH8TjKn2QrRDAT+Uxk2J7BFHDM68elIdCbgB/+MgB+S40aozaRINrPG72kDNeKItPwZiA==} + dev: false + + /@sd-jwt/utils@0.3.2-next.66: + resolution: {integrity: sha512-iXQxzCnl+mkTCwu+Hmj8OIrK4sJxxjRDigOMfz04dgIlkStxQFCwvyLgHyeKYNQulKnuI0Sor+TK+xCZ84Lq3g==} + dependencies: + '@sd-jwt/types': 0.3.2-next.66 + js-base64: 3.7.7 + dev: false + /@segment/loosely-validate-event@2.0.0: resolution: {integrity: sha512-ZMCSfztDBqwotkl848ODgVcAmN4OItEWDCkshcKz0/W6gGSQayuuCtWV/MlodFivAZD793d6UgANd6wCXUfrIw==} dependencies: @@ -10152,6 +10229,14 @@ packages: '@transmute/ld-key-pair': 0.7.0-unstable.81 dev: false + /@trufflesuite/bigint-buffer@1.1.10: + resolution: {integrity: sha512-pYIQC5EcMmID74t26GCC67946mgTJFiLXOT/BYozgrd4UEY2JHEGLhWi9cMiQCt5BSqFEvKkCHNnoj82SRjiEw==} + engines: {node: '>= 14.0.0'} + requiresBuild: true + dependencies: + node-gyp-build: 4.4.0 + dev: true + /@trufflesuite/uws-js-unofficial@20.30.0-unofficial.0: resolution: {integrity: sha512-r5X0aOQcuT6pLwTRLD+mPnAM/nlKtvIK4Z+My++A8tTOR0qTjNRx8UB8jzRj3D+p9PMAp5LnpCUUGmz7/TppwA==} dependencies: @@ -12343,7 +12428,6 @@ packages: /bn.js@4.12.0: resolution: {integrity: sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==} - dev: false /bn.js@5.2.1: resolution: {integrity: sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==} @@ -12458,7 +12542,6 @@ packages: /brorand@1.1.0: resolution: {integrity: sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==} - dev: false /browser-process-hrtime@1.0.0: resolution: {integrity: sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==} @@ -12582,7 +12665,6 @@ packages: /buffer-writer@2.0.0: resolution: {integrity: sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==} engines: {node: '>=4'} - dev: false /buffer-xor@1.0.3: resolution: {integrity: sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==} @@ -14527,7 +14609,6 @@ packages: inherits: 2.0.4 minimalistic-assert: 1.0.1 minimalistic-crypto-utils: 1.0.1 - dev: false /emittery@0.10.0: resolution: {integrity: sha512-AGvFfs+d0JKCJQ4o01ASQLGPmSCxgfU9RFXvzPvZdjKK8oscynksuJhWrSTSw7j7Ep/sZct5b5ZhYCi8S/t0HQ==} @@ -16172,6 +16253,7 @@ packages: resolution: {integrity: sha512-7gsVVDpO9AhrFyDMWWl7SpMsPpqGcnAzjxz3k32LheIPNd64p2XsY9GYRdhWmKuryb60W1iaWPZWDkFKlbRWHA==} hasBin: true dependencies: + '@trufflesuite/bigint-buffer': 1.1.10 '@trufflesuite/uws-js-unofficial': 20.30.0-unofficial.0 '@types/bn.js': 5.1.1 '@types/lru-cache': 5.1.1 @@ -16180,6 +16262,9 @@ packages: abstract-leveldown: 7.2.0 async-eventemitter: 0.2.4 emittery: 0.10.0 + keccak: 3.0.2 + leveldown: 6.1.0 + secp256k1: 4.0.3 optionalDependencies: bufferutil: 4.0.5 utf-8-validate: 5.0.7 @@ -16684,7 +16769,6 @@ packages: dependencies: inherits: 2.0.4 minimalistic-assert: 1.0.1 - dev: false /hasown@2.0.0: resolution: {integrity: sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==} @@ -16733,7 +16817,6 @@ packages: hash.js: 1.1.7 minimalistic-assert: 1.0.1 minimalistic-crypto-utils: 1.0.1 - dev: false /homedir-polyfill@1.0.3: resolution: {integrity: sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==} @@ -18892,6 +18975,10 @@ packages: resolution: {integrity: sha512-njj0VL2TsIxCtgzhO+9RRobBvws4oYyCM8TpvoUQwl/MbIM3NFJRR9+e6x0sS5xXaP1t6OCBkaBME98OV9zU5A==} dev: false + /js-base64@3.7.7: + resolution: {integrity: sha512-7rCnleh0z2CkXhH67J8K1Ytz0b2Y+yxTPL+/KOJoa20hfnVQ/3/T6W/KflYI4bRHRagNeXeU2bkNGI3v1oS/lw==} + dev: false + /js-sha3@0.8.0: resolution: {integrity: sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==} dev: false @@ -19170,6 +19257,16 @@ packages: object.assign: 4.1.4 dev: true + /keccak@3.0.2: + resolution: {integrity: sha512-PyKKjkH53wDMLGrvmRGSNWgmSxZOUqbnXwKL9tmgbFYA1iAYqW21kfR7mZXV0MlESiefxQQE9X9fTa3X+2MPDQ==} + engines: {node: '>=10.0.0'} + requiresBuild: true + dependencies: + node-addon-api: 2.0.2 + node-gyp-build: 4.6.0 + readable-stream: 3.6.2 + dev: true + /keyv@4.5.3: resolution: {integrity: sha512-QCiSav9WaX1PgETJ+SpNnx2PRRapJ/oRSXM4VO5OGYGSjrxbKPVFVhB3l2OCbLCk329N8qyAtsJjSjvVBWzEug==} dependencies: @@ -19376,6 +19473,16 @@ packages: module-error: 1.0.2 dev: true + /leveldown@6.1.0: + resolution: {integrity: sha512-8C7oJDT44JXxh04aSSsfcMI8YiaGRhOFI9/pMEL7nWJLVsWajDPTRxsSHTM2WcTVY5nXM+SuRHzPPi0GbnDX+w==} + engines: {node: '>=10.12.0'} + requiresBuild: true + dependencies: + abstract-leveldown: 7.2.0 + napi-macros: 2.0.0 + node-gyp-build: 4.6.0 + dev: true + /leven@3.1.0: resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} engines: {node: '>=6'} @@ -20302,7 +20409,6 @@ packages: /minimalistic-crypto-utils@1.0.1: resolution: {integrity: sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==} - dev: false /minimatch@3.0.5: resolution: {integrity: sha512-tUpxzX0VAzJHjLu0xUfFv1gwVp9ba3IOuRAVH2EGuRW8a5emA2FlACLqiT/lDVtS1W+TGNwqz3sWaNyLgDJWuw==} @@ -20583,6 +20689,10 @@ packages: /napi-build-utils@1.0.2: resolution: {integrity: sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==} + /napi-macros@2.0.0: + resolution: {integrity: sha512-A0xLykHtARfueITVDernsAWdtIMbOJgKgcluwENp3AlsKN/PloyO10HtmoqnFAQAcxPkgZN7wdfPfEd0zNGxbg==} + dev: true + /natural-compare-lite@1.4.0: resolution: {integrity: sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==} dev: true @@ -20646,7 +20756,6 @@ packages: /node-addon-api@2.0.2: resolution: {integrity: sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==} - dev: false /node-addon-api@4.3.0: resolution: {integrity: sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==} @@ -20734,6 +20843,11 @@ packages: resolution: {integrity: sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==} engines: {node: '>= 6.13.0'} + /node-gyp-build@4.4.0: + resolution: {integrity: sha512-amJnQCcgtRVw9SvoebO3BKGESClrfXGCUTX9hSn1OuGQTQBOZmVd0Z0OlecpuRksKvbsUqALE8jls/ErClAPuQ==} + hasBin: true + dev: true + /node-gyp-build@4.6.0: resolution: {integrity: sha512-NTZVKn9IylLwUzaKjkas1e4u2DLNcV4rdYagA4PWdPwW87Bi7z+BznyKSRwS/761tV/lzCGXplWsiaMjLqP2zQ==} hasBin: true @@ -21600,7 +21714,6 @@ packages: /packet-reader@1.0.0: resolution: {integrity: sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==} - dev: false /pacote@17.0.6: resolution: {integrity: sha512-cJKrW21VRE8vVTRskJo78c/RCvwJCn1f4qgfxL4w77SOWrTCRcmfkYHlHtS0gqpgjv3zhXflRtgsrUCX5xwNnQ==} @@ -21869,17 +21982,14 @@ packages: /pg-cloudflare@1.1.1: resolution: {integrity: sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==} requiresBuild: true - dev: false optional: true /pg-connection-string@2.6.2: resolution: {integrity: sha512-ch6OwaeaPYcova4kKZ15sbJ2hKb/VP48ZD2gE7i1J+L4MspCtBMAx8nMgz7bksc7IojCIIWuEhHibSMFH8m8oA==} - dev: false /pg-int8@1.0.1: resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==} engines: {node: '>=4.0.0'} - dev: false /pg-pool@3.6.1(pg@8.11.3): resolution: {integrity: sha512-jizsIzhkIitxCGfPRzJn1ZdcosIt3pz9Sh3V01fm1vZnbnCMgmGl5wvGGdNN2EL9Rmb0EcFoCkixH4Pu+sP9Og==} @@ -21887,11 +21997,9 @@ packages: pg: '>=8.0' dependencies: pg: 8.11.3 - dev: false /pg-protocol@1.6.0: resolution: {integrity: sha512-M+PDm637OY5WM307051+bsDia5Xej6d9IR4GwJse1qA1DIhiKlksvrneZOYQq42OM+spubpcNYEo2FcKQrDk+Q==} - dev: false /pg-types@2.2.0: resolution: {integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==} @@ -21902,7 +22010,6 @@ packages: postgres-bytea: 1.0.0 postgres-date: 1.0.7 postgres-interval: 1.2.0 - dev: false /pg@8.11.3: resolution: {integrity: sha512-+9iuvG8QfaaUrrph+kpF24cXkH1YOOUeArRNYIxq1viYHZagBxrTno7cecY1Fa44tJeZvaoG+Djpkc3JwehN5g==} @@ -21922,13 +22029,11 @@ packages: pgpass: 1.0.5 optionalDependencies: pg-cloudflare: 1.1.1 - dev: false /pgpass@1.0.5: resolution: {integrity: sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==} dependencies: split2: 4.2.0 - dev: false /picocolors@0.2.1: resolution: {integrity: sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==} @@ -22795,24 +22900,20 @@ packages: /postgres-array@2.0.0: resolution: {integrity: sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==} engines: {node: '>=4'} - dev: false /postgres-bytea@1.0.0: resolution: {integrity: sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==} engines: {node: '>=0.10.0'} - dev: false /postgres-date@1.0.7: resolution: {integrity: sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==} engines: {node: '>=0.10.0'} - dev: false /postgres-interval@1.2.0: resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==} engines: {node: '>=0.10.0'} dependencies: xtend: 4.0.2 - dev: false /prebuild-install@7.1.1: resolution: {integrity: sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==} @@ -24153,7 +24254,6 @@ packages: elliptic: 6.5.4 node-addon-api: 2.0.2 node-gyp-build: 4.6.0 - dev: false /select-hose@2.0.0: resolution: {integrity: sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==} @@ -24733,6 +24833,9 @@ packages: /sqlite3@5.1.6: resolution: {integrity: sha512-olYkWoKFVNSSSQNvxVUfjiVbz3YtBwTJj+mfV5zpHmqW3sELx2Cf4QCdirMelhM5Zh+KDVaKgQHqCxrqiWHybw==} requiresBuild: true + peerDependenciesMeta: + node-gyp: + optional: true dependencies: '@mapbox/node-pre-gyp': 1.0.10 node-addon-api: 4.3.0 @@ -24747,6 +24850,9 @@ packages: /sqlite3@5.1.7: resolution: {integrity: sha512-GGIyOiFaG+TUra3JIfkI/zGP8yZYLPQ0pl1bH+ODjiX57sPhrLU5sQJn1y9bDKZUFYkX1crlrPfSYt0BKKdkog==} requiresBuild: true + peerDependenciesMeta: + node-gyp: + optional: true dependencies: bindings: 1.5.0 node-addon-api: 7.1.0 @@ -25842,7 +25948,7 @@ packages: cli-highlight: 2.1.11 date-fns: 2.30.0 debug: 4.3.4 - dotenv: 16.4.5 + dotenv: 16.3.1 glob: 8.1.0 mkdirp: 2.1.6 pg: 8.11.3 @@ -25855,7 +25961,6 @@ packages: yargs: 17.7.2 transitivePeerDependencies: - supports-color - dev: false /typeorm@0.3.17(sqlite3@5.1.6)(ts-node@10.9.2): resolution: {integrity: sha512-UDjUEwIQalO9tWw9O2A4GU+sT3oyoUXheHJy4ft+RFdnRdQctdQ34L9SqE2p7LdwzafHx1maxT+bqXON+Qnmig==} @@ -25934,6 +26039,7 @@ packages: yargs: 17.7.2 transitivePeerDependencies: - supports-color + dev: false /typescript@5.3.3: resolution: {integrity: sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==} From 3acd753b1c1303261de4922590dfa5728f54d736 Mon Sep 17 00:00:00 2001 From: "Lukas.J.Han" Date: Sun, 3 Mar 2024 23:36:38 +0900 Subject: [PATCH 02/19] feat: sd-jwt Signed-off-by: Lukas --- packages/sd-jwt/package.json | 12 +- packages/sd-jwt/src/action-handler.ts | 213 ++++++---- packages/sd-jwt/src/index.ts | 12 +- packages/sd-jwt/src/message-handler.ts | 89 ---- packages/sd-jwt/src/plugin.schema.ts | 548 +++++-------------------- packages/sd-jwt/src/types.ts | 300 ++++++-------- pnpm-lock.yaml | 272 ++++++++++-- 7 files changed, 611 insertions(+), 835 deletions(-) delete mode 100644 packages/sd-jwt/src/message-handler.ts diff --git a/packages/sd-jwt/package.json b/packages/sd-jwt/package.json index b04718bd3..3327c6fe6 100644 --- a/packages/sd-jwt/package.json +++ b/packages/sd-jwt/package.json @@ -13,14 +13,16 @@ }, "veramo": { "pluginInterfaces": { - "ISelectiveDisclosure": "./src/types.ts" + "ISDJwtPlugin": "./src/types.ts" } }, "dependencies": { - "@sd-jwt/core": "next", - "@sd-jwt/crypto-nodejs": "0.3.2-next.63", - "@sd-jwt/types": "0.3.2-next.63", - "@sd-jwt/utils": "next", + "@sphereon/ssi-sdk-ext.did-utils": "^0.16.0", + "@sd-jwt/core": "0.3.2-next.102", + "@sd-jwt/crypto-nodejs": "0.3.2-next.102", + "@sd-jwt/types": "0.3.2-next.102", + "@sd-jwt/utils": "0.3.2-next.102", + "@sd-jwt/sd-jwt-vc": "0.3.2-next.102", "@veramo/core-types": "workspace:^", "@veramo/message-handler": "workspace:^", "@veramo/utils": "workspace:^", diff --git a/packages/sd-jwt/src/action-handler.ts b/packages/sd-jwt/src/action-handler.ts index ea7d30e6f..f56f7004f 100644 --- a/packages/sd-jwt/src/action-handler.ts +++ b/packages/sd-jwt/src/action-handler.ts @@ -1,21 +1,24 @@ -import { Jwt, SDJwt, SDJwtInstance } from '@sd-jwt/core' -import { Signer, Verifier } from '@sd-jwt/types' -import { IAgentPlugin, IIdentifier, IKey } from '@veramo/core-types' -import { extractIssuer } from '@veramo/utils' -import schema from '../plugin.schema.json' assert { type: 'json' } -import { SdJWTImplementation } from '../types/ISDJwtPlugin' +import { Jwt, SDJwt } from '@sd-jwt/core' +import { SDJwtVcInstance } from '@sd-jwt/sd-jwt-vc' +import { Signer, Verifier, KbVerifier, JwtPayload } from '@sd-jwt/types' +import { IAgentPlugin } from '@veramo/core-types' +import { schema } from './plugin.schema' import { - ICreateVerifiableCredentialSDJwtArgs, - ICreateVerifiableCredentialSDJwtResult, - ICreateVerifiablePresentationSDJwtArgs, - ICreateVerifiablePresentationSDJwtResult, + SdJWTImplementation, + ICreateSdJwtVcArgs, + ICreateSdJwtVcResult, + ICreateSdJwtVcPresentationArgs, + ICreateSdJwtVcPresentationResult, IRequiredContext, ISDJwtPlugin, - IVerifyVerifiableCredentialSDJwtArgs, - IVerifyVerifiableCredentialSDJwtResult, - IVerifyVerifiablePresentationSDJwtArgs, - IVerifyVerifiablePresentationSDJwtResult, -} from '../types/ISDJwtPlugin.js' + IVerifySdJwtVcArgs, + IVerifySdJwtVcResult, + IVerifySdJwtVcPresentationArgs, + IVerifySdJwtVcPresentationResult, + Claims, +} from './types.js' +import { mapIdentifierKeysToDocWithJwkSupport } from '@sphereon/ssi-sdk-ext.did-utils' +import { encodeJoseBlob } from '@veramo/utils' /** * SD-JWT plugin for Veramo @@ -27,10 +30,10 @@ export class SDJwtPlugin implements IAgentPlugin { // map the methods your plugin is declaring to their implementation readonly methods: ISDJwtPlugin = { - createVerifiableCredentialSDJwt: this.createVerifiableCredentialSDJwt.bind(this), - createVerifiablePresentationSDJwt: this.createVerifiablePresentationSDJwt.bind(this), - verifyVerifiableCredentialSDJwt: this.verifyVerifiableCredentialSDJwt.bind(this), - verifyVerifiablePresentationSDJwt: this.verifyVerifiablePresentationSDJwt.bind(this), + createSdJwtVc: this.createSdJwtVc.bind(this), + createSdJwtVcPresentation: this.createSdJwtVcPresentation.bind(this), + verifySdJwtVc: this.verifySdJwtVc.bind(this), + verifySdJwtVcPresentation: this.verifySdJwtVcPresentation.bind(this), } /** @@ -39,33 +42,23 @@ export class SDJwtPlugin implements IAgentPlugin { * @param context - This reserved param is automatically added and handled by the framework, *do not override* * @returns A signed SD-JWT credential. */ - async createVerifiableCredentialSDJwt( - args: ICreateVerifiableCredentialSDJwtArgs, - context: IRequiredContext, - ): Promise { - const issuer = extractIssuer(args.credentialPayload, { - removeParameters: true, - }) + async createSdJwtVc(args: ICreateSdJwtVcArgs, context: IRequiredContext): Promise { + const issuer = args.credentialPayload.iss if (!issuer) { - throw new Error('invalid_argument: credential.issuer must not be empty') + throw new Error('credential.issuer must not be empty') } if (issuer.split('#').length === 1) { - throw new Error( - 'invalid_argument: credential.issuer must contain a did id with key reference like did:exmaple.com#key-1', - ) + throw new Error('credential.issuer must reference a key') } - const identifier = await context.agent.didManagerGet({ - did: issuer.split('#')[0], - }) - //TODO: how to make sure it is getting the correct key? Right now it's looping over it, but without checking the key reference. - const { key, alg } = SDJwtPlugin.getSigningKey(identifier) + const { alg, key } = await this.getSignKey(issuer, context) + //TODO: let the user also insert a method to sign the data const signer: Signer = async (data: string) => context.agent.keyManagerSign({ keyRef: key.kid, data }) - const sdjwt = new SDJwtInstance({ + const sdjwt = new SDJwtVcInstance({ signer, hasher: this.algorithms.hasher, - saltGenerator: this.algorithms.salltGenerator, + saltGenerator: this.algorithms.saltGenerator, signAlg: alg, hashAlg: 'SHA-256', }) @@ -74,30 +67,73 @@ export class SDJwtPlugin implements IAgentPlugin { return { credential } } + /** + * Get the key to sign the SD-JWT + * @param issuer did url like did:exmaple.com#key-1 + * @param context agent instance + * @returns the key to sign the SD-JWT + */ + private async getSignKey(issuer: string, context: IRequiredContext) { + const identifier = await context.agent.didManagerGet({ + did: issuer.split('#')[0], + }) + const doc = await mapIdentifierKeysToDocWithJwkSupport(identifier, 'assertionMethod', context) + if (!doc || doc.length === 0) throw new Error('No key found for signing') + const key = doc.find((key) => key.meta.verificationMethod.id === issuer) + if (!key) throw new Error('No key found with the given id') + let alg: string + //transform the key type to the alg + switch (key.type) { + case 'Ed25519': + alg = 'EdDSA' + break + case 'Secp256k1': + alg = 'ES256K' + break + case 'Secp256r1': + alg = 'ES256' + break + default: + throw new Error(`unsupported key type ${key.type}`) + } + return { alg, key } + } + /** * Create a signed SD-JWT presentation. * @param args - Arguments necessary for the creation of a SD-JWT presentation. * @param context - This reserved param is automatically added and handled by the framework, *do not override* * @returns A signed SD-JWT presentation. */ - async createVerifiablePresentationSDJwt( - args: ICreateVerifiablePresentationSDJwtArgs, + async createSdJwtVcPresentation( + args: ICreateSdJwtVcPresentationArgs, context: IRequiredContext, - ): Promise { + ): Promise { const cred = await SDJwt.fromEncode(args.presentation, this.algorithms.hasher) - //get the key based on the credential - const identifier = await context.agent.didManagerFind({ alias: 'holder' }) - const { key, alg } = SDJwtPlugin.getSigningKey(identifier[0]) + const claims = await cred.getClaims(this.algorithms.hasher) + let holderDID: string + // we primarly look for a cnf field, if it's not there we look for a sub field. If this is also not given, we throw an error since we can not sign it. + if (claims.cnf?.jwk) { + const key = claims.cnf.jwk + holderDID = `did:jwk:${encodeJoseBlob(key)}#0` + } else if (claims.sub) { + holderDID = claims.sub as string + } else { + throw new Error('invalid_argument: credential does not include a holder reference') + } + const { alg, key } = await this.getSignKey(holderDID, context) - const signer: Signer = async (data: string) => context.agent.keyManagerSign({ keyRef: key.kid, data }) + const signer: Signer = async (data: string) => { + return context.agent.keyManagerSign({ keyRef: key.kid, data }) + } - const sdjwt = new SDJwtInstance({ + const sdjwt = new SDJwtVcInstance({ hasher: this.algorithms.hasher, - saltGenerator: this.algorithms.salltGenerator, - signAlg: alg, - signer, + saltGenerator: this.algorithms.saltGenerator, + kbSigner: signer, + kbSignAlg: alg, }) - const credential = await sdjwt.present(args.presentation, args.presentationKeys) + const credential = await sdjwt.present(args.presentation, args.presentationKeys, { kb: args.kb }) return { presentation: credential } } @@ -107,21 +143,41 @@ export class SDJwtPlugin implements IAgentPlugin { * @param context * @returns */ - async verifyVerifiableCredentialSDJwt( - args: IVerifyVerifiableCredentialSDJwtArgs, - context: IRequiredContext, - ): Promise { + async verifySdJwtVc(args: IVerifySdJwtVcArgs, context: IRequiredContext): Promise { // biome-ignore lint/style/useConst: - let sdjwt: SDJwtInstance + let sdjwt: SDJwtVcInstance const verifier: Verifier = async (data: string, signature: string) => this.verify(sdjwt, context, data, signature) - sdjwt = new SDJwtInstance({ verifier, hasher: this.algorithms.hasher }) + sdjwt = new SDJwtVcInstance({ verifier, hasher: this.algorithms.hasher }) const verifiedPayloads = await sdjwt.verify(args.credential) return { verifiedPayloads } } + /** + * Verify the key binding of a SD-JWT by validating the signature of the key bound to the SD-JWT + * @param sdjwt + * @param context + * @param data + * @param signature + * @param payload + * @returns + */ + private verifyKb( + sdjwt: SDJwtVcInstance, + context: IRequiredContext, + data: string, + signature: string, + payload: JwtPayload, + ): Promise { + if (!payload.cnf) { + throw Error('other method than cnf is not supported yet') + } + const key = payload.cnf.jwk as JsonWebKey + return this.algorithms.verifySignature(data, signature, key) + } + /** * Validates the signature of a SD-JWT * @param sdjwt @@ -130,10 +186,9 @@ export class SDJwtPlugin implements IAgentPlugin { * @param signature * @returns */ - async verify(sdjwt: SDJwtInstance, context: IRequiredContext, data: string, signature: string) { + async verify(sdjwt: SDJwtVcInstance, context: IRequiredContext, data: string, signature: string) { const decodedVC = await sdjwt.decode(`${data}.${signature}`) - const issuer: string = ((decodedVC.jwt as Jwt).payload as Record).issuer as string - //check if the issuer is a did + const issuer: string = ((decodedVC.jwt as Jwt).payload as Record).iss as string if (!issuer.startsWith('did:')) { throw new Error('invalid_issuer: issuer must be a did') } @@ -156,41 +211,23 @@ export class SDJwtPlugin implements IAgentPlugin { * @param context * @returns */ - async verifyVerifiablePresentationSDJwt( - args: IVerifyVerifiablePresentationSDJwtArgs, + async verifySdJwtVcPresentation( + args: IVerifySdJwtVcPresentationArgs, context: IRequiredContext, - ): Promise { + ): Promise { // biome-ignore lint/style/useConst: - let sdjwt: SDJwtInstance + let sdjwt: SDJwtVcInstance const verifier: Verifier = async (data: string, signature: string) => this.verify(sdjwt, context, data, signature) - sdjwt = new SDJwtInstance({ verifier, hasher: this.algorithms.hasher }) - const verifiedPayloads = await sdjwt.verify(args.presentation) + const verifierKb: KbVerifier = async (data: string, signature: string, payload: JwtPayload) => + this.verifyKb(sdjwt, context, data, signature, payload) + sdjwt = new SDJwtVcInstance({ + verifier, + hasher: this.algorithms.hasher, + kbVerifier: verifierKb, + }) + const verifiedPayloads = await sdjwt.verify(args.presentation, args.requiredClaimKeys, args.kb) return { verifiedPayloads } } - - /** - * Get the signing key for a given identifier - * @param identifier - * @returns - */ - private static getSigningKey(identifier: IIdentifier): { - key: IKey - alg: string - } { - for (const key of identifier.keys) { - if (key.type === 'Ed25519') { - return { key, alg: 'EdDSA' } - } - if (key.type === 'Secp256k1') { - return { key, alg: 'ES256K' } - } - if (key.type === 'Secp256r1') { - return { key, alg: 'ES256' } - } - } - - throw Error(`key_not_found: No signing key for ${identifier.did}`) - } } diff --git a/packages/sd-jwt/src/index.ts b/packages/sd-jwt/src/index.ts index 574ae924d..c8c7c3e5d 100644 --- a/packages/sd-jwt/src/index.ts +++ b/packages/sd-jwt/src/index.ts @@ -1,13 +1,5 @@ /** - * Provides a {@link @veramo/selective-disclosure#ISelectiveDisclosure | plugin} for the {@link @veramo/core#Agent} - * that implements {@link @veramo/selective-disclosure#SelectiveDisclosure} interface. - * - * Provides a {@link @veramo/selective-disclosure#SdrMessageHandler | plugin} for the - * {@link @veramo/message-handler#MessageHandler} that detects Selective Disclosure Request in a message - * - * @packageDocumentation + * @public */ -export { SdrMessageHandler, MessageTypes } from './message-handler.js' -export { SelectiveDisclosure } from './action-handler.js' +export { SDJwtPlugin } from './action-handler.js' export * from './types.js' -export { schema } from './plugin.schema.js' diff --git a/packages/sd-jwt/src/message-handler.ts b/packages/sd-jwt/src/message-handler.ts deleted file mode 100644 index a9d992c7d..000000000 --- a/packages/sd-jwt/src/message-handler.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { IAgentContext, IMessageHandler } from '@veramo/core-types' -import { Message, AbstractMessageHandler } from '@veramo/message-handler' -import { v4 as uuidv4 } from 'uuid' - -import Debug from 'debug' -import { asArray, computeEntryHash } from '@veramo/utils' - -const debug = Debug('veramo:selective-disclosure:message-handler') - -/** - * Identifies a {@link @veramo/core-types#IMessage} that represents a Selective Disclosure Request - * - * @remarks See - * {@link https://github.com/uport-project/specs/blob/develop/messages/sharereq.md | uPort Selective Disclosure Request} - * @beta This API may change without a BREAKING CHANGE notice. - */ -export const MessageTypes = { - sdr: 'sdr', -} - -/** - * A Veramo message handler plugin that can decode an incoming Selective Disclosure Response - * into the internal Message representation. - * - * @beta This API may change without a BREAKING CHANGE notice. - * - * @deprecated This plugin is deprecated as it implements a non-standard protocol created for the uPort project. It - * will be removed in a future release. - */ -export class SdrMessageHandler extends AbstractMessageHandler { - async handle(message: Message, context: IAgentContext): Promise { - const meta = message.getLastMetaData() - - if (message?.data?.type == MessageTypes.sdr && message?.data?.claims) { - debug('Message type is', MessageTypes.sdr) - - message.id = computeEntryHash(message.raw || message.id || uuidv4()) - message.type = MessageTypes.sdr - message.from = message.data.iss - - if (message.data.replyTo) { - message.replyTo = asArray(message.data.replyTo) - } - - if (message.data.replyUrl) { - message.replyUrl = message.data.replyUrl - } - - if (message.data.subject) { - message.to = message.data.subject - } - - if (message.data.tag) { - message.threadId = message.data.tag - } - message.createdAt = this.timestampToDate(message.data.nbf || message.data.iat).toISOString() - - if ( - message.data.credentials && - Array.isArray(message.data.credentials) && - message.data.credentials.length > 0 - ) { - debug('Verifying included credentials') - // FIXME - // message.credentials = [] - // for (const raw of message.data.credentials) { - // try { - // const tmpMessage = await context.agent.handleMessage({ raw, save: false }) - // if (tmpMessage.credentials) { - // message.credentials = [...message.credentials, ...tmpMessage.credentials] - // } - // } catch (e) { - // // Unsupported message type, or some other error - // debug(e) - // } - // } - } - return message - } - - return super.handle(message, context) - } - - private timestampToDate(timestamp: number): Date { - const date = new Date(0) - date.setUTCSeconds(timestamp) - return date - } -} diff --git a/packages/sd-jwt/src/plugin.schema.ts b/packages/sd-jwt/src/plugin.schema.ts index 2f1af65f4..f7fb76662 100644 --- a/packages/sd-jwt/src/plugin.schema.ts +++ b/packages/sd-jwt/src/plugin.schema.ts @@ -1,535 +1,207 @@ export const schema = { - "ISelectiveDisclosure": { + "ISDJwtPlugin": { "components": { "schemas": { - "ICreateProfileCredentialsArgs": { + "ICreateSdJwtVcArgs": { "type": "object", "properties": { - "holder": { - "type": "string", - "description": "Holder DID" - }, - "verifier": { - "type": "string", - "description": "Optional. Verifier DID" - }, - "name": { - "type": "string", - "description": "Optional. Name" - }, - "picture": { - "type": "string", - "description": "Optional. Picture URL" - }, - "url": { - "type": "string", - "description": "Optional. URL" - }, - "save": { - "type": "boolean", - "description": "Save presentation" - }, - "send": { - "type": "boolean", - "description": "Send presentation" - } - }, - "required": [ - "holder", - "save", - "send" - ], - "description": "Profile data" - }, - "VerifiablePresentation": { - "type": "object", - "properties": { - "proof": { - "$ref": "#/components/schemas/ProofType" - }, - "holder": { - "type": "string" - }, - "verifiableCredential": { - "type": "array", - "items": { - "$ref": "#/components/schemas/W3CVerifiableCredential" - } - }, - "type": { - "anyOf": [ - { - "type": "array", - "items": { - "type": "string" - } - }, - { + "credentialPayload": { + "type": "object", + "properties": { + "iss": { "type": "string" - } - ] - }, - "@context": { - "$ref": "#/components/schemas/ContextType" - }, - "verifier": { - "type": "array", - "items": { - "type": "string" - } - }, - "issuanceDate": { - "type": "string" - }, - "expirationDate": { - "type": "string" - }, - "id": { - "type": "string" - } - }, - "required": [ - "@context", - "holder", - "proof" - ], - "description": "Represents a signed Verifiable Presentation (includes proof), using a JSON representation. See {@link https://www.w3.org/TR/vc-data-model/#presentations | VP data model }" - }, - "ProofType": { - "type": "object", - "properties": { - "type": { - "type": "string" - } - }, - "description": "A proof property of a {@link VerifiableCredential } or {@link VerifiablePresentation }" - }, - "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": { - "proof": { - "$ref": "#/components/schemas/ProofType" - }, - "issuer": { - "$ref": "#/components/schemas/IssuerType" - }, - "credentialSubject": { - "$ref": "#/components/schemas/CredentialSubject" - }, - "type": { - "anyOf": [ - { - "type": "array", - "items": { - "type": "string" - } }, - { + "iat": { + "type": "number" + }, + "nbf": { + "type": "number" + }, + "exp": { + "type": "number" + }, + "cnf": {}, + "vct": { "type": "string" - } - ] - }, - "@context": { - "$ref": "#/components/schemas/ContextType" - }, - "issuanceDate": { - "type": "string" - }, - "expirationDate": { - "type": "string" - }, - "credentialStatus": { - "$ref": "#/components/schemas/CredentialStatusReference" - }, - "id": { - "type": "string" - } - }, - "required": [ - "@context", - "credentialSubject", - "issuanceDate", - "issuer", - "proof" - ], - "description": "Represents a signed Verifiable Credential payload (includes proof), using a JSON representation. See {@link https://www.w3.org/TR/vc-data-model/#credentials | VC data model }" - }, - "IssuerType": { - "anyOf": [ - { - "type": "object", - "properties": { - "id": { + }, + "status": {}, + "sub": { "type": "string" } }, "required": [ - "id" + "iss", + "iat", + "vct" ] }, - { - "type": "string" - } - ], - "description": "The issuer of a {@link VerifiableCredential } or the holder of a {@link VerifiablePresentation } .\n\nThe value of the issuer property MUST be either a URI or an object containing an id property. It is RECOMMENDED that the URI in the issuer or its id be one which, if de-referenced, results in a document containing machine-readable information about the issuer that can be used to verify the information expressed in the credential.\n\nSee {@link https://www.w3.org/TR/vc-data-model/#issuer | Issuer data model }" - }, - "CredentialSubject": { - "type": "object", - "properties": { - "id": { - "type": "string" - } - }, - "description": "The value of the credentialSubject property is defined as a set of objects that contain one or more properties that are each related to a subject of the verifiable credential. Each object MAY contain an id.\n\nSee {@link https://www.w3.org/TR/vc-data-model/#credential-subject | Credential Subject }" - }, - "ContextType": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "object" - }, - { - "type": "array", - "items": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "object" - } - ] - } - } - ], - "description": "The data type for `@context` properties of credentials, presentations, etc." - }, - "CredentialStatusReference": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "type": { - "type": "string" - } + "disclosureFrame": {} }, "required": [ - "id", - "type" + "credentialPayload" ], - "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 }" + "description": "ICreateSdJwtVcArgs" }, - "CompactJWT": { - "type": "string", - "description": "Represents a Json Web Token in compact form. \"header.payload.signature\"" - }, - "ICreateSelectiveDisclosureRequestArgs": { + "ICreateSdJwtVcResult": { "type": "object", "properties": { - "data": { - "$ref": "#/components/schemas/ISelectiveDisclosureRequest" - } - }, - "required": [ - "data" - ], - "description": "Contains the parameters of a Selective Disclosure Request." - }, - "ISelectiveDisclosureRequest": { - "type": "object", - "properties": { - "issuer": { - "type": "string", - "description": "The issuer of the request" - }, - "subject": { - "type": "string", - "description": "The target of the request" - }, - "replyUrl": { + "credential": { "type": "string", - "description": "The URL where the response should be sent back" - }, - "tag": { - "type": "string" - }, - "claims": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ICredentialRequestInput" - }, - "description": "A list of claims that are being requested" - }, - "credentials": { - "type": "array", - "items": { - "type": "string" - }, - "description": "A list of issuer credentials that the target will use to establish trust" + "description": "the encoded sd-jwt credential" } }, "required": [ - "issuer", - "claims" + "credential" ], - "description": "Represents the Selective Disclosure request parameters." + "description": "ICreateSdJwtVcResult" }, - "ICredentialRequestInput": { + "ICreateSdJwtVcPresentationArgs": { "type": "object", "properties": { - "reason": { - "type": "string", - "description": "Motive for requiring this credential." - }, - "essential": { - "type": "boolean", - "description": "If it is essential. A response that does not include this credential is not sufficient." - }, - "credentialType": { - "type": "string", - "description": "The credential type. See {@link https://www.w3.org/TR/vc-data-model/#types | W3C Credential Types }" - }, - "credentialContext": { - "type": "string", - "description": "The credential context. See {@link https://www.w3.org/TR/vc-data-model/#contexts | W3C Credential Context }" - }, - "claimType": { - "type": "string", - "description": "The name of the claim property that the credential should express." - }, - "claimValue": { + "presentation": { "type": "string", - "description": "The value of the claim that the credential should express." + "description": "Encoded SD-JWT credential" }, - "issuers": { + "presentationKeys": { "type": "array", "items": { - "$ref": "#/components/schemas/Issuer" - }, - "description": "A list of accepted Issuers for this credential." - } - }, - "required": [ - "claimType" - ], - "description": "Describes a particular credential that is being requested" - }, - "Issuer": { - "type": "object", - "properties": { - "did": { - "type": "string", - "description": "The DID of the issuer of a requested credential." + "type": "string" + } }, - "url": { - "type": "string", - "description": "A URL where a credential of that type can be obtained." - } - }, - "required": [ - "did", - "url" - ], - "description": "Used for requesting Credentials using Selective Disclosure. Represents an accepted issuer of a credential." - }, - "IGetVerifiableCredentialsForSdrArgs": { - "type": "object", - "properties": { - "sdr": { + "kb": { "type": "object", "properties": { - "subject": { - "type": "string", - "description": "The target of the request" - }, - "replyUrl": { - "type": "string", - "description": "The URL where the response should be sent back" - }, - "tag": { - "type": "string" - }, - "claims": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ICredentialRequestInput" - }, - "description": "A list of claims that are being requested" - }, - "credentials": { - "type": "array", - "items": { - "type": "string" + "payload": { + "type": "object", + "properties": { + "iat": { + "type": "number" + }, + "aud": { + "type": "string" + }, + "nonce": { + "type": "string" + } }, - "description": "A list of issuer credentials that the target will use to establish trust" + "required": [ + "iat", + "aud", + "nonce" + ] } }, "required": [ - "claims" + "payload" ], - "description": "The Selective Disclosure Request (issuer is omitted)" - }, - "did": { - "type": "string", - "description": "The DID of the subject" + "description": "Information to include to add key binding." } }, "required": [ - "sdr" - ], - "description": "Encapsulates the params needed to gather credentials to fulfill a Selective disclosure request." + "presentation" + ] }, - "ICredentialsForSdr": { + "ICreateSdJwtVcPresentationResult": { "type": "object", "properties": { - "reason": { - "type": "string", - "description": "Motive for requiring this credential." - }, - "essential": { - "type": "boolean", - "description": "If it is essential. A response that does not include this credential is not sufficient." - }, - "credentialType": { - "type": "string", - "description": "The credential type. See {@link https://www.w3.org/TR/vc-data-model/#types | W3C Credential Types }" - }, - "credentialContext": { - "type": "string", - "description": "The credential context. See {@link https://www.w3.org/TR/vc-data-model/#contexts | W3C Credential Context }" - }, - "claimType": { - "type": "string", - "description": "The name of the claim property that the credential should express." - }, - "claimValue": { + "presentation": { "type": "string", - "description": "The value of the claim that the credential should express." - }, - "issuers": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Issuer" - }, - "description": "A list of accepted Issuers for this credential." - }, - "credentials": { - "type": "array", - "items": { - "$ref": "#/components/schemas/UniqueVerifiableCredential" - } + "description": "Encoded presentation." } }, "required": [ - "claimType", - "credentials" + "presentation" ], - "description": "The credentials that make up a response of a Selective Disclosure" + "description": "Created presentation" }, - "UniqueVerifiableCredential": { + "IVerifySdJwtVcArgs": { "type": "object", "properties": { - "hash": { + "credential": { "type": "string" - }, - "verifiableCredential": { - "$ref": "#/components/schemas/VerifiableCredential" } }, "required": [ - "hash", - "verifiableCredential" - ], - "description": "Represents the result of a Query for {@link VerifiableCredential } s\n\nSee {@link IDataStoreORM.dataStoreORMGetVerifiableCredentials } See {@link IDataStoreORM.dataStoreORMGetVerifiableCredentialsByClaims }" + "credential" + ] }, - "IValidatePresentationAgainstSdrArgs": { + "IVerifySdJwtVcResult": { "type": "object", "properties": { - "presentation": { - "$ref": "#/components/schemas/VerifiablePresentation" - }, - "sdr": { - "$ref": "#/components/schemas/ISelectiveDisclosureRequest" - } + "verifiedPayloads": {} }, "required": [ - "presentation", - "sdr" - ], - "description": "A tuple used to verify a Selective Disclosure Response. Encapsulates the response(`presentation`) and the corresponding request (`sdr`) that made it." + "verifiedPayloads" + ] }, - "IPresentationValidationResult": { + "IVerifySdJwtVcPresentationArgs": { "type": "object", "properties": { - "valid": { - "type": "boolean" + "presentation": { + "type": "string" }, - "claims": { + "requiredClaimKeys": { "type": "array", "items": { - "$ref": "#/components/schemas/ICredentialsForSdr" + "type": "string" } + }, + "kb": { + "type": "boolean" } }, "required": [ - "valid", - "claims" - ], - "description": "The result of a selective disclosure response validation." + "presentation" + ] + }, + "IVerifySdJwtVcPresentationResult": { + "type": "object", + "properties": { + "verifiedPayloads": { + "type": "object", + "additionalProperties": {} + } + }, + "required": [ + "verifiedPayloads" + ] } }, "methods": { - "createProfilePresentation": { - "description": "", + "createSdJwtVc": { + "description": "Create a signed SD-JWT credential.", "arguments": { - "$ref": "#/components/schemas/ICreateProfileCredentialsArgs" + "$ref": "#/components/schemas/ICreateSdJwtVcArgs" }, "returnType": { - "$ref": "#/components/schemas/VerifiablePresentation" + "$ref": "#/components/schemas/ICreateSdJwtVcResult" } }, - "createSelectiveDisclosureRequest": { - "description": "", + "createSdJwtVcPresentation": { + "description": "Create a signed SD-JWT presentation.", "arguments": { - "$ref": "#/components/schemas/ICreateSelectiveDisclosureRequestArgs" + "$ref": "#/components/schemas/ICreateSdJwtVcPresentationArgs" }, "returnType": { - "type": "string" + "$ref": "#/components/schemas/ICreateSdJwtVcPresentationResult" } }, - "getVerifiableCredentialsForSdr": { - "description": "", + "verifySdJwtVc": { + "description": "Verify a signed SD-JWT credential.", "arguments": { - "$ref": "#/components/schemas/IGetVerifiableCredentialsForSdrArgs" + "$ref": "#/components/schemas/IVerifySdJwtVcArgs" }, "returnType": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ICredentialsForSdr" - } + "$ref": "#/components/schemas/IVerifySdJwtVcResult" } }, - "validatePresentationAgainstSdr": { - "description": "", + "verifySdJwtVcPresentation": { + "description": "Verify a signed SD-JWT presentation.", "arguments": { - "$ref": "#/components/schemas/IValidatePresentationAgainstSdrArgs" + "$ref": "#/components/schemas/IVerifySdJwtVcPresentationArgs" }, "returnType": { - "$ref": "#/components/schemas/IPresentationValidationResult" + "$ref": "#/components/schemas/IVerifySdJwtVcPresentationResult" } } } diff --git a/packages/sd-jwt/src/types.ts b/packages/sd-jwt/src/types.ts index 283d4ae5d..36621df88 100644 --- a/packages/sd-jwt/src/types.ts +++ b/packages/sd-jwt/src/types.ts @@ -1,239 +1,183 @@ -import { - IAgentContext, - ICredentialIssuer, - IDataStoreORM, - IDIDManager, - IKeyManager, - IPluginMethodMap, - UniqueVerifiableCredential, - VerifiablePresentation, -} from '@veramo/core-types' +import { Hasher, KBOptions, SaltGenerator } from '@sd-jwt/types' +import { SdJwtVcPayload } from '@sd-jwt/sd-jwt-vc' +import { IAgentContext, IDIDManager, IKeyManager, IPluginMethodMap, IResolver } from '@veramo/core-types' /** - * Used for requesting Credentials using Selective Disclosure. - * Represents an accepted issuer of a credential. - * - * @beta This API may change without a BREAKING CHANGE notice. + * My Agent Plugin description. + * + * This is the interface that describes what your plugin can do. + * The methods listed here, will be directly available to the veramo agent where your plugin is going to be used. + * Depending on the agent configuration, other agent plugins, as well as the application where the agent is used + * will be able to call these methods. + * + * To build a schema for your plugin using standard tools, you must link to this file in your package.json. + * Example: + * ``` + * "veramo": { + * "pluginInterfaces": { + * "IMyAgentPlugin": "./src/types/IMyAgentPlugin.ts" + * } + * }, + * ``` + * + * @beta */ -export interface Issuer { +export interface ISDJwtPlugin extends IPluginMethodMap { /** - * The DID of the issuer of a requested credential. + * Your plugin method description + * + * @param args - Input parameters for this method + * @param context - The required context where this method can run. + * Declaring a context type here lets other developers know which other plugins + * need to also be installed for this method to work. */ - did: string - /** - * A URL where a credential of that type can be obtained. + * Create a signed SD-JWT credential. + * @param args - Arguments necessary for the creation of a SD-JWT credential. + * @param context - This reserved param is automatically added and handled by the framework, *do not override* */ - url: string -} + createSdJwtVc(args: ICreateSdJwtVcArgs, context: IRequiredContext): Promise -/** - * Represents the Selective Disclosure request parameters. - * - * @remarks See - * {@link https://github.com/uport-project/specs/blob/develop/messages/sharereq.md | Selective Disclosure Request} - * - * @beta This API may change without a BREAKING CHANGE notice. */ -export interface ISelectiveDisclosureRequest { - /** - * The issuer of the request - */ - issuer: string /** - * The target of the request + * Create a signed SD-JWT presentation. + * @param args - Arguments necessary for the creation of a SD-JWT presentation. + * @param context - This reserved param is automatically added and handled by the framework, *do not override* */ - subject?: string - /** - * The URL where the response should be sent back - */ - replyUrl?: string - - tag?: string + createSdJwtVcPresentation( + args: ICreateSdJwtVcPresentationArgs, + context: IRequiredContext, + ): Promise /** - * A list of claims that are being requested + * Verify a signed SD-JWT credential. + * @param args - Arguments necessary for the verification of a SD-JWT credential. + * @param context - This reserved param is automatically added and handled by the framework, *do not override* */ - claims: ICredentialRequestInput[] + verifySdJwtVc(args: IVerifySdJwtVcArgs, context: IRequiredContext): Promise /** - * A list of issuer credentials that the target will use to establish trust + * Verify a signed SD-JWT presentation. + * @param args - Arguments necessary for the verification of a SD-JWT presentation. + * @param context - This reserved param is automatically added and handled by the framework, *do not override* */ - credentials?: string[] + verifySdJwtVcPresentation( + args: IVerifySdJwtVcPresentationArgs, + context: IRequiredContext, + ): Promise } /** - * Describes a particular credential that is being requested - * - * @remarks See - * {@link https://github.com/uport-project/specs/blob/develop/messages/sharereq.md | Selective Disclosure Request} + * ICreateSdJwtVcArgs * - * @beta This API may change without a BREAKING CHANGE notice. */ -export interface ICredentialRequestInput { - /** - * Motive for requiring this credential. - */ - reason?: string - - /** - * If it is essential. A response that does not include this credential is not sufficient. - */ - essential?: boolean + * @beta + */ +export interface ICreateSdJwtVcArgs { + credentialPayload: SdJwtVcPayload - /** - * The credential type. See {@link https://www.w3.org/TR/vc-data-model/#types | W3C Credential Types} - */ - credentialType?: string + // biome-ignore lint/suspicious/noExplicitAny: + disclosureFrame?: any +} +/** + * ICreateSdJwtVcResult + * + * @beta + */ +export interface ICreateSdJwtVcResult { /** - * The credential context. See {@link https://www.w3.org/TR/vc-data-model/#contexts | W3C Credential Context} + * the encoded sd-jwt credential */ - credentialContext?: string + credential: string +} +/** + * + * @beta + */ +export interface ICreateSdJwtVcPresentationArgs { /** - * The name of the claim property that the credential should express. + * Encoded SD-JWT credential */ - claimType: string + presentation: string - /** - * The value of the claim that the credential should express. + /* + * The keys to use for selective disclosure for presentation + * if not provided, all keys will be disclosed + * if empty array, no keys will be disclosed */ - claimValue?: string + presentationKeys?: string[] /** - * A list of accepted Issuers for this credential. + * Information to include to add key binding. */ - issuers?: Issuer[] + kb?: KBOptions } /** - * The credentials that make up a response of a Selective Disclosure - * - * @remarks See - * {@link https://github.com/uport-project/specs/blob/develop/messages/sharereq.md | Selective Disclosure Request} - * - * @beta This API may change without a BREAKING CHANGE notice. + * Created presentation + * @beta */ -export interface ICredentialsForSdr extends ICredentialRequestInput { - credentials: UniqueVerifiableCredential[] +export interface ICreateSdJwtVcPresentationResult { + /** + * Encoded presentation. + */ + presentation: string } /** - * The result of a selective disclosure response validation. - * - * @beta This API may change without a BREAKING CHANGE notice. + * @beta */ -export interface IPresentationValidationResult { - valid: boolean - claims: ICredentialsForSdr[] +export interface IVerifySdJwtVcArgs { + credential: string } /** - * Contains the parameters of a Selective Disclosure Request. - * - * @remarks See - * {@link https://github.com/uport-project/specs/blob/develop/messages/sharereq.md | Selective Disclosure Request} - * specs - * - * @beta This API may change without a BREAKING CHANGE notice. + * @beta */ -export interface ICreateSelectiveDisclosureRequestArgs { - data: ISelectiveDisclosureRequest +export type IVerifySdJwtVcResult = { + verifiedPayloads: unknown } /** - * Encapsulates the params needed to gather credentials to fulfill a Selective disclosure request. - * - * @remarks See - * {@link https://github.com/uport-project/specs/blob/develop/messages/sharereq.md | Selective Disclosure Request} - * specs - * - * @beta This API may change without a BREAKING CHANGE notice. + * @beta */ -export interface IGetVerifiableCredentialsForSdrArgs { - /** - * The Selective Disclosure Request (issuer is omitted) - */ - sdr: Omit +export interface IVerifySdJwtVcPresentationArgs { + presentation: string - /** - * The DID of the subject - */ - did?: string + requiredClaimKeys?: string[] + + kb?: boolean } /** - * A tuple used to verify a Selective Disclosure Response. - * Encapsulates the response(`presentation`) and the corresponding request (`sdr`) that made it. - * - * @beta This API may change without a BREAKING CHANGE notice. + * @beta */ -export interface IValidatePresentationAgainstSdrArgs { - presentation: VerifiablePresentation - sdr: ISelectiveDisclosureRequest +export type IVerifySdJwtVcPresentationResult = { + verifiedPayloads: Record } /** - * Profile data + * This context describes the requirements of this plugin. + * For this plugin to function properly, the agent needs to also have other plugins installed that implement the + * interfaces declared here. + * You can also define requirements on a more granular level, for each plugin method or event handler of your plugin. * - * @beta This API may change without a BREAKING CHANGE notice. + * @beta */ -export interface ICreateProfileCredentialsArgs { - /** - * Holder DID - */ - holder: string - /** - * Optional. Verifier DID - */ - verifier?: string - /** - * Optional. Name - */ - name?: string - /** - * Optional. Picture URL - */ - picture?: string - /** - * Optional. URL - */ - url?: string - /** - * Save presentation - */ - save: boolean - /** - * Send presentation - */ - send: boolean +export type IRequiredContext = IAgentContext +export interface SdJWTImplementation { + saltGenerator: SaltGenerator + hasher: Hasher + verifySignature: (data: string, signature: string, publicKey: JsonWebKey) => Promise } -/** - * Describes the interface of a Selective Disclosure plugin. - * - * @remarks See - * {@link https://github.com/uport-project/specs/blob/develop/messages/sharereq.md | Selective Disclosure Request} - * - * @beta This API may change without a BREAKING CHANGE notice. - */ -export interface ISelectiveDisclosure extends IPluginMethodMap { - createSelectiveDisclosureRequest( - args: ICreateSelectiveDisclosureRequestArgs, - context: IAgentContext, - ): Promise - - getVerifiableCredentialsForSdr( - args: IGetVerifiableCredentialsForSdrArgs, - context: IAgentContext, - ): Promise> - - validatePresentationAgainstSdr( - args: IValidatePresentationAgainstSdrArgs, - context: IAgentContext<{}>, - ): Promise - - createProfilePresentation( - args: ICreateProfileCredentialsArgs, - context: IAgentContext, - ): Promise +export interface Claims { + /** + * Subject of the SD-JWT + */ + sub?: string + cnf?: { + jwk: JsonWebKey + } + [key: string]: unknown } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 59d36187c..56d2f0263 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1303,17 +1303,23 @@ importers: packages/sd-jwt: dependencies: '@sd-jwt/core': - specifier: next - version: 0.3.2-next.66 + specifier: 0.3.2-next.102 + version: 0.3.2-next.102 '@sd-jwt/crypto-nodejs': - specifier: 0.3.2-next.63 - version: 0.3.2-next.63 + specifier: 0.3.2-next.102 + version: 0.3.2-next.102 + '@sd-jwt/sd-jwt-vc': + specifier: 0.3.2-next.102 + version: 0.3.2-next.102 '@sd-jwt/types': - specifier: 0.3.2-next.63 - version: 0.3.2-next.63 + specifier: 0.3.2-next.102 + version: 0.3.2-next.102 '@sd-jwt/utils': - specifier: next - version: 0.3.2-next.66 + specifier: 0.3.2-next.102 + version: 0.3.2-next.102 + '@sphereon/ssi-sdk-ext.did-utils': + specifier: ^0.16.0 + version: 0.16.0(expo-crypto@12.8.1)(expo@49.0.21)(msrcrypto@1.5.8)(react-native-securerandom@1.0.1) '@veramo/core-types': specifier: workspace:^ version: link:../core-types @@ -7142,6 +7148,13 @@ packages: '@ethersproject/logger': 5.7.0 dev: false + /@ethersproject/random@5.7.0: + resolution: {integrity: sha512-19WjScqRA8IIeWclFme75VMXSBvi4e6InrUNuaR4s5pTF2qNhcGdCUwdxUVGtDDqC00sDLCO93jPQoDUH4HVmQ==} + dependencies: + '@ethersproject/bytes': 5.7.0 + '@ethersproject/logger': 5.7.0 + dev: false + /@ethersproject/rlp@5.7.0: resolution: {integrity: sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w==} dependencies: @@ -9478,37 +9491,45 @@ packages: '@noble/hashes': 1.3.3 '@scure/base': 1.1.3 - /@sd-jwt/core@0.3.2-next.66: - resolution: {integrity: sha512-eaD2hMNfnfxjGtGzXTYfFXJ3iRa/juH7Bv7uAHpfcYP25tSUhAnXEhVaW+rtB4GjNm0xYUwvI6CB78DaNmhSsQ==} + /@sd-jwt/core@0.3.2-next.102: + resolution: {integrity: sha512-dAe83nxOEK5Ogf0r/DZ/cjD+YzLOp/1Pu8zWbWHastKMzUsjr+Qp/0SNBBJwXCplYEiHN++0M4pKLSI4J36bIQ==} + engines: {node: '>=16'} dependencies: - '@sd-jwt/decode': 0.3.2-next.66 - '@sd-jwt/types': 0.3.2-next.66 - '@sd-jwt/utils': 0.3.2-next.66 + '@sd-jwt/decode': 0.3.2-next.102 + '@sd-jwt/types': 0.3.2-next.102 + '@sd-jwt/utils': 0.3.2-next.102 dev: false - /@sd-jwt/crypto-nodejs@0.3.2-next.63: - resolution: {integrity: sha512-6W3u6nXYcl0Ivaim9v4s2atohJYpnZCRgHopCuMtDQwNglPPRKrDY2oZBHDyc52O3/XY1zPxY2s7y0ZA0obx1w==} + /@sd-jwt/crypto-nodejs@0.3.2-next.102: + resolution: {integrity: sha512-wMJHAZ1/SPNkrU+0L7TiZq3y1DNXhRWep8mGtFynuAQuKwOq+VQD8Ck6vfBsHJjb79whBoGg5Egh6n2sx7FUbQ==} + engines: {node: '>=16'} dev: false - /@sd-jwt/decode@0.3.2-next.66: - resolution: {integrity: sha512-xrOA91GdiCAWE8whU/wU+J/n3/Gns1sP6VJa24yU99B6/v8UW2qtBj3aFBmqfFwEXw6webgdP+Bnd9ssKqnSYw==} + /@sd-jwt/decode@0.3.2-next.102: + resolution: {integrity: sha512-9Zdekfqmh3aSvtAzJ1Pjn59rOY9wph77tfUjjyVs+IXxwUCQVXSmsa2egGIMjBaiW0eme6qt+Umy2T6QHPK8SQ==} + engines: {node: '>=16'} dependencies: - '@sd-jwt/types': 0.3.2-next.66 - '@sd-jwt/utils': 0.3.2-next.66 + '@sd-jwt/types': 0.3.2-next.102 + '@sd-jwt/utils': 0.3.2-next.102 dev: false - /@sd-jwt/types@0.3.2-next.63: - resolution: {integrity: sha512-6FG9n/RYJK5YRU8GI/61rBYPZ/0N+nq1CJ2MAUyv9jHX3FzVHACVoyIwxPaAXHgRFGGgn5WwwL1uqC2c/8Arnw==} + /@sd-jwt/sd-jwt-vc@0.3.2-next.102: + resolution: {integrity: sha512-UHgolIi2rjbQFMLEnyaFzUXmkRqRSDRVcxKeCb7fevcVQaR/95+R1n5nXk/0Rr0X2pJnDstlHXYNEhL2FObMmw==} + engines: {node: '>=16'} + dependencies: + '@sd-jwt/core': 0.3.2-next.102 dev: false - /@sd-jwt/types@0.3.2-next.66: - resolution: {integrity: sha512-lENdXY0scVrkNby1RoH8TjKn2QrRDAT+Uxk2J7BFHDM68elIdCbgB/+MgB+S40aozaRINrPG72kDNeKItPwZiA==} + /@sd-jwt/types@0.3.2-next.102: + resolution: {integrity: sha512-kLgkCzteXWtmZLjatsRjYdIZzlOGH8YCCl59G7CkAXR63hsRmqjV7ixjJuciCs4QzWNqYsfD1kRUtuC1TnOZOA==} + engines: {node: '>=16'} dev: false - /@sd-jwt/utils@0.3.2-next.66: - resolution: {integrity: sha512-iXQxzCnl+mkTCwu+Hmj8OIrK4sJxxjRDigOMfz04dgIlkStxQFCwvyLgHyeKYNQulKnuI0Sor+TK+xCZ84Lq3g==} + /@sd-jwt/utils@0.3.2-next.102: + resolution: {integrity: sha512-x/9h4pb+7GLqzdyuVcwCXIBTWDPnsZWI6gX8ZBQ5EQrUg+CZtaGZom9XTxeBW619UM/KuwZDwXv21M5+yAg+uA==} + engines: {node: '>=16'} dependencies: - '@sd-jwt/types': 0.3.2-next.66 + '@sd-jwt/types': 0.3.2-next.102 js-base64: 3.7.7 dev: false @@ -9732,6 +9753,15 @@ packages: engines: {node: '>= 8'} dev: true + /@sphereon/did-uni-client@0.6.1: + resolution: {integrity: sha512-ryIPq9fAp8UuaN0ZQ16Gong5n5SX8G+SjNQ3x3Uy/pmd6syxh97kkmrfbna7a8dTmbP8YdNtgPLpcNbhLPMClQ==} + dependencies: + cross-fetch: 4.0.0 + did-resolver: 4.1.0 + transitivePeerDependencies: + - encoding + dev: false + /@sphereon/ion-pow@0.2.0(@sphereon/react-native-argon2@2.0.9)(react-native@0.73.0): resolution: {integrity: sha512-SpEG4mV5D+K/jrqGI9QSBPPKO5+Kpu6F3cINBKbWiz+ZI4boWwz9JAdNspD45YnnMqTbR14CDEGtHwOaHboJQg==} peerDependencies: @@ -9795,6 +9825,74 @@ packages: react-native: 0.73.0(@babel/core@7.23.6)(@babel/preset-env@7.23.6)(react@18.2.0) dev: false + /@sphereon/ssi-sdk-ext.did-utils@0.16.0(expo-crypto@12.8.1)(expo@49.0.21)(msrcrypto@1.5.8)(react-native-securerandom@1.0.1): + resolution: {integrity: sha512-v7Uy0OqrxglxA3kG8rBUbE6mI7NXK5Fl3moO+7+waXu1R120kJKEyHGDKJaU5BN8Mlr2AURfguBdw2ls0yxYIw==} + dependencies: + '@ethersproject/transactions': 5.7.0 + '@sphereon/did-uni-client': 0.6.1 + '@sphereon/ssi-sdk-ext.key-utils': 0.16.0(expo-crypto@12.8.1)(expo@49.0.21)(msrcrypto@1.5.8)(react-native-securerandom@1.0.1) + '@sphereon/ssi-sdk.core': 0.17.1 + '@stablelib/ed25519': 1.0.3 + '@veramo/core': 4.2.0 + '@veramo/utils': 4.2.0 + did-jwt: 6.11.6 + did-resolver: 4.1.0 + elliptic: 6.5.4 + uint8arrays: 3.1.1 + transitivePeerDependencies: + - encoding + - expo + - expo-crypto + - msrcrypto + - react-native-securerandom + - supports-color + dev: false + + /@sphereon/ssi-sdk-ext.key-utils@0.16.0(expo-crypto@12.8.1)(expo@49.0.21)(msrcrypto@1.5.8)(react-native-securerandom@1.0.1): + resolution: {integrity: sha512-gaPgoAG2R5pBdMwktPKP39QrcMUc5ny3U9fmzSdlBky0n0BCXv+ifeCSuVSFKQP5tBPeOKPyMH/JcaQWxoFzkA==} + dependencies: + '@ethersproject/random': 5.7.0 + '@sphereon/isomorphic-webcrypto': 2.4.0-unstable.4(expo-crypto@12.8.1)(expo@49.0.21)(msrcrypto@1.5.8)(react-native-securerandom@1.0.1) + '@stablelib/ed25519': 1.0.3 + '@stablelib/sha256': 1.0.1 + '@stablelib/sha512': 1.0.1 + '@veramo/core': 4.2.0 + base64url: 3.0.1 + debug: 4.3.4 + did-resolver: 4.1.0 + elliptic: 6.5.4 + lodash.isplainobject: 4.0.6 + multiformats: 9.9.0 + uint8arrays: 3.1.1 + varint: 6.0.0 + web-encoding: 1.1.5 + transitivePeerDependencies: + - expo + - expo-crypto + - msrcrypto + - react-native-securerandom + - supports-color + dev: false + + /@sphereon/ssi-sdk.core@0.17.1: + resolution: {integrity: sha512-SoyfdN5gLecD/rxci1g8vE6YJLjOR/EnYQAp12gIuaKhdzP4MvRjZPng33NgwdhO8n+iZqaWkcAr9vXP5w2NBw==} + dependencies: + '@sphereon/ssi-types': 0.17.1 + '@veramo/core': 4.2.0 + cross-fetch: 3.1.8 + image-size: 1.0.2 + uint8arrays: 3.1.1 + transitivePeerDependencies: + - encoding + - supports-color + dev: false + + /@sphereon/ssi-types@0.17.1: + resolution: {integrity: sha512-EMcarIgHYhZVscuNuQCHP+AHOB2vePI79acOYmCYq04hiDI5z1FnY/29KMSwGnPwXabnMOxmkdcdrtU5RVW1bA==} + dependencies: + jwt-decode: 3.1.2 + dev: false + /@sqltools/formatter@1.2.5: resolution: {integrity: sha512-Uy0+khmZqUrUGm5dmMqVlnvufZRSK0FbYzVgp0UMstm+F5+W2/jnEEQyc9vo1ZR/E5ZI/B1WjjoTqBqwJL6Krw==} @@ -9923,6 +10021,14 @@ packages: '@stablelib/wipe': 1.0.1 dev: false + /@stablelib/sha256@1.0.1: + resolution: {integrity: sha512-GIIH3e6KH+91FqGV42Kcj71Uefd/QEe7Dy42sBTeqppXV95ggCcxLTk39bEr+lZfJmp+ghsR07J++ORkRELsBQ==} + dependencies: + '@stablelib/binary': 1.0.1 + '@stablelib/hash': 1.0.1 + '@stablelib/wipe': 1.0.1 + dev: false + /@stablelib/sha512@1.0.1: resolution: {integrity: sha512-13gl/iawHV9zvDKciLo1fQ8Bgn2Pvf7OV6amaRVKiq3pjQ3UmEpXxWiAfV8tYjUpeZroBxtyrwtdooQT/i3hzw==} dependencies: @@ -11009,6 +11115,39 @@ packages: wonka: 4.0.15 dev: false + /@veramo/core@4.2.0: + resolution: {integrity: sha512-HIqbXfCbwOAJelR5Ohsm22vr63cy6ND8Ua/+9wfMDAiymUUS7NryaJ/v6NRtnmIrNZqUMDdR9/TWdp4cCq5eBg==} + dependencies: + credential-status: 2.0.6 + debug: 4.3.4 + did-jwt-vc: 3.2.15 + did-resolver: 4.1.0 + events: 3.3.0 + z-schema: 5.0.5 + transitivePeerDependencies: + - supports-color + dev: false + + /@veramo/utils@4.2.0: + resolution: {integrity: sha512-jHkli0Qz9rFsWzPAdfJP3P2MFxvVMZPDXZvtVBm8x1fjAGrw/Htz/c5drhDAeBXnqPd9011/7cyvp6AOvdbc8Q==} + dependencies: + '@ethersproject/transactions': 5.7.0 + '@stablelib/ed25519': 1.0.3 + '@veramo/core': 4.2.0 + blakejs: 1.2.1 + cross-fetch: 3.1.8 + debug: 4.3.4 + did-jwt: 6.11.6 + did-jwt-vc: 3.2.15 + did-resolver: 4.1.0 + elliptic: 6.5.4 + multiformats: 9.7.1 + uint8arrays: 3.1.1 + transitivePeerDependencies: + - encoding + - supports-color + dev: false + /@webassemblyjs/ast@1.11.1: resolution: {integrity: sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==} dependencies: @@ -11152,6 +11291,12 @@ packages: argparse: 2.0.1 dev: true + /@zxing/text-encoding@0.9.0: + resolution: {integrity: sha512-U/4aVJ2mxI0aDNI8Uq0wEhMgY+u4CNtEb0om3+y3+niDAsoTCOB33UF0sxpzqzdqXLqmvc+vZyAt4O8pPdfkwA==} + requiresBuild: true + dev: false + optional: true + /JSONStream@1.3.5: resolution: {integrity: sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==} hasBin: true @@ -12356,6 +12501,10 @@ packages: resolution: {integrity: sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==} dev: true + /bech32@2.0.0: + resolution: {integrity: sha512-LcknSilhIGatDAsY1ak2I8VtGaHNhgMSYVxFrGLXv+xLHytaKZKcaUJJUE7qmBr7h33o5YQwP55pMI0xmkpJwg==} + dev: false + /before-after-hook@2.2.3: resolution: {integrity: sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==} dev: true @@ -12412,6 +12561,10 @@ packages: inherits: 2.0.4 readable-stream: 3.6.2 + /blakejs@1.2.1: + resolution: {integrity: sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==} + dev: false + /blessed@0.1.81: resolution: {integrity: sha512-LoF5gae+hlmfORcG1M5+5XZi4LBmvlXTzwJWzUlPryN/SJdSflZvROM2TwkT0GMpq7oqT48NRd4GS7BiVBc5OQ==} engines: {node: '>= 0.8.0'} @@ -13683,6 +13836,13 @@ packages: /create-require@1.1.1: resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} + /credential-status@2.0.6: + resolution: {integrity: sha512-l5ZwSbX/UXFJ3DQ3dFt4rc2BtfUu/rhlkefR7BL9EZsKPyCe21okJA9mDy4h/nXvMEwpYjSQEa5vzR7KZqhI9g==} + dependencies: + did-jwt: 6.11.6 + did-resolver: 4.1.0 + dev: false + /credential-status@3.0.0: resolution: {integrity: sha512-kCHyxp+dtFVV1wy0auNZXwWWLIUmQTuw6uFLfdm5aRaN5JUWyR2Bv6aHLszB8sxEwRYgL6bqfQAUVCXTWo61jw==} dependencies: @@ -14351,6 +14511,14 @@ packages: resolution: {integrity: sha512-Ctp4hInA0BEavlUoRy9mhGq0i+JSo/AwVyX2EFgZmV1kYB+Zq+EMBAn52QWu6FbRr10hRb6pBl420upbp4++vg==} dev: true + /did-jwt-vc@3.2.15: + resolution: {integrity: sha512-M/WPiL34CQUiN4bvWnZ0OFHJ3usPtstfQfbNbHAWHvwjeCGi7nAdv62VXHgy2xIhJMc790hH7PsMN3i6SCGEyg==} + engines: {node: '>=18'} + dependencies: + did-jwt: 7.4.7 + did-resolver: 4.1.0 + dev: false + /did-jwt-vc@4.0.0: resolution: {integrity: sha512-lplB8Ksehx1gn/FQZQ8hW+9KziTqOHsNKqIFBIw26n2mCi+mbDJUyAmJ/rqQoN4OOUm97bdI39HS/b8KDE4drg==} engines: {node: '>=18'} @@ -14358,6 +14526,23 @@ packages: did-jwt: 8.0.0 did-resolver: 4.1.0 + /did-jwt@6.11.6: + resolution: {integrity: sha512-OfbWknRxJuUqH6Lk0x+H1FsuelGugLbBDEwsoJnicFOntIG/A4y19fn0a8RLxaQbWQ5gXg0yDq5E2huSBiiXzw==} + dependencies: + '@stablelib/ed25519': 1.0.3 + '@stablelib/random': 1.0.2 + '@stablelib/sha256': 1.0.1 + '@stablelib/x25519': 1.0.3 + '@stablelib/xchacha20poly1305': 1.0.1 + bech32: 2.0.0 + canonicalize: 2.0.0 + did-resolver: 4.1.0 + elliptic: 6.5.4 + js-sha3: 0.8.0 + multiformats: 9.9.0 + uint8arrays: 3.1.1 + dev: false + /did-jwt@7.4.2: resolution: {integrity: sha512-bdMVrUKD8wBiYihrxm5Bso33vYuw5DHxxN6y+IFSpHQpYQF16nuW6T8+FCrVkS5gDYE6jFZmnkqjJwycT4K7AA==} dependencies: @@ -14371,6 +14556,20 @@ packages: uint8arrays: 4.0.6 dev: false + /did-jwt@7.4.7: + resolution: {integrity: sha512-Apz7nIfIHSKWIMaEP5L/K8xkwByvjezjTG0xiqwKdnNj1x8M0+Yasury5Dm/KPltxi2PlGfRPf3IejRKZrT8mQ==} + dependencies: + '@noble/ciphers': 0.4.1 + '@noble/curves': 1.2.0 + '@noble/hashes': 1.3.3 + '@scure/base': 1.1.3 + canonicalize: 2.0.0 + did-resolver: 4.1.0 + multibase: 4.0.6 + multiformats: 9.9.0 + uint8arrays: 3.1.1 + dev: false + /did-jwt@8.0.0: resolution: {integrity: sha512-lJSVC9Ckxl+U+jDPbdATDtXV7CwE0XGT0Js6KNfjRlaj0LTXvDF90IAyayFwLUzO6punA/q3ZHVfTZaYDhHrLw==} dependencies: @@ -19257,6 +19456,10 @@ packages: object.assign: 4.1.4 dev: true + /jwt-decode@3.1.2: + resolution: {integrity: sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==} + dev: false + /keccak@3.0.2: resolution: {integrity: sha512-PyKKjkH53wDMLGrvmRGSNWgmSxZOUqbnXwKL9tmgbFYA1iAYqW21kfR7mZXV0MlESiefxQQE9X9fTa3X+2MPDQ==} engines: {node: '>=10.0.0'} @@ -19731,7 +19934,6 @@ packages: /lodash.isplainobject@4.0.6: resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==} - dev: true /lodash.isstring@4.0.1: resolution: {integrity: sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==} @@ -20626,6 +20828,10 @@ packages: /multiformats@13.1.0: resolution: {integrity: sha512-HzdtdBwxsIkzpeXzhQ5mAhhuxcHbjEHH+JQoxt7hG/2HGFjjwyolLo7hbaexcnhoEuV4e0TNJ8kkpMjiEYY4VQ==} + /multiformats@9.7.1: + resolution: {integrity: sha512-TaVmGEBt0fhxiNJMGphBfB+oGvUxFs8KgGvgl8d3C+GWtrFcvXdJ2196eg+dYhmSFClmgFfSfJEklo+SZzdNuw==} + dev: false + /multiformats@9.9.0: resolution: {integrity: sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg==} @@ -26397,6 +26603,10 @@ packages: resolution: {integrity: sha512-lKxKYG6H03yCZUpAGOPOsMcGxd1RHCu1iKvEHYDPmTyq2HueGhD73ssNBqqQWfvYs04G9iUFRvmAVLW20Jw6ow==} dev: false + /varint@6.0.0: + resolution: {integrity: sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==} + dev: false + /vary@1.1.2: resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} engines: {node: '>= 0.8'} @@ -26486,6 +26696,14 @@ packages: transitivePeerDependencies: - encoding + /web-encoding@1.1.5: + resolution: {integrity: sha512-HYLeVCdJ0+lBYV2FvNZmv3HJ2Nt0QYXqZojk3d9FJOLkwnuhzM9tmamh8d7HPM8QqjKH8DeHkFTx+CFlWpZZDA==} + dependencies: + util: 0.12.5 + optionalDependencies: + '@zxing/text-encoding': 0.9.0 + dev: false + /web-streams-polyfill@3.2.1: resolution: {integrity: sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==} engines: {node: '>= 8'} From 6855eab4dde318c5b22c8a1f9f480e5e1aa7eaf6 Mon Sep 17 00:00:00 2001 From: "Lukas.J.Han" Date: Mon, 4 Mar 2024 00:13:22 +0900 Subject: [PATCH 03/19] test: remove test Signed-off-by: Lukas --- .../__tests__/validate-presentation.test.ts | 143 ------------------ 1 file changed, 143 deletions(-) delete mode 100644 packages/sd-jwt/src/__tests__/validate-presentation.test.ts diff --git a/packages/sd-jwt/src/__tests__/validate-presentation.test.ts b/packages/sd-jwt/src/__tests__/validate-presentation.test.ts deleted file mode 100644 index ac5705e3d..000000000 --- a/packages/sd-jwt/src/__tests__/validate-presentation.test.ts +++ /dev/null @@ -1,143 +0,0 @@ -import { IAgentContext, VerifiableCredential, VerifiablePresentation } from '../../../core-types/src' -import { ISelectiveDisclosureRequest } from '../types.js' -import { SelectiveDisclosure } from '../action-handler.js' -import { jest } from '@jest/globals' - -const actionHandler = new SelectiveDisclosure() - -const context = { - agent: { - execute: jest.fn(), - availableMethods: jest.fn(), - getSchema: jest.fn(), - emit: jest.fn(), - }, -} as IAgentContext - -describe('@veramo/selective-disclosure-helper', () => { - it('should validate presentation for sdr', async () => { - const sdr: ISelectiveDisclosureRequest = { - issuer: 'did:example:123', - replyUrl: 'https://example.com/didcomm', - tag: 'session-123', - claims: [ - { - reason: 'We are required by law to collect this information', - claimType: 'firstName', - essential: true, - }, - { - reason: 'You can get %30 discount if you are a member of the club', - credentialContext: 'https://www.w3.org/2018/credentials/v1', - credentialType: 'ClubMembership', - claimType: 'status', - claimValue: 'member', - issuers: [ - { - did: 'did:ethr:567', - url: 'https://join-the-club.partner1.com', - }, - { - did: 'did:ethr:659', - url: 'https://ecosystem.io', - }, - ], - }, - ], - credentials: ['JWT-public-profile...'], - } - - const did1 = 'did:example:555' - const did2 = 'did:ethr:659' - - const credential1: VerifiableCredential = { - '@context': ['https://www.w3.org/2018/credentials/v1'], - type: ['VerifiableCredential'], - issuer: { id: did1 }, - issuanceDate: '2012-12-19T06:01:17.171Z', - credentialSubject: { - id: did1, - firstName: 'Alice', - lastName: 'Smith', - }, - proof: { - jwt: 'mock', - }, - } - - const credential2: VerifiableCredential = { - '@context': ['https://www.w3.org/2018/credentials/v1'], - type: ['VerifiableCredential', 'ClubMembership'], - issuer: { id: did2 }, - issuanceDate: '2012-12-19T06:01:17.171Z', - credentialSubject: { - id: did1, - status: 'member', - }, - proof: { - jwt: 'mock', - }, - } - - const presentation: VerifiablePresentation = { - holder: did1, - verifier: [did1], - type: ['VerifiablePresentation'], - '@context': ['https://www.w3.org/2018/credentials/v1'], - verifiableCredential: [credential1, credential2], - proof: { - jwt: 'mock', - }, - } - - const result = await actionHandler.validatePresentationAgainstSdr({ presentation, sdr }, context) - - expect(result.claims[0].credentials[0].verifiableCredential.credentialSubject['firstName']).toEqual( - 'Alice', - ) - expect(result.valid).toEqual(true) - }) - - it('should invalidate presentation for sdr', async () => { - const sdr: ISelectiveDisclosureRequest = { - issuer: 'did:example:123', - claims: [ - { - reason: 'We are required by law to collect this information', - claimType: 'firstName', - essential: true, - }, - ], - } - - const did1 = 'did:example:555' - - const credential1: VerifiableCredential = { - '@context': ['https://www.w3.org/2018/credentials/v1'], - type: ['VerifiableCredential'], - issuer: { id: did1 }, - issuanceDate: '2012-12-19T06:01:17.171Z', - credentialSubject: { - id: did1, - lastName: 'Smith', - }, - proof: { - jwt: 'mock', - }, - } - - const presentation: VerifiablePresentation = { - holder: did1, - verifier: [did1], - type: ['VerifiablePresentation'], - '@context': ['https://www.w3.org/2018/credentials/v1'], - verifiableCredential: [credential1], - proof: { - jwt: 'mock', - }, - } - const result = await actionHandler.validatePresentationAgainstSdr({ presentation, sdr }, context) - - expect(result.valid).toEqual(false) - }) -}) From 4554b5fffedad92503e5561e90f50dde628d2875 Mon Sep 17 00:00:00 2001 From: "Lukas.J.Han" Date: Mon, 4 Mar 2024 00:14:14 +0900 Subject: [PATCH 04/19] test: restore test script Signed-off-by: Lukas --- jest.config.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jest.config.mjs b/jest.config.mjs index 0cbfb0ec6..abc3ad6fe 100644 --- a/jest.config.mjs +++ b/jest.config.mjs @@ -18,7 +18,7 @@ const config = { coverageReporters: ['json'], coverageDirectory: './coverage', coverageProvider: 'v8', - testMatch: ['**/sd-jwt/**/__tests__/**/*.test.ts'], + testMatch: ['**/__tests__/**/*.test.ts'], automock: false, // // typescript 5 removes the need to specify relative imports as .js, so we should no longer need this workaround // // but webpack still requires .js specifiers, so we are keeping it for now From d46eae0efc6d8ea3bfa074c993cad411bd99d806 Mon Sep 17 00:00:00 2001 From: Lukas Date: Wed, 6 Mar 2024 14:17:43 +0900 Subject: [PATCH 05/19] wip Signed-off-by: Lukas --- packages/sd-jwt/src/plugin.schema.ts | 336 ++++++++++++--------------- 1 file changed, 155 insertions(+), 181 deletions(-) diff --git a/packages/sd-jwt/src/plugin.schema.ts b/packages/sd-jwt/src/plugin.schema.ts index f7fb76662..2d190fbae 100644 --- a/packages/sd-jwt/src/plugin.schema.ts +++ b/packages/sd-jwt/src/plugin.schema.ts @@ -1,210 +1,184 @@ export const schema = { - "ISDJwtPlugin": { - "components": { - "schemas": { - "ICreateSdJwtVcArgs": { - "type": "object", - "properties": { - "credentialPayload": { - "type": "object", - "properties": { - "iss": { - "type": "string" + ISDJwtPlugin: { + components: { + schemas: { + ICreateSdJwtVcArgs: { + type: 'object', + properties: { + credentialPayload: { + type: 'object', + properties: { + iss: { + type: 'string', }, - "iat": { - "type": "number" + iat: { + type: 'number', }, - "nbf": { - "type": "number" + nbf: { + type: 'number', }, - "exp": { - "type": "number" + exp: { + type: 'number', }, - "cnf": {}, - "vct": { - "type": "string" + cnf: {}, + vct: { + type: 'string', + }, + status: {}, + sub: { + type: 'string', }, - "status": {}, - "sub": { - "type": "string" - } }, - "required": [ - "iss", - "iat", - "vct" - ] + required: ['iss', 'iat', 'vct'], }, - "disclosureFrame": {} + disclosureFrame: {}, }, - "required": [ - "credentialPayload" - ], - "description": "ICreateSdJwtVcArgs" + required: ['credentialPayload'], + description: 'ICreateSdJwtVcArgs', }, - "ICreateSdJwtVcResult": { - "type": "object", - "properties": { - "credential": { - "type": "string", - "description": "the encoded sd-jwt credential" - } - }, - "required": [ - "credential" - ], - "description": "ICreateSdJwtVcResult" + ICreateSdJwtVcResult: { + type: 'object', + properties: { + credential: { + type: 'string', + description: 'the encoded sd-jwt credential', + }, + }, + required: ['credential'], + description: 'ICreateSdJwtVcResult', }, - "ICreateSdJwtVcPresentationArgs": { - "type": "object", - "properties": { - "presentation": { - "type": "string", - "description": "Encoded SD-JWT credential" + ICreateSdJwtVcPresentationArgs: { + type: 'object', + properties: { + presentation: { + type: 'string', + description: 'Encoded SD-JWT credential', }, - "presentationKeys": { - "type": "array", - "items": { - "type": "string" - } + presentationKeys: { + type: 'array', + items: { + type: 'string', + }, }, - "kb": { - "type": "object", - "properties": { - "payload": { - "type": "object", - "properties": { - "iat": { - "type": "number" + kb: { + type: 'object', + properties: { + payload: { + type: 'object', + properties: { + iat: { + type: 'number', }, - "aud": { - "type": "string" + aud: { + type: 'string', + }, + nonce: { + type: 'string', }, - "nonce": { - "type": "string" - } }, - "required": [ - "iat", - "aud", - "nonce" - ] - } + required: ['iat', 'aud', 'nonce'], + }, }, - "required": [ - "payload" - ], - "description": "Information to include to add key binding." - } - }, - "required": [ - "presentation" - ] + required: ['payload'], + description: 'Information to include to add key binding.', + }, + }, + required: ['presentation'], }, - "ICreateSdJwtVcPresentationResult": { - "type": "object", - "properties": { - "presentation": { - "type": "string", - "description": "Encoded presentation." - } - }, - "required": [ - "presentation" - ], - "description": "Created presentation" + ICreateSdJwtVcPresentationResult: { + type: 'object', + properties: { + presentation: { + type: 'string', + description: 'Encoded presentation.', + }, + }, + required: ['presentation'], + description: 'Created presentation', }, - "IVerifySdJwtVcArgs": { - "type": "object", - "properties": { - "credential": { - "type": "string" - } - }, - "required": [ - "credential" - ] + IVerifySdJwtVcArgs: { + type: 'object', + properties: { + credential: { + type: 'string', + }, + }, + required: ['credential'], }, - "IVerifySdJwtVcResult": { - "type": "object", - "properties": { - "verifiedPayloads": {} - }, - "required": [ - "verifiedPayloads" - ] + IVerifySdJwtVcResult: { + type: 'object', + properties: { + verifiedPayloads: {}, + }, + required: ['verifiedPayloads'], }, - "IVerifySdJwtVcPresentationArgs": { - "type": "object", - "properties": { - "presentation": { - "type": "string" + IVerifySdJwtVcPresentationArgs: { + type: 'object', + properties: { + presentation: { + type: 'string', + }, + requiredClaimKeys: { + type: 'array', + items: { + type: 'string', + }, + }, + kb: { + type: 'boolean', }, - "requiredClaimKeys": { - "type": "array", - "items": { - "type": "string" - } + }, + required: ['presentation'], + }, + IVerifySdJwtVcPresentationResult: { + type: 'object', + properties: { + verifiedPayloads: { + type: 'object', + additionalProperties: {}, }, - "kb": { - "type": "boolean" - } }, - "required": [ - "presentation" - ] + required: ['verifiedPayloads'], }, - "IVerifySdJwtVcPresentationResult": { - "type": "object", - "properties": { - "verifiedPayloads": { - "type": "object", - "additionalProperties": {} - } - }, - "required": [ - "verifiedPayloads" - ] - } }, - "methods": { - "createSdJwtVc": { - "description": "Create a signed SD-JWT credential.", - "arguments": { - "$ref": "#/components/schemas/ICreateSdJwtVcArgs" - }, - "returnType": { - "$ref": "#/components/schemas/ICreateSdJwtVcResult" - } + methods: { + createSdJwtVc: { + description: 'Create a signed SD-JWT credential.', + arguments: { + $ref: '#/components/schemas/ICreateSdJwtVcArgs', + }, + returnType: { + $ref: '#/components/schemas/ICreateSdJwtVcResult', + }, + }, + createSdJwtVcPresentation: { + description: 'Create a signed SD-JWT presentation.', + arguments: { + $ref: '#/components/schemas/ICreateSdJwtVcPresentationArgs', + }, + returnType: { + $ref: '#/components/schemas/ICreateSdJwtVcPresentationResult', + }, }, - "createSdJwtVcPresentation": { - "description": "Create a signed SD-JWT presentation.", - "arguments": { - "$ref": "#/components/schemas/ICreateSdJwtVcPresentationArgs" - }, - "returnType": { - "$ref": "#/components/schemas/ICreateSdJwtVcPresentationResult" - } + verifySdJwtVc: { + description: 'Verify a signed SD-JWT credential.', + arguments: { + $ref: '#/components/schemas/IVerifySdJwtVcArgs', + }, + returnType: { + $ref: '#/components/schemas/IVerifySdJwtVcResult', + }, }, - "verifySdJwtVc": { - "description": "Verify a signed SD-JWT credential.", - "arguments": { - "$ref": "#/components/schemas/IVerifySdJwtVcArgs" - }, - "returnType": { - "$ref": "#/components/schemas/IVerifySdJwtVcResult" - } + verifySdJwtVcPresentation: { + description: 'Verify a signed SD-JWT presentation.', + arguments: { + $ref: '#/components/schemas/IVerifySdJwtVcPresentationArgs', + }, + returnType: { + $ref: '#/components/schemas/IVerifySdJwtVcPresentationResult', + }, }, - "verifySdJwtVcPresentation": { - "description": "Verify a signed SD-JWT presentation.", - "arguments": { - "$ref": "#/components/schemas/IVerifySdJwtVcPresentationArgs" - }, - "returnType": { - "$ref": "#/components/schemas/IVerifySdJwtVcPresentationResult" - } - } - } - } - } -} \ No newline at end of file + }, + }, + }, +} From 4bde70c87aa7b86c4e9891f092647a7f472b2918 Mon Sep 17 00:00:00 2001 From: Lukas Date: Wed, 6 Mar 2024 14:29:42 +0900 Subject: [PATCH 06/19] fix: plugin Signed-off-by: Lukas --- packages/sd-jwt/src/plugin.schema.ts | 320 +++++++++++++++------------ 1 file changed, 183 insertions(+), 137 deletions(-) diff --git a/packages/sd-jwt/src/plugin.schema.ts b/packages/sd-jwt/src/plugin.schema.ts index 2d190fbae..0dedbc962 100644 --- a/packages/sd-jwt/src/plugin.schema.ts +++ b/packages/sd-jwt/src/plugin.schema.ts @@ -1,181 +1,227 @@ export const schema = { - ISDJwtPlugin: { - components: { - schemas: { - ICreateSdJwtVcArgs: { - type: 'object', - properties: { - credentialPayload: { - type: 'object', - properties: { - iss: { - type: 'string', - }, - iat: { - type: 'number', - }, - nbf: { - type: 'number', - }, - exp: { - type: 'number', - }, - cnf: {}, - vct: { - type: 'string', - }, - status: {}, - sub: { - type: 'string', - }, + "ISDJwtPlugin": { + "components": { + "schemas": { + "IcreateSDJwtVcArgs": { + "type": 'object', + "properties": { + "credentialPayload": { + "$ref": '#/components/schemas/CredentialPayload', + }, + "disclosureFrame": {}, + }, + "required": ['credentialPayload'], + "description": 'IcreateSDJwtVcArgs', + }, + "CredentialPayload": { + "type": 'object', + "properties": { + "issuer": { + "$ref": '#/components/schemas/IssuerType', + }, + "credentialSubject": { + "$ref": '#/components/schemas/CredentialSubject', + }, + "type": { + "type": 'array', + "items": { + "type": 'string', }, - required: ['iss', 'iat', 'vct'], }, - disclosureFrame: {}, + '@context': { + "$ref": '#/components/schemas/ContextType', + }, + "issuanceDate": { + "$ref": '#/components/schemas/DateType', + }, + "expirationDate": { + "$ref": '#/components/schemas/DateType', + }, + "credentialStatus": { + "$ref": '#/components/schemas/CredentialStatusReference', + }, + "id": { + "type": 'string', + }, }, - required: ['credentialPayload'], - description: 'ICreateSdJwtVcArgs', + "required": ['issuer'], + "description": 'Used as input when creating Verifiable Credentials', }, - ICreateSdJwtVcResult: { - type: 'object', - properties: { - credential: { - type: 'string', - description: 'the encoded sd-jwt credential', + "IssuerType": { + "anyOf": [ + { + "type": 'object', + "properties": { + "id": { + "type": 'string', + }, + }, + "required": ['id'], + }, + { + 'type': 'string', + }, + ], + "description": + 'The issuer of a {@link VerifiableCredential } or the holder of a {@link VerifiablePresentation } .\n\nThe value of the issuer property MUST be either a URI or an object containing an id property. It is RECOMMENDED that the URI in the issuer or its id be one which, if de-referenced, results in a document containing machine-readable information about the issuer that can be used to verify the information expressed in the credential.\n\nSee {@link https://www.w3.org/TR/vc-data-model/#issuer | Issuer data model }', + }, + "CredentialSubject": { + "type": 'object', + "properties": { + "id": { + "type": 'string', }, }, - required: ['credential'], - description: 'ICreateSdJwtVcResult', + "description": + 'The value of the credentialSubject property is defined as a set of objects that contain one or more properties that are each related to a subject of the verifiable credential. Each object MAY contain an id.\n\nSee {@link https://www.w3.org/TR/vc-data-model/#credential-subject | Credential Subject }', }, - ICreateSdJwtVcPresentationArgs: { - type: 'object', - properties: { - presentation: { - type: 'string', - description: 'Encoded SD-JWT credential', + "ContextType": { + "anyOf": [ + { + "type": 'string', }, - presentationKeys: { - type: 'array', - items: { - type: 'string', - }, + { + "type": 'object', }, - kb: { - type: 'object', - properties: { - payload: { - type: 'object', - properties: { - iat: { - type: 'number', - }, - aud: { - type: 'string', - }, - nonce: { - type: 'string', - }, + { + "type": 'array', + "items": { + "anyOf": [ + { + "type": 'string', }, - required: ['iat', 'aud', 'nonce'], - }, + { + "type": 'object', + }, + ], }, - required: ['payload'], - description: 'Information to include to add key binding.', + }, + ], + "description": 'The data type for `@context` properties of credentials, presentations, etc.', + }, + "DateType": { + "type": 'string', + "description": + 'Represents an issuance or expiration date for Credentials / Presentations. This is used as input when creating them.', + }, + "CredentialStatusReference": { + "type": 'object', + "properties": { + "id": { + "type": 'string', + }, + "type": { + "type": 'string', }, }, - required: ['presentation'], + "required": ['id', 'type'], + "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 }', }, - ICreateSdJwtVcPresentationResult: { - type: 'object', - properties: { - presentation: { - type: 'string', - description: 'Encoded presentation.', + "IcreateSDJwtVcResult": { + "type": 'object', + "properties": { + "credential": { + "type": 'string', }, }, - required: ['presentation'], - description: 'Created presentation', + "required": ['credential'], + "description": 'IcreateSDJwtVcResult', }, - IVerifySdJwtVcArgs: { - type: 'object', - properties: { - credential: { - type: 'string', + "ICreateSdJwtVcPresentationArgs": { + "type": 'object', + "properties": { + "presentation": { + "type": 'string', + }, + "presentationKeys": { + "type": 'array', + "items": { + "type": 'string', + }, }, }, - required: ['credential'], + "required": ['presentation'], }, - IVerifySdJwtVcResult: { - type: 'object', - properties: { - verifiedPayloads: {}, + "ICreateSdJwtVcPresentationResult": { + "type": 'object', + "properties": { + "presentation": { + "type": 'string', + }, }, - required: ['verifiedPayloads'], + "required": ['presentation'], }, - IVerifySdJwtVcPresentationArgs: { - type: 'object', - properties: { - presentation: { - type: 'string', + "IVerifySdJwtVcArgs": { + "type": 'object', + "properties": { + "credential": { + "type": 'string', }, - requiredClaimKeys: { - type: 'array', - items: { - type: 'string', - }, + }, + "required": ['credential'], + }, + "IVerifySdJwtVcResult": { + "type": 'object', + }, + "IVerifySdJwtVcPresentationArgs": { + "type": 'object', + "properties": { + "presentation": { + "type": 'string', }, - kb: { - type: 'boolean', + "requiredClaimKeys": { + "type": 'array', + "items": { + "type": 'string', + }, }, }, - required: ['presentation'], + "required": ['presentation'], }, - IVerifySdJwtVcPresentationResult: { - type: 'object', - properties: { - verifiedPayloads: { - type: 'object', - additionalProperties: {}, - }, + "IVerifySdJwtVcPresentationResult": { + "type": 'object', + "properties": { + "verifiedPayloads": {}, }, - required: ['verifiedPayloads'], + "required": ['verifiedPayloads'], }, }, - methods: { - createSdJwtVc: { - description: 'Create a signed SD-JWT credential.', - arguments: { - $ref: '#/components/schemas/ICreateSdJwtVcArgs', + "methods": { + "createSDJwtVc": { + "description": 'Create a signed SD-JWT credential.', + "arguments": { + "$ref": '#/components/schemas/IcreateSDJwtVcArgs', }, - returnType: { - $ref: '#/components/schemas/ICreateSdJwtVcResult', + "returnType": { + "$ref": '#/components/schemas/IcreateSDJwtVcResult', }, }, - createSdJwtVcPresentation: { - description: 'Create a signed SD-JWT presentation.', - arguments: { - $ref: '#/components/schemas/ICreateSdJwtVcPresentationArgs', + "createSdJwtVcPresentation": { + "description": 'Create a signed SD-JWT presentation.', + "arguments": { + "$ref": '#/components/schemas/ICreateSdJwtVcPresentationArgs', }, - returnType: { - $ref: '#/components/schemas/ICreateSdJwtVcPresentationResult', + "returnType": { + "$ref": '#/components/schemas/ICreateSdJwtVcPresentationResult', }, }, - verifySdJwtVc: { - description: 'Verify a signed SD-JWT credential.', - arguments: { - $ref: '#/components/schemas/IVerifySdJwtVcArgs', + "verifySdJwtVc": { + "description": 'Verify a signed SD-JWT credential.', + "arguments": { + "$ref": '#/components/schemas/IVerifySdJwtVcArgs', }, - returnType: { - $ref: '#/components/schemas/IVerifySdJwtVcResult', + "returnType": { + "$ref": '#/components/schemas/IVerifySdJwtVcResult', }, }, - verifySdJwtVcPresentation: { - description: 'Verify a signed SD-JWT presentation.', - arguments: { - $ref: '#/components/schemas/IVerifySdJwtVcPresentationArgs', + "verifySdJwtVcPresentation": { + "description": 'Verify a signed SD-JWT presentation.', + "arguments": { + "$ref": '#/components/schemas/IVerifySdJwtVcPresentationArgs', }, - returnType: { - $ref: '#/components/schemas/IVerifySdJwtVcPresentationResult', + "returnType": { + "$ref": '#/components/schemas/IVerifySdJwtVcPresentationResult', }, }, }, From dd082080417f5e4596818aadbb9259a548bffa32 Mon Sep 17 00:00:00 2001 From: Lukas Date: Wed, 6 Mar 2024 14:30:05 +0900 Subject: [PATCH 07/19] chore: update package Signed-off-by: Lukas --- packages/sd-jwt/package.json | 21 +++-- pnpm-lock.yaml | 169 ++++++++++++++++++++++++++++------- 2 files changed, 153 insertions(+), 37 deletions(-) diff --git a/packages/sd-jwt/package.json b/packages/sd-jwt/package.json index 3327c6fe6..62adfc824 100644 --- a/packages/sd-jwt/package.json +++ b/packages/sd-jwt/package.json @@ -18,11 +18,12 @@ }, "dependencies": { "@sphereon/ssi-sdk-ext.did-utils": "^0.16.0", - "@sd-jwt/core": "0.3.2-next.102", - "@sd-jwt/crypto-nodejs": "0.3.2-next.102", - "@sd-jwt/types": "0.3.2-next.102", - "@sd-jwt/utils": "0.3.2-next.102", - "@sd-jwt/sd-jwt-vc": "0.3.2-next.102", + "@sd-jwt/core": "0.3.2-next.107", + "@sd-jwt/crypto-nodejs": "0.3.2-next.107", + "@sd-jwt/types": "0.3.2-next.107", + "@sd-jwt/utils": "0.3.2-next.107", + "@sd-jwt/decode": "0.3.2-next.107", + "@sd-jwt/sd-jwt-vc": "0.3.2-next.107", "@veramo/core-types": "workspace:^", "@veramo/message-handler": "workspace:^", "@veramo/utils": "workspace:^", @@ -31,9 +32,17 @@ "uuid": "^9.0.0" }, "devDependencies": { + "@veramo/core": "workspace:^", + "@veramo/data-store": "workspace:^", + "@veramo/did-manager": "workspace:^", + "@veramo/did-provider-jwk": "workspace:^", + "@veramo/key-manager": "workspace:^", + "@veramo/kms-local": "workspace:^", + "@veramo/did-resolver": "workspace:^", "@types/debug": "4.1.8", "@types/uuid": "9.0.2", - "typescript": "5.3.3" + "typescript": "5.3.3", + "typeorm": "^0.3.20" }, "files": [ "build/**/*", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 56d2f0263..bd3ddb4ce 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1303,20 +1303,23 @@ importers: packages/sd-jwt: dependencies: '@sd-jwt/core': - specifier: 0.3.2-next.102 - version: 0.3.2-next.102 + specifier: 0.3.2-next.107 + version: 0.3.2-next.107 '@sd-jwt/crypto-nodejs': - specifier: 0.3.2-next.102 - version: 0.3.2-next.102 + specifier: 0.3.2-next.107 + version: 0.3.2-next.107 + '@sd-jwt/decode': + specifier: 0.3.2-next.107 + version: 0.3.2-next.107 '@sd-jwt/sd-jwt-vc': - specifier: 0.3.2-next.102 - version: 0.3.2-next.102 + specifier: 0.3.2-next.107 + version: 0.3.2-next.107 '@sd-jwt/types': - specifier: 0.3.2-next.102 - version: 0.3.2-next.102 + specifier: 0.3.2-next.107 + version: 0.3.2-next.107 '@sd-jwt/utils': - specifier: 0.3.2-next.102 - version: 0.3.2-next.102 + specifier: 0.3.2-next.107 + version: 0.3.2-next.107 '@sphereon/ssi-sdk-ext.did-utils': specifier: ^0.16.0 version: 0.16.0(expo-crypto@12.8.1)(expo@49.0.21)(msrcrypto@1.5.8)(react-native-securerandom@1.0.1) @@ -1345,6 +1348,30 @@ importers: '@types/uuid': specifier: 9.0.2 version: 9.0.2 + '@veramo/core': + specifier: workspace:^ + version: link:../core + '@veramo/data-store': + specifier: workspace:^ + version: link:../data-store + '@veramo/did-manager': + specifier: workspace:^ + version: link:../did-manager + '@veramo/did-provider-jwk': + specifier: workspace:^ + version: link:../did-provider-jwk + '@veramo/did-resolver': + specifier: workspace:^ + version: link:../did-resolver + '@veramo/key-manager': + specifier: workspace:^ + version: link:../key-manager + '@veramo/kms-local': + specifier: workspace:^ + version: link:../kms-local + typeorm: + specifier: ^0.3.20 + version: 0.3.20(ts-node@10.9.2) typescript: specifier: 5.3.3 version: 5.3.3 @@ -9491,45 +9518,45 @@ packages: '@noble/hashes': 1.3.3 '@scure/base': 1.1.3 - /@sd-jwt/core@0.3.2-next.102: - resolution: {integrity: sha512-dAe83nxOEK5Ogf0r/DZ/cjD+YzLOp/1Pu8zWbWHastKMzUsjr+Qp/0SNBBJwXCplYEiHN++0M4pKLSI4J36bIQ==} + /@sd-jwt/core@0.3.2-next.107: + resolution: {integrity: sha512-B77/4i/01R8lnXSfPDITZdN+1MOcviSsgsqlxICOQjSL8eWoKjtMwQvI+e3zHLqVgw2O0p7zbNBDhymqxFR3IA==} engines: {node: '>=16'} dependencies: - '@sd-jwt/decode': 0.3.2-next.102 - '@sd-jwt/types': 0.3.2-next.102 - '@sd-jwt/utils': 0.3.2-next.102 + '@sd-jwt/decode': 0.3.2-next.107 + '@sd-jwt/types': 0.3.2-next.107 + '@sd-jwt/utils': 0.3.2-next.107 dev: false - /@sd-jwt/crypto-nodejs@0.3.2-next.102: - resolution: {integrity: sha512-wMJHAZ1/SPNkrU+0L7TiZq3y1DNXhRWep8mGtFynuAQuKwOq+VQD8Ck6vfBsHJjb79whBoGg5Egh6n2sx7FUbQ==} + /@sd-jwt/crypto-nodejs@0.3.2-next.107: + resolution: {integrity: sha512-thHe0ZGJrja/PY4iAyDblV3axBfPSX9jNMSp4fwuy6nVgMspEZBDpvSMyY+yDVRZe2ol4CNj6uY/1M7imOIOsA==} engines: {node: '>=16'} dev: false - /@sd-jwt/decode@0.3.2-next.102: - resolution: {integrity: sha512-9Zdekfqmh3aSvtAzJ1Pjn59rOY9wph77tfUjjyVs+IXxwUCQVXSmsa2egGIMjBaiW0eme6qt+Umy2T6QHPK8SQ==} + /@sd-jwt/decode@0.3.2-next.107: + resolution: {integrity: sha512-GZBzslcyAYgMzs63BnkOY2+AJVmg2Vh5aAAR1y8TlHzaAe1UxNIiCwLOcJpQt+nkCmBDxO4P9rOLMMBHQ5WFEQ==} engines: {node: '>=16'} dependencies: - '@sd-jwt/types': 0.3.2-next.102 - '@sd-jwt/utils': 0.3.2-next.102 + '@sd-jwt/types': 0.3.2-next.107 + '@sd-jwt/utils': 0.3.2-next.107 dev: false - /@sd-jwt/sd-jwt-vc@0.3.2-next.102: - resolution: {integrity: sha512-UHgolIi2rjbQFMLEnyaFzUXmkRqRSDRVcxKeCb7fevcVQaR/95+R1n5nXk/0Rr0X2pJnDstlHXYNEhL2FObMmw==} + /@sd-jwt/sd-jwt-vc@0.3.2-next.107: + resolution: {integrity: sha512-uIxRpkjrVwSl+Qdc1IEny+3L4s+aeyoWR5Cjy1uvm7e8xkMJMWGbFdXfLGT8fGjFYgEJppAg8bY0kKqZSm0g4Q==} engines: {node: '>=16'} dependencies: - '@sd-jwt/core': 0.3.2-next.102 + '@sd-jwt/core': 0.3.2-next.107 dev: false - /@sd-jwt/types@0.3.2-next.102: - resolution: {integrity: sha512-kLgkCzteXWtmZLjatsRjYdIZzlOGH8YCCl59G7CkAXR63hsRmqjV7ixjJuciCs4QzWNqYsfD1kRUtuC1TnOZOA==} + /@sd-jwt/types@0.3.2-next.107: + resolution: {integrity: sha512-mft02chJEYvucDhD0FM/czILG5SA8DHYHuhl3yWZZx+KUTmtSe3IVfJ4BzZIWPtyr2B2FhEjX9Cz4XjxzDQZ3Q==} engines: {node: '>=16'} dev: false - /@sd-jwt/utils@0.3.2-next.102: - resolution: {integrity: sha512-x/9h4pb+7GLqzdyuVcwCXIBTWDPnsZWI6gX8ZBQ5EQrUg+CZtaGZom9XTxeBW619UM/KuwZDwXv21M5+yAg+uA==} + /@sd-jwt/utils@0.3.2-next.107: + resolution: {integrity: sha512-VdeZLUu2Lj3ZWCqyyETOBM6X1JJufpBzOUJnJK/u0oBuY88DO5u4Ha76u43R+UNgMYgoUad/W5rQl87Bt7w7Ng==} engines: {node: '>=16'} dependencies: - '@sd-jwt/types': 0.3.2-next.102 + '@sd-jwt/types': 0.3.2-next.107 js-base64: 3.7.7 dev: false @@ -14244,7 +14271,6 @@ packages: /dayjs@1.11.10: resolution: {integrity: sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==} - dev: false /debug@2.6.9: resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} @@ -14751,7 +14777,6 @@ packages: /dotenv@16.4.5: resolution: {integrity: sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==} engines: {node: '>=12'} - dev: false /duplexer2@0.1.4: resolution: {integrity: sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==} @@ -23979,6 +24004,10 @@ packages: /reflect-metadata@0.1.13: resolution: {integrity: sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==} + /reflect-metadata@0.2.1: + resolution: {integrity: sha512-i5lLI6iw9AU3Uu4szRNPPEkomnkjRTaVt9hy/bn5g/oSzekBSMeLZblcjP74AW0vBabqERLLIrz+gR8QYR54Tw==} + dev: true + /regenerate-unicode-properties@10.1.0: resolution: {integrity: sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ==} engines: {node: '>=4'} @@ -26247,6 +26276,84 @@ packages: - supports-color dev: false + /typeorm@0.3.20(ts-node@10.9.2): + resolution: {integrity: sha512-sJ0T08dV5eoZroaq9uPKBoNcGslHBR4E4y+EBHs//SiGbblGe7IeduP/IH4ddCcj0qp3PHwDwGnuvqEAnKlq/Q==} + engines: {node: '>=16.13.0'} + hasBin: true + peerDependencies: + '@google-cloud/spanner': ^5.18.0 + '@sap/hana-client': ^2.12.25 + better-sqlite3: ^7.1.2 || ^8.0.0 || ^9.0.0 + hdb-pool: ^0.1.6 + ioredis: ^5.0.4 + mongodb: ^5.8.0 + mssql: ^9.1.1 || ^10.0.1 + mysql2: ^2.2.5 || ^3.0.1 + oracledb: ^6.3.0 + pg: ^8.5.1 + pg-native: ^3.0.0 + pg-query-stream: ^4.0.0 + redis: ^3.1.1 || ^4.0.0 + sql.js: ^1.4.0 + sqlite3: ^5.0.3 + ts-node: ^10.7.0 + typeorm-aurora-data-api-driver: ^2.0.0 + peerDependenciesMeta: + '@google-cloud/spanner': + optional: true + '@sap/hana-client': + optional: true + better-sqlite3: + optional: true + hdb-pool: + optional: true + ioredis: + optional: true + mongodb: + optional: true + mssql: + optional: true + mysql2: + optional: true + oracledb: + optional: true + pg: + optional: true + pg-native: + optional: true + pg-query-stream: + optional: true + redis: + optional: true + sql.js: + optional: true + sqlite3: + optional: true + ts-node: + optional: true + typeorm-aurora-data-api-driver: + optional: true + dependencies: + '@sqltools/formatter': 1.2.5 + app-root-path: 3.1.0 + buffer: 6.0.3 + chalk: 4.1.2 + cli-highlight: 2.1.11 + dayjs: 1.11.10 + debug: 4.3.4 + dotenv: 16.4.5 + glob: 10.3.10 + mkdirp: 2.1.6 + reflect-metadata: 0.2.1 + sha.js: 2.4.11 + ts-node: 10.9.2(@types/node@20.11.19)(typescript@5.3.3) + tslib: 2.6.2 + uuid: 9.0.1 + yargs: 17.7.2 + transitivePeerDependencies: + - supports-color + dev: true + /typescript@5.3.3: resolution: {integrity: sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==} engines: {node: '>=14.17'} From f34f0f92b16ca5a1d0bb00f37e6a73b9ca5f51b4 Mon Sep 17 00:00:00 2001 From: Lukas Date: Wed, 6 Mar 2024 14:30:25 +0900 Subject: [PATCH 08/19] Revert "test: restore test script" This reverts commit 4d0dc75add90c915ffcec53f8eacadb0d21d43f4. Signed-off-by: Lukas --- jest.config.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jest.config.mjs b/jest.config.mjs index abc3ad6fe..0cbfb0ec6 100644 --- a/jest.config.mjs +++ b/jest.config.mjs @@ -18,7 +18,7 @@ const config = { coverageReporters: ['json'], coverageDirectory: './coverage', coverageProvider: 'v8', - testMatch: ['**/__tests__/**/*.test.ts'], + testMatch: ['**/sd-jwt/**/__tests__/**/*.test.ts'], automock: false, // // typescript 5 removes the need to specify relative imports as .js, so we should no longer need this workaround // // but webpack still requires .js specifiers, so we are keeping it for now From bcecbfa11ff52d46f2cc4d7f9cccdc09f8084b9b Mon Sep 17 00:00:00 2001 From: Lukas Date: Wed, 6 Mar 2024 14:30:49 +0900 Subject: [PATCH 09/19] Revert "Revert "test: restore test script"" This reverts commit 63d76ff7c15cbfc6abe13e64eaf0ee3802813481. Signed-off-by: Lukas --- jest.config.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jest.config.mjs b/jest.config.mjs index 0cbfb0ec6..abc3ad6fe 100644 --- a/jest.config.mjs +++ b/jest.config.mjs @@ -18,7 +18,7 @@ const config = { coverageReporters: ['json'], coverageDirectory: './coverage', coverageProvider: 'v8', - testMatch: ['**/sd-jwt/**/__tests__/**/*.test.ts'], + testMatch: ['**/__tests__/**/*.test.ts'], automock: false, // // typescript 5 removes the need to specify relative imports as .js, so we should no longer need this workaround // // but webpack still requires .js specifiers, so we are keeping it for now From 89856651948431213c1b7067e77b8e06c1cd729b Mon Sep 17 00:00:00 2001 From: Lukas Date: Wed, 6 Mar 2024 14:31:39 +0900 Subject: [PATCH 10/19] test: add tests Signed-off-by: Lukas --- packages/sd-jwt/__tests__/sd-jwt.test.ts | 339 +++++++++++++++++++++++ packages/sd-jwt/tsconfig.json | 3 +- 2 files changed, 341 insertions(+), 1 deletion(-) create mode 100644 packages/sd-jwt/__tests__/sd-jwt.test.ts diff --git a/packages/sd-jwt/__tests__/sd-jwt.test.ts b/packages/sd-jwt/__tests__/sd-jwt.test.ts new file mode 100644 index 000000000..4eacd475e --- /dev/null +++ b/packages/sd-jwt/__tests__/sd-jwt.test.ts @@ -0,0 +1,339 @@ +import { subtle } from 'node:crypto' +import { digest, generateSalt } from '@sd-jwt/crypto-nodejs' +import { DisclosureFrame, kbPayload } from '@sd-jwt/types' +import { createAgent } from '@veramo/core' +import { IDIDManager, IKeyManager, IResolver, TAgent } from '@veramo/core-types' +import { DIDManager, MemoryDIDStore } from '@veramo/did-manager' +import { JwkCreateIdentifierOptions, JwkDIDProvider, getDidJwkResolver } from '@veramo/did-provider-jwk' +import { DIDResolverPlugin } from '@veramo/did-resolver' +import { KeyManager, MemoryKeyStore, MemoryPrivateKeyStore } from '@veramo/key-manager' +import { KeyManagementSystem, SecretBox } from '@veramo/kms-local' +import { JwkDidSupportedKeyTypes, createJWK } from '@veramo/utils' +import { DIDDocument, Resolver, VerificationMethod } from 'did-resolver' +import { SdJwtVcPayload } from '@sd-jwt/sd-jwt-vc' +import { decodeSdJwt } from '@sd-jwt/decode' +import { KBJwt } from '@sd-jwt/core' +import { ISDJwtPlugin, SDJwtPlugin } from '../src/index' + +async function verifySignature(data: string, signature: string, key: JsonWebKey) { + let { alg, crv } = key + if (alg === 'ES256') alg = 'ECDSA' + const publicKey = await subtle.importKey( + 'jwk', + key, + { name: alg, namedCurve: crv } as EcKeyImportParams, + true, + ['verify'], + ) + return Promise.resolve( + subtle.verify( + { name: alg as string, hash: 'SHA-256' }, + publicKey, + Buffer.from(signature, 'base64'), + Buffer.from(data), + ), + ) +} + +type AgentType = IDIDManager & IKeyManager & IResolver & ISDJwtPlugin + +describe('Agent plugin', () => { + let agent: TAgent + + let issuer: string + + let holder: string + + // Issuer Define the claims object with the user's information + const claims = { + sub: '', + given_name: 'John', + family_name: 'Deo', + email: 'johndeo@example.com', + phone: '+1-202-555-0101', + address: { + street_address: '123 Main St', + locality: 'Anytown', + region: 'Anystate', + country: 'US', + }, + birthdate: '1940-01-01', + } + + // Issuer Define the disclosure frame to specify which claims can be disclosed + const disclosureFrame: DisclosureFrame = { + _sd: ['given_name', 'family_name', 'email', 'phone', 'address', 'birthdate'], + } + + beforeAll(async () => { + agent = createAgent({ + plugins: [ + new SDJwtPlugin({ + hasher: digest, + saltGenerator: generateSalt, + verifySignature, + }), + new KeyManager({ + store: new MemoryKeyStore(), + kms: { + local: new KeyManagementSystem(new MemoryPrivateKeyStore()), + }, + }), + new DIDResolverPlugin({ + resolver: new Resolver({ + ...getDidJwkResolver(), + }), + }), + new DIDManager({ + store: new MemoryDIDStore(), + defaultProvider: 'did:jwk', + providers: { + 'did:jwk': new JwkDIDProvider({ + defaultKms: 'local', + }), + }, + }), + ], + }) + issuer = await agent + .didManagerCreate({ + kms: 'local', + provider: 'did:jwk', + alias: 'issuer', + //we use this curve since nodejs does not support ES256k which is the default one. + options: { keyType: 'Secp256r1' } as JwkCreateIdentifierOptions, + }) + .then((did) => { + // we add a key reference + return `${did.did}#0` + }) + holder = await agent + .didManagerCreate({ + kms: 'local', + provider: 'did:jwk', + alias: 'holder', + //we use this curve since nodejs does not support ES256k which is the default one. + options: { keyType: 'Secp256r1' } as JwkCreateIdentifierOptions, + }) + .then((did) => `${did.did}#0`) + claims.sub = holder + }) + + it('create a sd-jwt', async () => { + const credentialPayload: SdJwtVcPayload = { + ...claims, + iss: issuer, + iat: new Date().getTime() / 1000, + vct: '', + } + const credential = await agent.createSdJwtVc({ + credentialPayload, + disclosureFrame, + }) + expect(credential).toBeDefined() + }) + + it('create sd without an issuer', async () => { + const credentialPayload = { + ...claims, + iat: new Date().getTime() / 1000, + vct: '', + } + expect( + agent.createSdJwtVc({ + credentialPayload: credentialPayload as unknown as SdJwtVcPayload, + disclosureFrame, + }), + ).rejects.toThrow('credential.issuer must not be empty') + }) + + it('creat sd without the issuers key reference', async () => { + const credentialPayload: SdJwtVcPayload = { + ...claims, + iss: 'did:web:issuer', + iat: new Date().getTime() / 1000, + vct: '', + } + expect( + agent.createSdJwtVc({ + credentialPayload, + disclosureFrame, + }), + ).rejects.toThrow('credential.issuer must reference a key') + }) + + it('verify a sd-jwt', async () => { + const credentialPayload: SdJwtVcPayload = { + ...claims, + iss: issuer, + iat: new Date().getTime() / 1000, + vct: '', + } + const credential = await agent.createSdJwtVc({ + credentialPayload, + disclosureFrame: disclosureFrame, + }) + const verified = await agent.verifySdJwtVc({ + credential: credential.credential, + }) + }, 5000) + + it('create a presentation', async () => { + const credentialPayload: SdJwtVcPayload = { + ...claims, + iss: issuer, + iat: new Date().getTime() / 1000, + vct: '', + } + const credential = await agent.createSdJwtVc({ + credentialPayload, + disclosureFrame, + }) + const presentation = await agent.createSdJwtVcPresentation({ + presentation: credential.credential, + presentationKeys: ['given_name'], + kb: { + payload: { + aud: '1', + iat: 1, + nonce: '342', + }, + }, + }) + expect(presentation).toBeDefined() + const decoded = await decodeSdJwt(presentation.presentation, digest) + expect(decoded.kbJwt).toBeDefined() + expect(((decoded.kbJwt as KBJwt).payload as kbPayload).aud).toBe('1') + }) + + it('create presentation with cnf', async () => { + const did = await agent.didManagerFind({ alias: 'holder' }).then((dids) => dids[0]) + const jwk = createJWK(did.keys[0].type as JwkDidSupportedKeyTypes, did.keys[0].publicKeyHex) as JsonWebKey + const credentialPayload: SdJwtVcPayload = { + ...claims, + cnf: { + jwk, + }, + iss: issuer, + iat: new Date().getTime() / 1000, + vct: '', + } + const credential = await agent.createSdJwtVc({ + credentialPayload, + disclosureFrame, + }) + const presentation = await agent.createSdJwtVcPresentation({ + presentation: credential.credential, + presentationKeys: ['given_name'], + kb: { + payload: { + aud: '1', + iat: 1, + nonce: '342', + }, + }, + }) + expect(presentation).toBeDefined() + const decoded = await decodeSdJwt(presentation.presentation, digest) + expect(decoded.kbJwt).toBeDefined() + expect(((decoded.kbJwt as KBJwt).payload as kbPayload).aud).toBe('1') + }) + + it('includes no holder reference', async () => { + const newClaims = JSON.parse(JSON.stringify(claims)) + newClaims.sub = undefined + const credentialPayload: SdJwtVcPayload = { + ...newClaims, + iss: issuer, + iat: new Date().getTime() / 1000, + vct: '', + } + const credential = await agent.createSdJwtVc({ + credentialPayload, + disclosureFrame, + }) + const presentation = agent.createSdJwtVcPresentation({ + presentation: credential.credential, + presentationKeys: ['given_name'], + kb: { + payload: { + aud: '1', + iat: 1, + nonce: '342', + }, + }, + }) + expect(presentation).rejects.toThrow('credential does not include a holder reference') + }) + + it('verify a presentation', async () => { + const holderDId = await agent.resolveDid({ didUrl: holder }) + const jwk: JsonWebKey = ( + (holderDId.didDocument as DIDDocument).verificationMethod as VerificationMethod[] + )[0].publicKeyJwk as JsonWebKey + const credentialPayload: SdJwtVcPayload = { + ...claims, + iss: issuer, + iat: new Date().getTime() / 1000, + vct: '', + cnf: { + jwk, + }, + } + const credential = await agent.createSdJwtVc({ + credentialPayload, + disclosureFrame, + }) + const presentation = await agent.createSdJwtVcPresentation({ + presentation: credential.credential, + presentationKeys: ['given_name'], + kb: { + payload: { + aud: '1', + iat: 1, + nonce: '342', + }, + }, + }) + const result = await agent.verifySdJwtVcPresentation({ + presentation: presentation.presentation, + requiredClaimKeys: ['given_name'], + // we are not able to verify the kb yet since we have no reference to the public key of the holder. + kb: true, + }) + expect(result).toBeDefined() + expect((result.verifiedPayloads.payload as typeof claims).given_name).toBe('John') + }) + + it('verify a presentation with sub set', async () => { + const credentialPayload: SdJwtVcPayload = { + ...claims, + iss: issuer, + iat: new Date().getTime() / 1000, + vct: '', + } + const credential = await agent.createSdJwtVc({ + credentialPayload, + disclosureFrame, + }) + const presentation = await agent.createSdJwtVcPresentation({ + presentation: credential.credential, + presentationKeys: ['given_name'], + kb: { + payload: { + aud: '1', + iat: 1, + nonce: '342', + }, + }, + }) + const result = await agent.verifySdJwtVcPresentation({ + presentation: presentation.presentation, + requiredClaimKeys: ['given_name'], + // we are not able to verify the kb yet since we have no reference to the public key of the holder. + kb: true, + }) + expect(result).toBeDefined() + expect((result.verifiedPayloads.payload as typeof claims).given_name).toBe('John') + }) +}) diff --git a/packages/sd-jwt/tsconfig.json b/packages/sd-jwt/tsconfig.json index 7dff4d76e..eff722558 100644 --- a/packages/sd-jwt/tsconfig.json +++ b/packages/sd-jwt/tsconfig.json @@ -17,5 +17,6 @@ "path": "../utils" } ], - "include": ["./**/*.ts"] + "include": ["./**/*.ts"], + "exclude": ["__tests__/*"] } From 376924fcd35cfb506aa3e480ae33526c01469612 Mon Sep 17 00:00:00 2001 From: Lukas Date: Wed, 6 Mar 2024 14:30:25 +0900 Subject: [PATCH 11/19] Revert "test: restore test script" This reverts commit 4d0dc75add90c915ffcec53f8eacadb0d21d43f4. Signed-off-by: Lukas --- jest.config.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jest.config.mjs b/jest.config.mjs index abc3ad6fe..0cbfb0ec6 100644 --- a/jest.config.mjs +++ b/jest.config.mjs @@ -18,7 +18,7 @@ const config = { coverageReporters: ['json'], coverageDirectory: './coverage', coverageProvider: 'v8', - testMatch: ['**/__tests__/**/*.test.ts'], + testMatch: ['**/sd-jwt/**/__tests__/**/*.test.ts'], automock: false, // // typescript 5 removes the need to specify relative imports as .js, so we should no longer need this workaround // // but webpack still requires .js specifiers, so we are keeping it for now From a7c7f25dac814ab0f8e726e85aaf32a0aef6d52d Mon Sep 17 00:00:00 2001 From: Lukas Date: Wed, 6 Mar 2024 14:34:36 +0900 Subject: [PATCH 12/19] test: fix tests Signed-off-by: Lukas --- packages/sd-jwt/__tests__/sd-jwt.test.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/sd-jwt/__tests__/sd-jwt.test.ts b/packages/sd-jwt/__tests__/sd-jwt.test.ts index 4eacd475e..1e53332af 100644 --- a/packages/sd-jwt/__tests__/sd-jwt.test.ts +++ b/packages/sd-jwt/__tests__/sd-jwt.test.ts @@ -306,11 +306,18 @@ describe('Agent plugin', () => { }) it('verify a presentation with sub set', async () => { + const holderDId = await agent.resolveDid({ didUrl: holder }) + const jwk: JsonWebKey = ( + (holderDId.didDocument as DIDDocument).verificationMethod as VerificationMethod[] + )[0].publicKeyJwk as JsonWebKey const credentialPayload: SdJwtVcPayload = { ...claims, iss: issuer, iat: new Date().getTime() / 1000, vct: '', + cnf: { + jwk, + }, } const credential = await agent.createSdJwtVc({ credentialPayload, From b0dcab9517b54a61b02eeed6794127cb8b027448 Mon Sep 17 00:00:00 2001 From: Lukas Date: Wed, 6 Mar 2024 14:36:41 +0900 Subject: [PATCH 13/19] Revert "Revert "test: restore test script"" This reverts commit 376924fcd35cfb506aa3e480ae33526c01469612. Signed-off-by: Lukas --- jest.config.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jest.config.mjs b/jest.config.mjs index 0cbfb0ec6..abc3ad6fe 100644 --- a/jest.config.mjs +++ b/jest.config.mjs @@ -18,7 +18,7 @@ const config = { coverageReporters: ['json'], coverageDirectory: './coverage', coverageProvider: 'v8', - testMatch: ['**/sd-jwt/**/__tests__/**/*.test.ts'], + testMatch: ['**/__tests__/**/*.test.ts'], automock: false, // // typescript 5 removes the need to specify relative imports as .js, so we should no longer need this workaround // // but webpack still requires .js specifiers, so we are keeping it for now From da1788470df5bff57d7f1c011ac5f42f98dd3549 Mon Sep 17 00:00:00 2001 From: Lukas Date: Wed, 6 Mar 2024 14:49:38 +0900 Subject: [PATCH 14/19] fix: schema Signed-off-by: Lukas --- packages/sd-jwt/src/plugin.schema.ts | 302 +++++++++++++-------------- 1 file changed, 141 insertions(+), 161 deletions(-) diff --git a/packages/sd-jwt/src/plugin.schema.ts b/packages/sd-jwt/src/plugin.schema.ts index 0dedbc962..f7fb76662 100644 --- a/packages/sd-jwt/src/plugin.schema.ts +++ b/packages/sd-jwt/src/plugin.schema.ts @@ -2,229 +2,209 @@ export const schema = { "ISDJwtPlugin": { "components": { "schemas": { - "IcreateSDJwtVcArgs": { - "type": 'object', + "ICreateSdJwtVcArgs": { + "type": "object", "properties": { "credentialPayload": { - "$ref": '#/components/schemas/CredentialPayload', - }, - "disclosureFrame": {}, - }, - "required": ['credentialPayload'], - "description": 'IcreateSDJwtVcArgs', - }, - "CredentialPayload": { - "type": 'object', - "properties": { - "issuer": { - "$ref": '#/components/schemas/IssuerType', - }, - "credentialSubject": { - "$ref": '#/components/schemas/CredentialSubject', - }, - "type": { - "type": 'array', - "items": { - "type": 'string', - }, - }, - '@context': { - "$ref": '#/components/schemas/ContextType', - }, - "issuanceDate": { - "$ref": '#/components/schemas/DateType', - }, - "expirationDate": { - "$ref": '#/components/schemas/DateType', - }, - "credentialStatus": { - "$ref": '#/components/schemas/CredentialStatusReference', - }, - "id": { - "type": 'string', - }, - }, - "required": ['issuer'], - "description": 'Used as input when creating Verifiable Credentials', - }, - "IssuerType": { - "anyOf": [ - { - "type": 'object', + "type": "object", "properties": { - "id": { - "type": 'string', + "iss": { + "type": "string" + }, + "iat": { + "type": "number" + }, + "nbf": { + "type": "number" + }, + "exp": { + "type": "number" }, + "cnf": {}, + "vct": { + "type": "string" + }, + "status": {}, + "sub": { + "type": "string" + } }, - "required": ['id'], - }, - { - 'type': 'string', - }, - ], - "description": - 'The issuer of a {@link VerifiableCredential } or the holder of a {@link VerifiablePresentation } .\n\nThe value of the issuer property MUST be either a URI or an object containing an id property. It is RECOMMENDED that the URI in the issuer or its id be one which, if de-referenced, results in a document containing machine-readable information about the issuer that can be used to verify the information expressed in the credential.\n\nSee {@link https://www.w3.org/TR/vc-data-model/#issuer | Issuer data model }', - }, - "CredentialSubject": { - "type": 'object', - "properties": { - "id": { - "type": 'string', + "required": [ + "iss", + "iat", + "vct" + ] }, + "disclosureFrame": {} }, - "description": - 'The value of the credentialSubject property is defined as a set of objects that contain one or more properties that are each related to a subject of the verifiable credential. Each object MAY contain an id.\n\nSee {@link https://www.w3.org/TR/vc-data-model/#credential-subject | Credential Subject }', - }, - "ContextType": { - "anyOf": [ - { - "type": 'string', - }, - { - "type": 'object', - }, - { - "type": 'array', - "items": { - "anyOf": [ - { - "type": 'string', - }, - { - "type": 'object', - }, - ], - }, - }, + "required": [ + "credentialPayload" ], - "description": 'The data type for `@context` properties of credentials, presentations, etc.', - }, - "DateType": { - "type": 'string', - "description": - 'Represents an issuance or expiration date for Credentials / Presentations. This is used as input when creating them.', + "description": "ICreateSdJwtVcArgs" }, - "CredentialStatusReference": { - "type": 'object', - "properties": { - "id": { - "type": 'string', - }, - "type": { - "type": 'string', - }, - }, - "required": ['id', 'type'], - "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 }', - }, - "IcreateSDJwtVcResult": { - "type": 'object', + "ICreateSdJwtVcResult": { + "type": "object", "properties": { "credential": { - "type": 'string', - }, + "type": "string", + "description": "the encoded sd-jwt credential" + } }, - "required": ['credential'], - "description": 'IcreateSDJwtVcResult', + "required": [ + "credential" + ], + "description": "ICreateSdJwtVcResult" }, "ICreateSdJwtVcPresentationArgs": { - "type": 'object', + "type": "object", "properties": { "presentation": { - "type": 'string', + "type": "string", + "description": "Encoded SD-JWT credential" }, "presentationKeys": { - "type": 'array', + "type": "array", "items": { - "type": 'string', - }, + "type": "string" + } }, + "kb": { + "type": "object", + "properties": { + "payload": { + "type": "object", + "properties": { + "iat": { + "type": "number" + }, + "aud": { + "type": "string" + }, + "nonce": { + "type": "string" + } + }, + "required": [ + "iat", + "aud", + "nonce" + ] + } + }, + "required": [ + "payload" + ], + "description": "Information to include to add key binding." + } }, - "required": ['presentation'], + "required": [ + "presentation" + ] }, "ICreateSdJwtVcPresentationResult": { - "type": 'object', + "type": "object", "properties": { "presentation": { - "type": 'string', - }, + "type": "string", + "description": "Encoded presentation." + } }, - "required": ['presentation'], + "required": [ + "presentation" + ], + "description": "Created presentation" }, "IVerifySdJwtVcArgs": { - "type": 'object', + "type": "object", "properties": { "credential": { - "type": 'string', - }, + "type": "string" + } }, - "required": ['credential'], + "required": [ + "credential" + ] }, "IVerifySdJwtVcResult": { - "type": 'object', + "type": "object", + "properties": { + "verifiedPayloads": {} + }, + "required": [ + "verifiedPayloads" + ] }, "IVerifySdJwtVcPresentationArgs": { - "type": 'object', + "type": "object", "properties": { "presentation": { - "type": 'string', + "type": "string" }, "requiredClaimKeys": { - "type": 'array', + "type": "array", "items": { - "type": 'string', - }, + "type": "string" + } }, + "kb": { + "type": "boolean" + } }, - "required": ['presentation'], + "required": [ + "presentation" + ] }, "IVerifySdJwtVcPresentationResult": { - "type": 'object', + "type": "object", "properties": { - "verifiedPayloads": {}, - }, - "required": ['verifiedPayloads'], - }, + "verifiedPayloads": { + "type": "object", + "additionalProperties": {} + } + }, + "required": [ + "verifiedPayloads" + ] + } }, "methods": { - "createSDJwtVc": { - "description": 'Create a signed SD-JWT credential.', + "createSdJwtVc": { + "description": "Create a signed SD-JWT credential.", "arguments": { - "$ref": '#/components/schemas/IcreateSDJwtVcArgs', + "$ref": "#/components/schemas/ICreateSdJwtVcArgs" }, "returnType": { - "$ref": '#/components/schemas/IcreateSDJwtVcResult', - }, + "$ref": "#/components/schemas/ICreateSdJwtVcResult" + } }, "createSdJwtVcPresentation": { - "description": 'Create a signed SD-JWT presentation.', + "description": "Create a signed SD-JWT presentation.", "arguments": { - "$ref": '#/components/schemas/ICreateSdJwtVcPresentationArgs', + "$ref": "#/components/schemas/ICreateSdJwtVcPresentationArgs" }, "returnType": { - "$ref": '#/components/schemas/ICreateSdJwtVcPresentationResult', - }, + "$ref": "#/components/schemas/ICreateSdJwtVcPresentationResult" + } }, "verifySdJwtVc": { - "description": 'Verify a signed SD-JWT credential.', + "description": "Verify a signed SD-JWT credential.", "arguments": { - "$ref": '#/components/schemas/IVerifySdJwtVcArgs', + "$ref": "#/components/schemas/IVerifySdJwtVcArgs" }, "returnType": { - "$ref": '#/components/schemas/IVerifySdJwtVcResult', - }, + "$ref": "#/components/schemas/IVerifySdJwtVcResult" + } }, "verifySdJwtVcPresentation": { - "description": 'Verify a signed SD-JWT presentation.', + "description": "Verify a signed SD-JWT presentation.", "arguments": { - "$ref": '#/components/schemas/IVerifySdJwtVcPresentationArgs', + "$ref": "#/components/schemas/IVerifySdJwtVcPresentationArgs" }, "returnType": { - "$ref": '#/components/schemas/IVerifySdJwtVcPresentationResult', - }, - }, - }, - }, - }, -} + "$ref": "#/components/schemas/IVerifySdJwtVcPresentationResult" + } + } + } + } + } +} \ No newline at end of file From e92b0efef79ef388a7e4de9f03f1bfb629b6b8d6 Mon Sep 17 00:00:00 2001 From: Lukas Date: Wed, 6 Mar 2024 14:53:17 +0900 Subject: [PATCH 15/19] fix build Signed-off-by: Lukas --- packages/sd-jwt/{ => src}/__tests__/sd-jwt.test.ts | 2 +- packages/sd-jwt/tsconfig.json | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) rename packages/sd-jwt/{ => src}/__tests__/sd-jwt.test.ts (99%) diff --git a/packages/sd-jwt/__tests__/sd-jwt.test.ts b/packages/sd-jwt/src/__tests__/sd-jwt.test.ts similarity index 99% rename from packages/sd-jwt/__tests__/sd-jwt.test.ts rename to packages/sd-jwt/src/__tests__/sd-jwt.test.ts index 1e53332af..71a85458e 100644 --- a/packages/sd-jwt/__tests__/sd-jwt.test.ts +++ b/packages/sd-jwt/src/__tests__/sd-jwt.test.ts @@ -13,7 +13,7 @@ import { DIDDocument, Resolver, VerificationMethod } from 'did-resolver' import { SdJwtVcPayload } from '@sd-jwt/sd-jwt-vc' import { decodeSdJwt } from '@sd-jwt/decode' import { KBJwt } from '@sd-jwt/core' -import { ISDJwtPlugin, SDJwtPlugin } from '../src/index' +import { ISDJwtPlugin, SDJwtPlugin } from '../index' async function verifySignature(data: string, signature: string, key: JsonWebKey) { let { alg, crv } = key diff --git a/packages/sd-jwt/tsconfig.json b/packages/sd-jwt/tsconfig.json index eff722558..7dff4d76e 100644 --- a/packages/sd-jwt/tsconfig.json +++ b/packages/sd-jwt/tsconfig.json @@ -17,6 +17,5 @@ "path": "../utils" } ], - "include": ["./**/*.ts"], - "exclude": ["__tests__/*"] + "include": ["./**/*.ts"] } From 06b1561228ab383da7122f59b314bf6dec25f26b Mon Sep 17 00:00:00 2001 From: "Lukas.J.Han" Date: Thu, 28 Mar 2024 23:28:04 +0900 Subject: [PATCH 16/19] feat: upgrade sd-jwt package to 0.6.1 --- packages/sd-jwt/package.json | 17 ++--- packages/sd-jwt/src/__tests__/sd-jwt.test.ts | 10 +-- packages/sd-jwt/src/action-handler.ts | 46 +++++++----- packages/sd-jwt/src/plugin.schema.ts | 64 +++++++++++++--- packages/sd-jwt/src/types.ts | 22 +++++- pnpm-lock.yaml | 78 ++++++++++---------- 6 files changed, 154 insertions(+), 83 deletions(-) diff --git a/packages/sd-jwt/package.json b/packages/sd-jwt/package.json index 62adfc824..9a5a15eb7 100644 --- a/packages/sd-jwt/package.json +++ b/packages/sd-jwt/package.json @@ -18,12 +18,12 @@ }, "dependencies": { "@sphereon/ssi-sdk-ext.did-utils": "^0.16.0", - "@sd-jwt/core": "0.3.2-next.107", - "@sd-jwt/crypto-nodejs": "0.3.2-next.107", - "@sd-jwt/types": "0.3.2-next.107", - "@sd-jwt/utils": "0.3.2-next.107", - "@sd-jwt/decode": "0.3.2-next.107", - "@sd-jwt/sd-jwt-vc": "0.3.2-next.107", + "@sd-jwt/core": "0.6.1", + "@sd-jwt/crypto-nodejs": "0.6.1", + "@sd-jwt/types": "0.6.1", + "@sd-jwt/utils": "0.6.1", + "@sd-jwt/decode": "0.6.1", + "@sd-jwt/sd-jwt-vc": "0.6.1", "@veramo/core-types": "workspace:^", "@veramo/message-handler": "workspace:^", "@veramo/utils": "workspace:^", @@ -58,10 +58,9 @@ "url": "https://github.com/decentralized-identity/veramo.git", "directory": "packages/selective-disclosure" }, - "author": "Consensys Mesh R&D ", + "author": "Lukas.J.Han ", "contributors": [ - "Simonas Karuzas ", - "Mircea Nistor " + "Mirko Mollik " ], "keywords": [ "Veramo", diff --git a/packages/sd-jwt/src/__tests__/sd-jwt.test.ts b/packages/sd-jwt/src/__tests__/sd-jwt.test.ts index 71a85458e..0b00798e5 100644 --- a/packages/sd-jwt/src/__tests__/sd-jwt.test.ts +++ b/packages/sd-jwt/src/__tests__/sd-jwt.test.ts @@ -191,7 +191,7 @@ describe('Agent plugin', () => { }) const presentation = await agent.createSdJwtVcPresentation({ presentation: credential.credential, - presentationKeys: ['given_name'], + presentationFrame: { given_name: true }, kb: { payload: { aud: '1', @@ -224,7 +224,7 @@ describe('Agent plugin', () => { }) const presentation = await agent.createSdJwtVcPresentation({ presentation: credential.credential, - presentationKeys: ['given_name'], + presentationFrame: { given_name: true }, kb: { payload: { aud: '1', @@ -254,7 +254,7 @@ describe('Agent plugin', () => { }) const presentation = agent.createSdJwtVcPresentation({ presentation: credential.credential, - presentationKeys: ['given_name'], + presentationFrame: { given_name: true }, kb: { payload: { aud: '1', @@ -286,7 +286,7 @@ describe('Agent plugin', () => { }) const presentation = await agent.createSdJwtVcPresentation({ presentation: credential.credential, - presentationKeys: ['given_name'], + presentationFrame: { given_name: true }, kb: { payload: { aud: '1', @@ -325,7 +325,7 @@ describe('Agent plugin', () => { }) const presentation = await agent.createSdJwtVcPresentation({ presentation: credential.credential, - presentationKeys: ['given_name'], + presentationFrame: { given_name: true }, kb: { payload: { aud: '1', diff --git a/packages/sd-jwt/src/action-handler.ts b/packages/sd-jwt/src/action-handler.ts index f56f7004f..5fdfc50d1 100644 --- a/packages/sd-jwt/src/action-handler.ts +++ b/packages/sd-jwt/src/action-handler.ts @@ -1,6 +1,6 @@ import { Jwt, SDJwt } from '@sd-jwt/core' -import { SDJwtVcInstance } from '@sd-jwt/sd-jwt-vc' -import { Signer, Verifier, KbVerifier, JwtPayload } from '@sd-jwt/types' +import { SDJwtVcInstance, SdJwtVcPayload } from '@sd-jwt/sd-jwt-vc' +import { Signer, Verifier, KbVerifier, JwtPayload, DisclosureFrame, PresentationFrame } from '@sd-jwt/types' import { IAgentPlugin } from '@veramo/core-types' import { schema } from './plugin.schema' import { @@ -21,6 +21,7 @@ import { mapIdentifierKeysToDocWithJwkSupport } from '@sphereon/ssi-sdk-ext.did- import { encodeJoseBlob } from '@veramo/utils' /** + * @beta * SD-JWT plugin for Veramo */ export class SDJwtPlugin implements IAgentPlugin { @@ -63,14 +64,17 @@ export class SDJwtPlugin implements IAgentPlugin { hashAlg: 'SHA-256', }) - const credential = await sdjwt.issue(args.credentialPayload, args.disclosureFrame) + const credential = await sdjwt.issue( + args.credentialPayload, + args.disclosureFrame as DisclosureFrame, + ) return { credential } } /** * Get the key to sign the SD-JWT - * @param issuer did url like did:exmaple.com#key-1 - * @param context agent instance + * @param issuer - did url like did:exmaple.com#key-1 + * @param context - agent instance * @returns the key to sign the SD-JWT */ private async getSignKey(issuer: string, context: IRequiredContext) { @@ -133,14 +137,18 @@ export class SDJwtPlugin implements IAgentPlugin { kbSigner: signer, kbSignAlg: alg, }) - const credential = await sdjwt.present(args.presentation, args.presentationKeys, { kb: args.kb }) + const credential = await sdjwt.present( + args.presentation, + args.presentationFrame as PresentationFrame, + { kb: args.kb }, + ) return { presentation: credential } } /** * Verify a signed SD-JWT credential. - * @param args - * @param context + * @param args - Arguments necessary for the verify a SD-JWT credential. + * @param context - This reserved param is automatically added and handled by the framework, *do not override* * @returns */ async verifySdJwtVc(args: IVerifySdJwtVcArgs, context: IRequiredContext): Promise { @@ -157,11 +165,11 @@ export class SDJwtPlugin implements IAgentPlugin { /** * Verify the key binding of a SD-JWT by validating the signature of the key bound to the SD-JWT - * @param sdjwt - * @param context - * @param data - * @param signature - * @param payload + * @param sdjwt - SD-JWT instance + * @param context - This reserved param is automatically added and handled by the framework, *do not override* + * @param data - signed data + * @param signature - The signature + * @param payload - The payload of the SD-JWT * @returns */ private verifyKb( @@ -180,10 +188,10 @@ export class SDJwtPlugin implements IAgentPlugin { /** * Validates the signature of a SD-JWT - * @param sdjwt - * @param context - * @param data - * @param signature + * @param sdjwt - SD-JWT instance + * @param context - This reserved param is automatically added and handled by the framework, *do not override* + * @param data - signed data + * @param signature - The signature * @returns */ async verify(sdjwt: SDJwtVcInstance, context: IRequiredContext, data: string, signature: string) { @@ -207,8 +215,8 @@ export class SDJwtPlugin implements IAgentPlugin { /** * Verify a signed SD-JWT presentation. - * @param args - * @param context + * @param args - Arguments necessary for the verify a SD-JWT presentation. + * @param context - This reserved param is automatically added and handled by the framework, *do not override* * @returns */ async verifySdJwtVcPresentation( diff --git a/packages/sd-jwt/src/plugin.schema.ts b/packages/sd-jwt/src/plugin.schema.ts index f7fb76662..62ee508b9 100644 --- a/packages/sd-jwt/src/plugin.schema.ts +++ b/packages/sd-jwt/src/plugin.schema.ts @@ -11,9 +11,6 @@ export const schema = { "iss": { "type": "string" }, - "iat": { - "type": "number" - }, "nbf": { "type": "number" }, @@ -27,21 +24,58 @@ export const schema = { "status": {}, "sub": { "type": "string" + }, + "iat": { + "type": "number" } }, "required": [ "iss", - "iat", "vct" ] }, - "disclosureFrame": {} + "disclosureFrame": { + "$ref": "#/components/schemas/IDisclosureFrame" + } }, "required": [ "credentialPayload" ], "description": "ICreateSdJwtVcArgs" }, + "IDisclosureFrame": { + "type": "object", + "properties": { + "_sd": { + "type": "array", + "items": { + "type": "string" + } + }, + "_sd_decoy": { + "type": "number" + } + }, + "additionalProperties": { + "anyOf": [ + { + "type": "array", + "items": { + "type": "string" + } + }, + { + "type": "number" + }, + { + "$ref": "#/components/schemas/IDisclosureFrame" + }, + { + "not": {} + } + ] + } + }, "ICreateSdJwtVcResult": { "type": "object", "properties": { @@ -62,11 +96,8 @@ export const schema = { "type": "string", "description": "Encoded SD-JWT credential" }, - "presentationKeys": { - "type": "array", - "items": { - "type": "string" - } + "presentationFrame": { + "$ref": "#/components/schemas/IPresentationFrame" }, "kb": { "type": "object", @@ -101,6 +132,19 @@ export const schema = { "presentation" ] }, + "IPresentationFrame": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "boolean" + }, + { + "$ref": "#/components/schemas/IPresentationFrame" + } + ] + } + }, "ICreateSdJwtVcPresentationResult": { "type": "object", "properties": { diff --git a/packages/sd-jwt/src/types.ts b/packages/sd-jwt/src/types.ts index 36621df88..ad3dd588e 100644 --- a/packages/sd-jwt/src/types.ts +++ b/packages/sd-jwt/src/types.ts @@ -75,7 +75,16 @@ export interface ICreateSdJwtVcArgs { credentialPayload: SdJwtVcPayload // biome-ignore lint/suspicious/noExplicitAny: - disclosureFrame?: any + disclosureFrame?: IDisclosureFrame +} + +/** + * @beta + */ +export interface IDisclosureFrame { + _sd?: string[] + _sd_decoy?: number + [x: string]: string[] | number | IDisclosureFrame | undefined } /** @@ -103,9 +112,9 @@ export interface ICreateSdJwtVcPresentationArgs { /* * The keys to use for selective disclosure for presentation * if not provided, all keys will be disclosed - * if empty array, no keys will be disclosed + * if empty object, no keys will be disclosed */ - presentationKeys?: string[] + presentationFrame?: IPresentationFrame /** * Information to include to add key binding. @@ -113,6 +122,13 @@ export interface ICreateSdJwtVcPresentationArgs { kb?: KBOptions } +/** + * @beta + */ +export interface IPresentationFrame { + [x: string]: boolean | IPresentationFrame +} + /** * Created presentation * @beta diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bd3ddb4ce..d87c5da84 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1303,23 +1303,23 @@ importers: packages/sd-jwt: dependencies: '@sd-jwt/core': - specifier: 0.3.2-next.107 - version: 0.3.2-next.107 + specifier: 0.6.1 + version: 0.6.1 '@sd-jwt/crypto-nodejs': - specifier: 0.3.2-next.107 - version: 0.3.2-next.107 + specifier: 0.6.1 + version: 0.6.1 '@sd-jwt/decode': - specifier: 0.3.2-next.107 - version: 0.3.2-next.107 + specifier: 0.6.1 + version: 0.6.1 '@sd-jwt/sd-jwt-vc': - specifier: 0.3.2-next.107 - version: 0.3.2-next.107 + specifier: 0.6.1 + version: 0.6.1 '@sd-jwt/types': - specifier: 0.3.2-next.107 - version: 0.3.2-next.107 + specifier: 0.6.1 + version: 0.6.1 '@sd-jwt/utils': - specifier: 0.3.2-next.107 - version: 0.3.2-next.107 + specifier: 0.6.1 + version: 0.6.1 '@sphereon/ssi-sdk-ext.did-utils': specifier: ^0.16.0 version: 0.16.0(expo-crypto@12.8.1)(expo@49.0.21)(msrcrypto@1.5.8)(react-native-securerandom@1.0.1) @@ -9518,45 +9518,55 @@ packages: '@noble/hashes': 1.3.3 '@scure/base': 1.1.3 - /@sd-jwt/core@0.3.2-next.107: - resolution: {integrity: sha512-B77/4i/01R8lnXSfPDITZdN+1MOcviSsgsqlxICOQjSL8eWoKjtMwQvI+e3zHLqVgw2O0p7zbNBDhymqxFR3IA==} + /@sd-jwt/core@0.6.1: + resolution: {integrity: sha512-egFTb23o6BGWF93vnjopN02rSiC1HOOnkk9BI8Kao3jz9ipZAHdO6wF7gwfZm5Nlol/Kd1/KSLhbOUPYt++FjA==} engines: {node: '>=16'} dependencies: - '@sd-jwt/decode': 0.3.2-next.107 - '@sd-jwt/types': 0.3.2-next.107 - '@sd-jwt/utils': 0.3.2-next.107 + '@sd-jwt/decode': 0.6.1 + '@sd-jwt/present': 0.6.1 + '@sd-jwt/types': 0.6.1 + '@sd-jwt/utils': 0.6.1 dev: false - /@sd-jwt/crypto-nodejs@0.3.2-next.107: - resolution: {integrity: sha512-thHe0ZGJrja/PY4iAyDblV3axBfPSX9jNMSp4fwuy6nVgMspEZBDpvSMyY+yDVRZe2ol4CNj6uY/1M7imOIOsA==} + /@sd-jwt/crypto-nodejs@0.6.1: + resolution: {integrity: sha512-dkzZYNPlswCCnn4PfR/+GFeo/tI7QEZv4vqzpAp8/7v62Cpi/VjdyMmW5+SlHg3sTw82eL/B9aFTcFlnbQuvPA==} engines: {node: '>=16'} dev: false - /@sd-jwt/decode@0.3.2-next.107: - resolution: {integrity: sha512-GZBzslcyAYgMzs63BnkOY2+AJVmg2Vh5aAAR1y8TlHzaAe1UxNIiCwLOcJpQt+nkCmBDxO4P9rOLMMBHQ5WFEQ==} + /@sd-jwt/decode@0.6.1: + resolution: {integrity: sha512-QgTIoYd5zyKKLgXB4xEYJTrvumVwtsj5Dog0v0L9UH9ZvHekDaeexS247X7A4iSdzTvmZzUpGskgABOa4D8NmQ==} engines: {node: '>=16'} dependencies: - '@sd-jwt/types': 0.3.2-next.107 - '@sd-jwt/utils': 0.3.2-next.107 + '@sd-jwt/types': 0.6.1 + '@sd-jwt/utils': 0.6.1 dev: false - /@sd-jwt/sd-jwt-vc@0.3.2-next.107: - resolution: {integrity: sha512-uIxRpkjrVwSl+Qdc1IEny+3L4s+aeyoWR5Cjy1uvm7e8xkMJMWGbFdXfLGT8fGjFYgEJppAg8bY0kKqZSm0g4Q==} + /@sd-jwt/present@0.6.1: + resolution: {integrity: sha512-QRD3TUDLj4PqQNZ70bBxh8FLLrOE9mY8V9qiZrJSsaDOLFs2p1CtZG+v9ig62fxFYJZMf4bWKwYjz+qqGAtxCg==} engines: {node: '>=16'} dependencies: - '@sd-jwt/core': 0.3.2-next.107 + '@sd-jwt/decode': 0.6.1 + '@sd-jwt/types': 0.6.1 + '@sd-jwt/utils': 0.6.1 dev: false - /@sd-jwt/types@0.3.2-next.107: - resolution: {integrity: sha512-mft02chJEYvucDhD0FM/czILG5SA8DHYHuhl3yWZZx+KUTmtSe3IVfJ4BzZIWPtyr2B2FhEjX9Cz4XjxzDQZ3Q==} + /@sd-jwt/sd-jwt-vc@0.6.1: + resolution: {integrity: sha512-eF7NAFvedBCx+vrw4TVY3evUz5rAG8/FtB/CUudYEigKcpanLgfuNGhk93D45k+lLDG0b24w+qorqbpLZzHA2g==} + engines: {node: '>=16'} + dependencies: + '@sd-jwt/core': 0.6.1 + dev: false + + /@sd-jwt/types@0.6.1: + resolution: {integrity: sha512-LKpABZJGT77jNhOLvAHIkNNmGqXzyfwBT+6r+DN9zNzMx1CzuNR0qXk1GMUbast9iCfPkGbnEpUv/jHTBvlIvg==} engines: {node: '>=16'} dev: false - /@sd-jwt/utils@0.3.2-next.107: - resolution: {integrity: sha512-VdeZLUu2Lj3ZWCqyyETOBM6X1JJufpBzOUJnJK/u0oBuY88DO5u4Ha76u43R+UNgMYgoUad/W5rQl87Bt7w7Ng==} + /@sd-jwt/utils@0.6.1: + resolution: {integrity: sha512-1NHZ//+GecGQJb+gSdDicnrHG0DvACUk9jTnXA5yLZhlRjgkjyfJLNsCZesYeCyVp/SiyvIC9B+JwoY4kI0TwQ==} engines: {node: '>=16'} dependencies: - '@sd-jwt/types': 0.3.2-next.107 + '@sd-jwt/types': 0.6.1 js-base64: 3.7.7 dev: false @@ -25068,9 +25078,6 @@ packages: /sqlite3@5.1.6: resolution: {integrity: sha512-olYkWoKFVNSSSQNvxVUfjiVbz3YtBwTJj+mfV5zpHmqW3sELx2Cf4QCdirMelhM5Zh+KDVaKgQHqCxrqiWHybw==} requiresBuild: true - peerDependenciesMeta: - node-gyp: - optional: true dependencies: '@mapbox/node-pre-gyp': 1.0.10 node-addon-api: 4.3.0 @@ -25085,9 +25092,6 @@ packages: /sqlite3@5.1.7: resolution: {integrity: sha512-GGIyOiFaG+TUra3JIfkI/zGP8yZYLPQ0pl1bH+ODjiX57sPhrLU5sQJn1y9bDKZUFYkX1crlrPfSYt0BKKdkog==} requiresBuild: true - peerDependenciesMeta: - node-gyp: - optional: true dependencies: bindings: 1.5.0 node-addon-api: 7.1.0 From 470bef255e7a626addb3510c27dcd187b93a72a7 Mon Sep 17 00:00:00 2001 From: "Lukas.J.Han" Date: Mon, 6 May 2024 19:43:37 +0900 Subject: [PATCH 17/19] chore: remove unused dep --- packages/sd-jwt/src/__tests__/sd-jwt.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/sd-jwt/src/__tests__/sd-jwt.test.ts b/packages/sd-jwt/src/__tests__/sd-jwt.test.ts index 0b00798e5..6045756e3 100644 --- a/packages/sd-jwt/src/__tests__/sd-jwt.test.ts +++ b/packages/sd-jwt/src/__tests__/sd-jwt.test.ts @@ -7,7 +7,7 @@ import { DIDManager, MemoryDIDStore } from '@veramo/did-manager' import { JwkCreateIdentifierOptions, JwkDIDProvider, getDidJwkResolver } from '@veramo/did-provider-jwk' import { DIDResolverPlugin } from '@veramo/did-resolver' import { KeyManager, MemoryKeyStore, MemoryPrivateKeyStore } from '@veramo/key-manager' -import { KeyManagementSystem, SecretBox } from '@veramo/kms-local' +import { KeyManagementSystem } from '@veramo/kms-local' import { JwkDidSupportedKeyTypes, createJWK } from '@veramo/utils' import { DIDDocument, Resolver, VerificationMethod } from 'did-resolver' import { SdJwtVcPayload } from '@sd-jwt/sd-jwt-vc' From 4671aafc38bb6bc2129a56b07c0c5e52e2a05485 Mon Sep 17 00:00:00 2001 From: "Lukas.J.Han" Date: Mon, 6 May 2024 22:17:15 +0900 Subject: [PATCH 18/19] chore: reorder packages --- packages/sd-jwt/package.json | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/sd-jwt/package.json b/packages/sd-jwt/package.json index 9a5a15eb7..1a0a0f714 100644 --- a/packages/sd-jwt/package.json +++ b/packages/sd-jwt/package.json @@ -17,13 +17,13 @@ } }, "dependencies": { - "@sphereon/ssi-sdk-ext.did-utils": "^0.16.0", "@sd-jwt/core": "0.6.1", "@sd-jwt/crypto-nodejs": "0.6.1", - "@sd-jwt/types": "0.6.1", - "@sd-jwt/utils": "0.6.1", "@sd-jwt/decode": "0.6.1", "@sd-jwt/sd-jwt-vc": "0.6.1", + "@sd-jwt/types": "0.6.1", + "@sd-jwt/utils": "0.6.1", + "@sphereon/ssi-sdk-ext.did-utils": "^0.16.0", "@veramo/core-types": "workspace:^", "@veramo/message-handler": "workspace:^", "@veramo/utils": "workspace:^", @@ -32,17 +32,17 @@ "uuid": "^9.0.0" }, "devDependencies": { + "@types/debug": "4.1.8", + "@types/uuid": "9.0.2", "@veramo/core": "workspace:^", "@veramo/data-store": "workspace:^", "@veramo/did-manager": "workspace:^", "@veramo/did-provider-jwk": "workspace:^", + "@veramo/did-resolver": "workspace:^", "@veramo/key-manager": "workspace:^", "@veramo/kms-local": "workspace:^", - "@veramo/did-resolver": "workspace:^", - "@types/debug": "4.1.8", - "@types/uuid": "9.0.2", - "typescript": "5.3.3", - "typeorm": "^0.3.20" + "typeorm": "^0.3.20", + "typescript": "5.3.3" }, "files": [ "build/**/*", From c31cd82a0d4360c51ebc2099ec5d9e25a78e68d9 Mon Sep 17 00:00:00 2001 From: "Lukas.J.Han" Date: Mon, 6 May 2024 22:17:41 +0900 Subject: [PATCH 19/19] feat: remove did frag constraint --- packages/sd-jwt/src/__tests__/sd-jwt.test.ts | 15 --------------- packages/sd-jwt/src/action-handler.ts | 4 +--- 2 files changed, 1 insertion(+), 18 deletions(-) diff --git a/packages/sd-jwt/src/__tests__/sd-jwt.test.ts b/packages/sd-jwt/src/__tests__/sd-jwt.test.ts index 6045756e3..81221a8e1 100644 --- a/packages/sd-jwt/src/__tests__/sd-jwt.test.ts +++ b/packages/sd-jwt/src/__tests__/sd-jwt.test.ts @@ -147,21 +147,6 @@ describe('Agent plugin', () => { ).rejects.toThrow('credential.issuer must not be empty') }) - it('creat sd without the issuers key reference', async () => { - const credentialPayload: SdJwtVcPayload = { - ...claims, - iss: 'did:web:issuer', - iat: new Date().getTime() / 1000, - vct: '', - } - expect( - agent.createSdJwtVc({ - credentialPayload, - disclosureFrame, - }), - ).rejects.toThrow('credential.issuer must reference a key') - }) - it('verify a sd-jwt', async () => { const credentialPayload: SdJwtVcPayload = { ...claims, diff --git a/packages/sd-jwt/src/action-handler.ts b/packages/sd-jwt/src/action-handler.ts index 5fdfc50d1..0b9b33e7b 100644 --- a/packages/sd-jwt/src/action-handler.ts +++ b/packages/sd-jwt/src/action-handler.ts @@ -48,9 +48,7 @@ export class SDJwtPlugin implements IAgentPlugin { if (!issuer) { throw new Error('credential.issuer must not be empty') } - if (issuer.split('#').length === 1) { - throw new Error('credential.issuer must reference a key') - } + const { alg, key } = await this.getSignKey(issuer, context) //TODO: let the user also insert a method to sign the data