From 7fe49f8e5a01cf36f4fdd87bccd72f87554a9072 Mon Sep 17 00:00:00 2001 From: Ng Han Inn <43451336+nghaninn@users.noreply.github.com> Date: Wed, 9 Apr 2025 14:58:54 +0800 Subject: [PATCH 001/122] fix: update fetchCredentialStatusVC to use documentLoader (#46) Co-authored-by: nghaninn --- packages/w3c-context/src/index.ts | 3 +- packages/w3c-context/src/lib/index.ts | 85 +++++++++++++++++ packages/w3c-context/src/lib/types.ts | 9 ++ .../w3c-credential-status/src/lib/utils.ts | 14 +-- packages/w3c-vc/src/index.ts | 2 +- packages/w3c-vc/src/lib/types.ts | 17 ---- .../src/lib/verify/credentialStatus/index.ts | 12 ++- packages/w3c-vc/src/lib/w3c-vc.ts | 94 +------------------ 8 files changed, 114 insertions(+), 122 deletions(-) diff --git a/packages/w3c-context/src/index.ts b/packages/w3c-context/src/index.ts index f41a696f..e1bc2a74 100644 --- a/packages/w3c-context/src/index.ts +++ b/packages/w3c-context/src/index.ts @@ -1 +1,2 @@ -export * from './lib'; +export * from './lib/index'; +export * from './lib/types'; diff --git a/packages/w3c-context/src/lib/index.ts b/packages/w3c-context/src/lib/index.ts index f1e7907b..232e60d2 100644 --- a/packages/w3c-context/src/lib/index.ts +++ b/packages/w3c-context/src/lib/index.ts @@ -1,3 +1,8 @@ +import { Resolver } from 'did-resolver'; +import { DocumentLoader, DocumentLoaderObject } from './types'; +// @ts-ignore: No types available for jsonld-signatures +import jsonldSignatures from 'jsonld-signatures'; +import { getResolver as webGetResolver } from 'web-did-resolver'; import attachmentsContext from '../context/attachments-context.json'; import bbsV1 from '../context/bbs-v1.json'; import bolContext from '../context/bill-of-lading.json'; @@ -52,3 +57,83 @@ export const CredentialContextVersion = { v1: VC_V1_URL, v2: VC_V2_URL, }; + +/** + * Creates and returns a custom document loader for JSON-LD contexts. + * The loader resolves DID URLs and fetches the corresponding DID documents. + * + * @param {Record} additionalContexts - Optional additional contexts to be loaded. + * @returns {Promise} A function that loads JSON-LD contexts. + */ + +export async function getDocumentLoader( + additionalContexts?: Record, +): Promise { + const resultMap = new Map(); + + // Set default cached files within our lib. + [ + contexts, + trContexts, + renderContexts, + attachmentsContexts, + bolContexts, + invoiceContexts, + additionalContexts, + ].forEach((context) => { + if (!context) return; + Object.entries(context).forEach(([url, document]) => { + resultMap.set(url, { + contextUrl: null, + document: document, + documentUrl: url, + }); + }); + }); + + const resolveDid = async (did: string) => { + const resolver = new Resolver({ + ...webGetResolver(), + }); + const doc = await resolver.resolve(did); + + const result: DocumentLoaderObject = { + contextUrl: null, + document: doc.didDocument, + documentUrl: did, + }; + + resultMap.set(did, result); + + return result; + }; + + const customDocLoader = async (url: string) => { + let result; + + // Serve cached results + if (resultMap.has(url)) { + result = resultMap.get(url); + + return result; + } + + if (url.includes('did:')) { + return resolveDid(url); + } + + const results = await fetch(url, { redirect: 'follow' }); + + const resolveContext: DocumentLoaderObject = { + contextUrl: null, + document: await results.json(), + documentUrl: results.url, + }; + + resultMap.set(url, resolveContext); + + return resolveContext; + }; + + return jsonldSignatures.extendContextLoader(customDocLoader); +} diff --git a/packages/w3c-context/src/lib/types.ts b/packages/w3c-context/src/lib/types.ts index bd6d46f6..304bd7d0 100644 --- a/packages/w3c-context/src/lib/types.ts +++ b/packages/w3c-context/src/lib/types.ts @@ -6,3 +6,12 @@ export type ContextDocument = { // Define the type for the DID document export type Document = ContextDocument | DIDDocument; + +export type DocumentLoaderObject = { + contextUrl: string | null; + document: Document; + documentUrl: string; +}; +// Define a type for the context loader function + +export type DocumentLoader = (url: string) => Promise; diff --git a/packages/w3c-credential-status/src/lib/utils.ts b/packages/w3c-credential-status/src/lib/utils.ts index 7ee88242..d1a90ec3 100644 --- a/packages/w3c-credential-status/src/lib/utils.ts +++ b/packages/w3c-credential-status/src/lib/utils.ts @@ -1,3 +1,4 @@ +import { DocumentLoader, getDocumentLoader } from '@trustvc/w3c-context'; import { assertAllowedStatusPurpose, isNonNegativeInteger, @@ -132,19 +133,18 @@ export const assertTransferableRecords = ( * @param {string} url - The URL of the statusListCredential. * @returns {Promise} The verifiable credential of the credential status. */ -export const fetchCredentialStatusVC = async (url: string): Promise => { +export const fetchCredentialStatusVC = async ( + url: string, + documentLoader?: DocumentLoader, +): Promise => { // Check statusListCredential is valid e.g. URL if (!url || !URL.canParse(url)) { throw new Error(`Invalid statusListCredential: "${url}"`); } try { - const response = await fetch(url, { - redirect: 'follow', - headers: { Accept: 'application/*' }, - }); - const result: T = await response.json(); - + documentLoader = documentLoader ?? (await getDocumentLoader()); + const result = (await documentLoader(url))?.document as T; return result; } catch (err: unknown) { if (!(err instanceof Error)) { diff --git a/packages/w3c-vc/src/index.ts b/packages/w3c-vc/src/index.ts index 17b5d8d3..87bc1465 100644 --- a/packages/w3c-vc/src/index.ts +++ b/packages/w3c-vc/src/index.ts @@ -1,12 +1,12 @@ import { verifyCredentialStatus } from './lib/verify/credentialStatus'; import { deriveCredential, - getDocumentLoader, isRawDocument, isSignedDocument, signCredential, verifyCredential, } from './lib/w3c-vc'; +import { getDocumentLoader } from '@trustvc/w3c-context'; export * from './lib/types'; export { CredentialStatusResult } from './lib/verify/credentialStatus/types'; diff --git a/packages/w3c-vc/src/lib/types.ts b/packages/w3c-vc/src/lib/types.ts index b42365c4..00dc1969 100644 --- a/packages/w3c-vc/src/lib/types.ts +++ b/packages/w3c-vc/src/lib/types.ts @@ -1,5 +1,4 @@ import { BbsBlsSignature2020, BbsBlsSignatureProof2020 } from '@mattrglobal/jsonld-signatures-bbs'; -import { DIDDocument } from 'did-resolver'; // Define the type for the signing result export interface SigningResult { @@ -56,22 +55,6 @@ export type SignedVerifiableCredential = { export type RawVerifiableCredential = Omit; -export type ContextDocument = { - '@context': Record; -} & Record; - -// Define the type for the DID document -export type Document = ContextDocument | DIDDocument; - -export type DocumentLoaderObject = { - contextUrl: string | null; - document: Document; - documentUrl: string; -}; - -// Define a type for the context loader function -export type DocumentLoader = (url: string) => Promise; - export type ProofType = 'BbsBlsSignature2020' | 'BbsBlsSignatureProof2020'; export const proofTypeMapping: Record< diff --git a/packages/w3c-vc/src/lib/verify/credentialStatus/index.ts b/packages/w3c-vc/src/lib/verify/credentialStatus/index.ts index 7058683a..5d1bf256 100644 --- a/packages/w3c-vc/src/lib/verify/credentialStatus/index.ts +++ b/packages/w3c-vc/src/lib/verify/credentialStatus/index.ts @@ -11,6 +11,7 @@ import { _checkCredentialStatus } from '../../helper'; import { CredentialStatus, CredentialStatusResult } from './types'; import { verifyCredential } from '../../w3c-vc'; import { SignedVerifiableCredential } from '../../types'; +import { DocumentLoader } from '@trustvc/w3c-context'; /** * Verifies the credential status and returns the status of the given index. @@ -20,6 +21,9 @@ import { SignedVerifiableCredential } from '../../types'; export const verifyCredentialStatus = async ( credentialStatus: CredentialStatus, type: CredentialStatusType = 'StatusList2021Entry', + options?: { + documentLoader?: DocumentLoader; + }, ): Promise => { try { _checkCredentialStatus(credentialStatus, 'verify'); @@ -35,8 +39,10 @@ export const verifyCredentialStatus = async ( const index = Number.parseInt(statusListIndex); - const vcStatusList: SignedVerifiableCredential = - await fetchCredentialStatusVC(statusListCredential); + const vcStatusList: SignedVerifiableCredential = await fetchCredentialStatusVC( + statusListCredential, + options?.documentLoader, + ); const statusList = vcStatusList.credentialSubject as VCBitstringCredentialSubject; assertStatusPurposeMatches(statusList, statusPurpose); @@ -46,7 +52,7 @@ export const verifyCredentialStatus = async ( assertStatusListIndexWithinRange(bitstringStatusList, index); // Check if the statusListCredential is valid - const vcStatusListVerificationResult = await verifyCredential(vcStatusList); + const vcStatusListVerificationResult = await verifyCredential(vcStatusList, options); if (!vcStatusListVerificationResult?.verified) { console.error( `Failed to verify Credential Status VC: ${vcStatusListVerificationResult.verified}. Error: ${vcStatusListVerificationResult.error}`, diff --git a/packages/w3c-vc/src/lib/w3c-vc.ts b/packages/w3c-vc/src/lib/w3c-vc.ts index 56c1a560..7025350d 100644 --- a/packages/w3c-vc/src/lib/w3c-vc.ts +++ b/packages/w3c-vc/src/lib/w3c-vc.ts @@ -5,28 +5,15 @@ import { Bls12381G2KeyPair, deriveProof, } from '@mattrglobal/jsonld-signatures-bbs'; -import { - attachmentsContexts, - bolContexts, - contexts, - invoiceContexts, - renderContexts, - trContexts, -} from '@trustvc/w3c-context'; +import { ContextDocument, DocumentLoader, getDocumentLoader } from '@trustvc/w3c-context'; import { PrivateKeyPair } from '@trustvc/w3c-issuer'; -import { Resolver } from 'did-resolver'; // @ts-ignore: No types available for jsonld-signatures import jsonldSignatures from 'jsonld-signatures'; // @ts-ignore: No types available for jsonld import * as jsonld from 'jsonld'; -import { getResolver as webGetResolver } from 'web-did-resolver'; import { _checkCredential, _checkKeyPair, prefilCredentialId } from './helper'; import { - ContextDocument, DerivedResult, - Document, - DocumentLoader, - DocumentLoaderObject, ProofType, proofTypeMapping, RawVerifiableCredential, @@ -35,85 +22,6 @@ import { VerificationResult, } from './types'; -/** - * Creates and returns a custom document loader for JSON-LD contexts. - * The loader resolves DID URLs and fetches the corresponding DID documents. - * - * @param {Record} additionalContexts - Optional additional contexts to be loaded. - * @returns {Promise} A function that loads JSON-LD contexts. - */ -export async function getDocumentLoader( - additionalContexts?: Record, -): Promise { - const resultMap = new Map(); - - // Set default cached files within our lib. - [ - contexts, - trContexts, - renderContexts, - attachmentsContexts, - bolContexts, - invoiceContexts, - additionalContexts, - ].forEach((context) => { - if (!context) return; - Object.entries(context).forEach(([url, document]) => { - resultMap.set(url, { - contextUrl: null, - document: document, - documentUrl: url, - }); - }); - }); - - const resolveDid = async (did: string) => { - const resolver = new Resolver({ - ...webGetResolver(), - }); - const doc = await resolver.resolve(did); - - const result: DocumentLoaderObject = { - contextUrl: null, - document: doc.didDocument, - documentUrl: did, - }; - - resultMap.set(did, result); - - return result; - }; - - const customDocLoader = async (url: string) => { - let result; - - // Serve cached results - if (resultMap.has(url)) { - result = resultMap.get(url); - - return result; - } - - if (url.includes('did:')) { - return resolveDid(url); - } - - const results = await fetch(url, { redirect: 'follow' }); - - const resolveContext: DocumentLoaderObject = { - contextUrl: null, - document: await results.json(), - documentUrl: results.url, - }; - - resultMap.set(url, resolveContext); - - return resolveContext; - }; - - return jsonldSignatures.extendContextLoader(customDocLoader); -} - /** * Checks if the input document is a raw credential. * @param {RawVerifiableCredential | unknown} document - The raw credential to be checked. From 9244c35ce33b376a153b065f9a6c28e9a785c8cd Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 9 Apr 2025 07:01:19 +0000 Subject: [PATCH 002/122] chore(release): @trustvc/w3c-context@1.2.3-alpha.1 [skip ci] ## [1.2.3-alpha.1](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-context@1.2.2...@trustvc/w3c-context@1.2.3-alpha.1) (2025-04-09) ### Bug Fixes * update fetchCredentialStatusVC to use documentLoader ([#46](https://github.com/TrustVC/w3c/issues/46)) ([7fe49f8](https://github.com/TrustVC/w3c/commit/7fe49f8e5a01cf36f4fdd87bccd72f87554a9072)) --- packages/w3c-context/CHANGELOG.md | 7 +++++++ packages/w3c-context/package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/w3c-context/CHANGELOG.md b/packages/w3c-context/CHANGELOG.md index 2fd800c4..146358bf 100644 --- a/packages/w3c-context/CHANGELOG.md +++ b/packages/w3c-context/CHANGELOG.md @@ -1,3 +1,10 @@ +## [1.2.3-alpha.1](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-context@1.2.2...@trustvc/w3c-context@1.2.3-alpha.1) (2025-04-09) + + +### Bug Fixes + +* update fetchCredentialStatusVC to use documentLoader ([#46](https://github.com/TrustVC/w3c/issues/46)) ([7fe49f8](https://github.com/TrustVC/w3c/commit/7fe49f8e5a01cf36f4fdd87bccd72f87554a9072)) + ## [1.2.2](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-context@1.2.1...@trustvc/w3c-context@1.2.2) (2025-04-07) diff --git a/packages/w3c-context/package.json b/packages/w3c-context/package.json index 2737633f..76319884 100644 --- a/packages/w3c-context/package.json +++ b/packages/w3c-context/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c-context", - "version": "1.2.2", + "version": "1.2.3-alpha.1", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", From 5afee3318b948bba46a99f77674abc641fa8b5d5 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 9 Apr 2025 07:02:21 +0000 Subject: [PATCH 003/122] chore(release): @trustvc/w3c-credential-status@1.2.3-alpha.1 [skip ci] ## [1.2.3-alpha.1](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-credential-status@1.2.2...@trustvc/w3c-credential-status@1.2.3-alpha.1) (2025-04-09) ### Bug Fixes * update fetchCredentialStatusVC to use documentLoader ([#46](https://github.com/TrustVC/w3c/issues/46)) ([7fe49f8](https://github.com/TrustVC/w3c/commit/7fe49f8e5a01cf36f4fdd87bccd72f87554a9072)) --- packages/w3c-credential-status/CHANGELOG.md | 7 +++++++ packages/w3c-credential-status/package.json | 4 ++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/packages/w3c-credential-status/CHANGELOG.md b/packages/w3c-credential-status/CHANGELOG.md index aa2f7846..12059066 100644 --- a/packages/w3c-credential-status/CHANGELOG.md +++ b/packages/w3c-credential-status/CHANGELOG.md @@ -1,3 +1,10 @@ +## [1.2.3-alpha.1](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-credential-status@1.2.2...@trustvc/w3c-credential-status@1.2.3-alpha.1) (2025-04-09) + + +### Bug Fixes + +* update fetchCredentialStatusVC to use documentLoader ([#46](https://github.com/TrustVC/w3c/issues/46)) ([7fe49f8](https://github.com/TrustVC/w3c/commit/7fe49f8e5a01cf36f4fdd87bccd72f87554a9072)) + ## [1.2.2](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-credential-status@1.2.1...@trustvc/w3c-credential-status@1.2.2) (2025-04-07) diff --git a/packages/w3c-credential-status/package.json b/packages/w3c-credential-status/package.json index 281f5104..2339bd97 100644 --- a/packages/w3c-credential-status/package.json +++ b/packages/w3c-credential-status/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c-credential-status", - "version": "1.2.2", + "version": "1.2.3-alpha.1", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", @@ -29,7 +29,7 @@ } }, "dependencies": { - "@trustvc/w3c-context": "^1.2.2", + "@trustvc/w3c-context": "^1.2.3-alpha.1", "@trustvc/w3c-issuer": "^1.2.1", "base64url-universal": "^2.0.0", "pako": "^2.1.0" From 2a8006863d7b85db7e2fd97355107923680ddcaa Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 9 Apr 2025 07:03:00 +0000 Subject: [PATCH 004/122] chore(release): @trustvc/w3c-vc@1.2.7-alpha.1 [skip ci] ## [1.2.7-alpha.1](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.2.6...@trustvc/w3c-vc@1.2.7-alpha.1) (2025-04-09) ### Bug Fixes * update fetchCredentialStatusVC to use documentLoader ([#46](https://github.com/TrustVC/w3c/issues/46)) ([7fe49f8](https://github.com/TrustVC/w3c/commit/7fe49f8e5a01cf36f4fdd87bccd72f87554a9072)) --- packages/w3c-vc/CHANGELOG.md | 7 +++++++ packages/w3c-vc/package.json | 4 ++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/packages/w3c-vc/CHANGELOG.md b/packages/w3c-vc/CHANGELOG.md index e27750e4..334f7204 100644 --- a/packages/w3c-vc/CHANGELOG.md +++ b/packages/w3c-vc/CHANGELOG.md @@ -1,3 +1,10 @@ +## [1.2.7-alpha.1](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.2.6...@trustvc/w3c-vc@1.2.7-alpha.1) (2025-04-09) + + +### Bug Fixes + +* update fetchCredentialStatusVC to use documentLoader ([#46](https://github.com/TrustVC/w3c/issues/46)) ([7fe49f8](https://github.com/TrustVC/w3c/commit/7fe49f8e5a01cf36f4fdd87bccd72f87554a9072)) + ## [1.2.6](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.2.5...@trustvc/w3c-vc@1.2.6) (2025-04-08) diff --git a/packages/w3c-vc/package.json b/packages/w3c-vc/package.json index 22098c35..493e0d89 100644 --- a/packages/w3c-vc/package.json +++ b/packages/w3c-vc/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c-vc", - "version": "1.2.6", + "version": "1.2.7-alpha.1", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", @@ -32,7 +32,7 @@ }, "dependencies": { "@mattrglobal/jsonld-signatures-bbs": "^1.2.0", - "@trustvc/w3c-credential-status": "^1.2.2", + "@trustvc/w3c-credential-status": "^1.2.3-alpha.1", "@trustvc/w3c-issuer": "^1.2.1", "did-resolver": "^4.1.0", "jsonld": "^6.0.0", From d31b356ece8a4ecdc36512d0e771f7f45ca087b9 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 9 Apr 2025 07:03:37 +0000 Subject: [PATCH 005/122] chore(release): @trustvc/w3c-cli@1.2.7-alpha.1 [skip ci] ## [1.2.7-alpha.1](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-cli@1.2.6...@trustvc/w3c-cli@1.2.7-alpha.1) (2025-04-09) ### Bug Fixes * update fetchCredentialStatusVC to use documentLoader ([#46](https://github.com/TrustVC/w3c/issues/46)) ([7fe49f8](https://github.com/TrustVC/w3c/commit/7fe49f8e5a01cf36f4fdd87bccd72f87554a9072)) --- apps/w3c-cli/CHANGELOG.md | 7 +++++++ apps/w3c-cli/package.json | 8 ++++---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/apps/w3c-cli/CHANGELOG.md b/apps/w3c-cli/CHANGELOG.md index a94b3c4e..5c26ff14 100644 --- a/apps/w3c-cli/CHANGELOG.md +++ b/apps/w3c-cli/CHANGELOG.md @@ -1,3 +1,10 @@ +## [1.2.7-alpha.1](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-cli@1.2.6...@trustvc/w3c-cli@1.2.7-alpha.1) (2025-04-09) + + +### Bug Fixes + +* update fetchCredentialStatusVC to use documentLoader ([#46](https://github.com/TrustVC/w3c/issues/46)) ([7fe49f8](https://github.com/TrustVC/w3c/commit/7fe49f8e5a01cf36f4fdd87bccd72f87554a9072)) + ## [1.2.6](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-cli@1.2.5...@trustvc/w3c-cli@1.2.6) (2025-04-08) diff --git a/apps/w3c-cli/package.json b/apps/w3c-cli/package.json index 6a836ef8..599a047f 100644 --- a/apps/w3c-cli/package.json +++ b/apps/w3c-cli/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c-cli", - "version": "1.2.6", + "version": "1.2.7-alpha.1", "description": "CLI for TrustVC W3C", "main": "dist/main.js", "types": "dist/main.d.ts", @@ -34,9 +34,9 @@ }, "dependencies": { "@inquirer/prompts": "^5.3.8", - "@trustvc/w3c-context": "^1.2.2", - "@trustvc/w3c-credential-status": "^1.2.2", - "@trustvc/w3c-vc": "^1.2.6", + "@trustvc/w3c-context": "^1.2.3-alpha.1", + "@trustvc/w3c-credential-status": "^1.2.3-alpha.1", + "@trustvc/w3c-vc": "^1.2.7-alpha.1", "@trustvc/w3c-issuer": "^1.2.1", "@types/yargs": "^17.0.32", "chalk": "^4.1.2", From 57f94c95a31d33aea4df3c1dc0d8869bf6c872bf Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 9 Apr 2025 07:04:13 +0000 Subject: [PATCH 006/122] chore(release): @trustvc/w3c@1.2.7-alpha.1 [skip ci] ## [1.2.7-alpha.1](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.2.6...@trustvc/w3c@1.2.7-alpha.1) (2025-04-09) ### Bug Fixes * update fetchCredentialStatusVC to use documentLoader ([#46](https://github.com/TrustVC/w3c/issues/46)) ([7fe49f8](https://github.com/TrustVC/w3c/commit/7fe49f8e5a01cf36f4fdd87bccd72f87554a9072)) --- packages/w3c/CHANGELOG.md | 7 +++++++ packages/w3c/package.json | 8 ++++---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/packages/w3c/CHANGELOG.md b/packages/w3c/CHANGELOG.md index 8d897f73..29e7caf2 100644 --- a/packages/w3c/CHANGELOG.md +++ b/packages/w3c/CHANGELOG.md @@ -1,3 +1,10 @@ +## [1.2.7-alpha.1](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.2.6...@trustvc/w3c@1.2.7-alpha.1) (2025-04-09) + + +### Bug Fixes + +* update fetchCredentialStatusVC to use documentLoader ([#46](https://github.com/TrustVC/w3c/issues/46)) ([7fe49f8](https://github.com/TrustVC/w3c/commit/7fe49f8e5a01cf36f4fdd87bccd72f87554a9072)) + ## [1.2.6](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.2.5...@trustvc/w3c@1.2.6) (2025-04-08) diff --git a/packages/w3c/package.json b/packages/w3c/package.json index 64a7ed5c..3bbbe18d 100644 --- a/packages/w3c/package.json +++ b/packages/w3c/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c", - "version": "1.2.6", + "version": "1.2.7-alpha.1", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", @@ -32,10 +32,10 @@ } }, "dependencies": { - "@trustvc/w3c-context": "^1.2.2", - "@trustvc/w3c-credential-status": "^1.2.2", + "@trustvc/w3c-context": "^1.2.3-alpha.1", + "@trustvc/w3c-credential-status": "^1.2.3-alpha.1", "@trustvc/w3c-issuer": "^1.2.1", - "@trustvc/w3c-vc": "^1.2.6" + "@trustvc/w3c-vc": "^1.2.7-alpha.1" }, "repository": { "type": "git", From dae74e779e8f26dcd84f63e9baea905d2eca91fc Mon Sep 17 00:00:00 2001 From: Ng Han Inn <43451336+nghaninn@users.noreply.github.com> Date: Wed, 9 Apr 2025 15:23:47 +0800 Subject: [PATCH 007/122] fix: add export (#47) * fix: update fetchCredentialStatusVC to use documentLoader * fix: add export --------- Co-authored-by: nghaninn --- packages/w3c-vc/src/index.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/w3c-vc/src/index.ts b/packages/w3c-vc/src/index.ts index 87bc1465..ff29334d 100644 --- a/packages/w3c-vc/src/index.ts +++ b/packages/w3c-vc/src/index.ts @@ -9,6 +9,12 @@ import { import { getDocumentLoader } from '@trustvc/w3c-context'; export * from './lib/types'; +export { + ContextDocument, + DocumentLoader, + Document, + DocumentLoaderObject, +} from '@trustvc/w3c-context'; export { CredentialStatusResult } from './lib/verify/credentialStatus/types'; export { deriveCredential, From 7413fa81263aa9b9a14c0a2022f94aefe23f6f97 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 9 Apr 2025 07:26:48 +0000 Subject: [PATCH 008/122] chore(release): @trustvc/w3c-vc@1.2.7-alpha.2 [skip ci] ## [1.2.7-alpha.2](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.2.7-alpha.1...@trustvc/w3c-vc@1.2.7-alpha.2) (2025-04-09) ### Bug Fixes * add export ([#47](https://github.com/TrustVC/w3c/issues/47)) ([dae74e7](https://github.com/TrustVC/w3c/commit/dae74e779e8f26dcd84f63e9baea905d2eca91fc)) --- packages/w3c-vc/CHANGELOG.md | 7 +++++++ packages/w3c-vc/package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/w3c-vc/CHANGELOG.md b/packages/w3c-vc/CHANGELOG.md index 334f7204..eef9a5a0 100644 --- a/packages/w3c-vc/CHANGELOG.md +++ b/packages/w3c-vc/CHANGELOG.md @@ -1,3 +1,10 @@ +## [1.2.7-alpha.2](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.2.7-alpha.1...@trustvc/w3c-vc@1.2.7-alpha.2) (2025-04-09) + + +### Bug Fixes + +* add export ([#47](https://github.com/TrustVC/w3c/issues/47)) ([dae74e7](https://github.com/TrustVC/w3c/commit/dae74e779e8f26dcd84f63e9baea905d2eca91fc)) + ## [1.2.7-alpha.1](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.2.6...@trustvc/w3c-vc@1.2.7-alpha.1) (2025-04-09) diff --git a/packages/w3c-vc/package.json b/packages/w3c-vc/package.json index 493e0d89..9dfe5924 100644 --- a/packages/w3c-vc/package.json +++ b/packages/w3c-vc/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c-vc", - "version": "1.2.7-alpha.1", + "version": "1.2.7-alpha.2", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", From 356395019727193ed673898de2145cde2aea9568 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 9 Apr 2025 07:27:16 +0000 Subject: [PATCH 009/122] chore(release): @trustvc/w3c-cli@1.2.7-alpha.2 [skip ci] ## [1.2.7-alpha.2](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-cli@1.2.7-alpha.1...@trustvc/w3c-cli@1.2.7-alpha.2) (2025-04-09) ### Bug Fixes * add export ([#47](https://github.com/TrustVC/w3c/issues/47)) ([dae74e7](https://github.com/TrustVC/w3c/commit/dae74e779e8f26dcd84f63e9baea905d2eca91fc)) --- apps/w3c-cli/CHANGELOG.md | 7 +++++++ apps/w3c-cli/package.json | 4 ++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/apps/w3c-cli/CHANGELOG.md b/apps/w3c-cli/CHANGELOG.md index 5c26ff14..216cec9b 100644 --- a/apps/w3c-cli/CHANGELOG.md +++ b/apps/w3c-cli/CHANGELOG.md @@ -1,3 +1,10 @@ +## [1.2.7-alpha.2](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-cli@1.2.7-alpha.1...@trustvc/w3c-cli@1.2.7-alpha.2) (2025-04-09) + + +### Bug Fixes + +* add export ([#47](https://github.com/TrustVC/w3c/issues/47)) ([dae74e7](https://github.com/TrustVC/w3c/commit/dae74e779e8f26dcd84f63e9baea905d2eca91fc)) + ## [1.2.7-alpha.1](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-cli@1.2.6...@trustvc/w3c-cli@1.2.7-alpha.1) (2025-04-09) diff --git a/apps/w3c-cli/package.json b/apps/w3c-cli/package.json index 599a047f..f05c81c2 100644 --- a/apps/w3c-cli/package.json +++ b/apps/w3c-cli/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c-cli", - "version": "1.2.7-alpha.1", + "version": "1.2.7-alpha.2", "description": "CLI for TrustVC W3C", "main": "dist/main.js", "types": "dist/main.d.ts", @@ -36,7 +36,7 @@ "@inquirer/prompts": "^5.3.8", "@trustvc/w3c-context": "^1.2.3-alpha.1", "@trustvc/w3c-credential-status": "^1.2.3-alpha.1", - "@trustvc/w3c-vc": "^1.2.7-alpha.1", + "@trustvc/w3c-vc": "^1.2.7-alpha.2", "@trustvc/w3c-issuer": "^1.2.1", "@types/yargs": "^17.0.32", "chalk": "^4.1.2", From c3b8f9c21fe72f0950621282a705e768c44c0d3d Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 9 Apr 2025 07:27:44 +0000 Subject: [PATCH 010/122] chore(release): @trustvc/w3c@1.2.7-alpha.2 [skip ci] ## [1.2.7-alpha.2](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.2.7-alpha.1...@trustvc/w3c@1.2.7-alpha.2) (2025-04-09) ### Bug Fixes * add export ([#47](https://github.com/TrustVC/w3c/issues/47)) ([dae74e7](https://github.com/TrustVC/w3c/commit/dae74e779e8f26dcd84f63e9baea905d2eca91fc)) --- packages/w3c/CHANGELOG.md | 7 +++++++ packages/w3c/package.json | 4 ++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/packages/w3c/CHANGELOG.md b/packages/w3c/CHANGELOG.md index 29e7caf2..605eb647 100644 --- a/packages/w3c/CHANGELOG.md +++ b/packages/w3c/CHANGELOG.md @@ -1,3 +1,10 @@ +## [1.2.7-alpha.2](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.2.7-alpha.1...@trustvc/w3c@1.2.7-alpha.2) (2025-04-09) + + +### Bug Fixes + +* add export ([#47](https://github.com/TrustVC/w3c/issues/47)) ([dae74e7](https://github.com/TrustVC/w3c/commit/dae74e779e8f26dcd84f63e9baea905d2eca91fc)) + ## [1.2.7-alpha.1](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.2.6...@trustvc/w3c@1.2.7-alpha.1) (2025-04-09) diff --git a/packages/w3c/package.json b/packages/w3c/package.json index 3bbbe18d..6a64871f 100644 --- a/packages/w3c/package.json +++ b/packages/w3c/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c", - "version": "1.2.7-alpha.1", + "version": "1.2.7-alpha.2", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", @@ -35,7 +35,7 @@ "@trustvc/w3c-context": "^1.2.3-alpha.1", "@trustvc/w3c-credential-status": "^1.2.3-alpha.1", "@trustvc/w3c-issuer": "^1.2.1", - "@trustvc/w3c-vc": "^1.2.7-alpha.1" + "@trustvc/w3c-vc": "^1.2.7-alpha.2" }, "repository": { "type": "git", From 4a9f52a823e5836454c65239916fa5807c9d0be1 Mon Sep 17 00:00:00 2001 From: Ng Han Inn <43451336+nghaninn@users.noreply.github.com> Date: Wed, 9 Apr 2025 15:48:45 +0800 Subject: [PATCH 011/122] fix: add cache for jws 2020 v1 (#48) * fix: update fetchCredentialStatusVC to use documentLoader * fix: add export * fix: add cache for jws 2020 v1 --------- Co-authored-by: nghaninn --- .../w3c-context/src/context/jws-2020-v1.json | 78 +++++++++++++++++++ packages/w3c-context/src/lib/index.ts | 3 + 2 files changed, 81 insertions(+) create mode 100644 packages/w3c-context/src/context/jws-2020-v1.json diff --git a/packages/w3c-context/src/context/jws-2020-v1.json b/packages/w3c-context/src/context/jws-2020-v1.json new file mode 100644 index 00000000..30f74b11 --- /dev/null +++ b/packages/w3c-context/src/context/jws-2020-v1.json @@ -0,0 +1,78 @@ +{ + "@context": { + "privateKeyJwk": { + "@id": "https://w3id.org/security#privateKeyJwk", + "@type": "@json" + }, + "JsonWebKey2020": { + "@id": "https://w3id.org/security#JsonWebKey2020", + "@context": { + "@protected": true, + "id": "@id", + "type": "@type", + "publicKeyJwk": { + "@id": "https://w3id.org/security#publicKeyJwk", + "@type": "@json" + } + } + }, + "JsonWebSignature2020": { + "@id": "https://w3id.org/security#JsonWebSignature2020", + "@context": { + "@protected": true, + "id": "@id", + "type": "@type", + "challenge": "https://w3id.org/security#challenge", + "created": { + "@id": "http://purl.org/dc/terms/created", + "@type": "http://www.w3.org/2001/XMLSchema#dateTime" + }, + "domain": "https://w3id.org/security#domain", + "expires": { + "@id": "https://w3id.org/security#expiration", + "@type": "http://www.w3.org/2001/XMLSchema#dateTime" + }, + "jws": "https://w3id.org/security#jws", + "nonce": "https://w3id.org/security#nonce", + "proofPurpose": { + "@id": "https://w3id.org/security#proofPurpose", + "@type": "@vocab", + "@context": { + "@protected": true, + "id": "@id", + "type": "@type", + "assertionMethod": { + "@id": "https://w3id.org/security#assertionMethod", + "@type": "@id", + "@container": "@set" + }, + "authentication": { + "@id": "https://w3id.org/security#authenticationMethod", + "@type": "@id", + "@container": "@set" + }, + "capabilityInvocation": { + "@id": "https://w3id.org/security#capabilityInvocationMethod", + "@type": "@id", + "@container": "@set" + }, + "capabilityDelegation": { + "@id": "https://w3id.org/security#capabilityDelegationMethod", + "@type": "@id", + "@container": "@set" + }, + "keyAgreement": { + "@id": "https://w3id.org/security#keyAgreementMethod", + "@type": "@id", + "@container": "@set" + } + } + }, + "verificationMethod": { + "@id": "https://w3id.org/security#verificationMethod", + "@type": "@id" + } + } + } + } +} \ No newline at end of file diff --git a/packages/w3c-context/src/lib/index.ts b/packages/w3c-context/src/lib/index.ts index 232e60d2..8529e043 100644 --- a/packages/w3c-context/src/lib/index.ts +++ b/packages/w3c-context/src/lib/index.ts @@ -10,6 +10,7 @@ import credentialsV1 from '../context/credentials-v1.json'; import credentialsV2 from '../context/credentials-v2.json'; import didV1 from '../context/did-v1.json'; import invoiceContext from '../context/invoice.json'; +import jwsV1 from '../context/jws-2020-v1.json'; import renderContext from '../context/render-method-context.json'; import trContext from '../context/transferable-records-context.json'; import { Document } from './types'; @@ -24,6 +25,7 @@ export const BOL_CONTEXT_URL = 'https://trustvc.io/context/bill-of-lading.json'; export const INVOICE_CONTEXT_URL = 'https://trustvc.io/context/invoice.json'; export const BBS_V1_URL = 'https://w3id.org/security/bbs/v1'; +export const JWS_V1_URL = 'https://w3id.org/security/suites/jws-2020/v1'; export const STATUS_LIST_2021_CREDENTIAL_URL = 'https://w3id.org/vc/status-list/2021/v1'; export const contexts: { [key: string]: Document } = { @@ -31,6 +33,7 @@ export const contexts: { [key: string]: Document } = { [VC_V1_URL]: credentialsV1, [VC_V2_URL]: credentialsV2, [BBS_V1_URL]: bbsV1, + [JWS_V1_URL]: jwsV1, }; export const trContexts: { [key: string]: Document } = { From e36ceccb0610e192e561021dfeb287c796c2650e Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 9 Apr 2025 07:51:03 +0000 Subject: [PATCH 012/122] chore(release): @trustvc/w3c-context@1.2.3-alpha.2 [skip ci] ## [1.2.3-alpha.2](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-context@1.2.3-alpha.1...@trustvc/w3c-context@1.2.3-alpha.2) (2025-04-09) ### Bug Fixes * add cache for jws 2020 v1 ([#48](https://github.com/TrustVC/w3c/issues/48)) ([4a9f52a](https://github.com/TrustVC/w3c/commit/4a9f52a823e5836454c65239916fa5807c9d0be1)) --- packages/w3c-context/CHANGELOG.md | 7 +++++++ packages/w3c-context/package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/w3c-context/CHANGELOG.md b/packages/w3c-context/CHANGELOG.md index 146358bf..b020b39d 100644 --- a/packages/w3c-context/CHANGELOG.md +++ b/packages/w3c-context/CHANGELOG.md @@ -1,3 +1,10 @@ +## [1.2.3-alpha.2](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-context@1.2.3-alpha.1...@trustvc/w3c-context@1.2.3-alpha.2) (2025-04-09) + + +### Bug Fixes + +* add cache for jws 2020 v1 ([#48](https://github.com/TrustVC/w3c/issues/48)) ([4a9f52a](https://github.com/TrustVC/w3c/commit/4a9f52a823e5836454c65239916fa5807c9d0be1)) + ## [1.2.3-alpha.1](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-context@1.2.2...@trustvc/w3c-context@1.2.3-alpha.1) (2025-04-09) diff --git a/packages/w3c-context/package.json b/packages/w3c-context/package.json index 76319884..ba0d44ae 100644 --- a/packages/w3c-context/package.json +++ b/packages/w3c-context/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c-context", - "version": "1.2.3-alpha.1", + "version": "1.2.3-alpha.2", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", From b2faa800afb53fc67fbe810461283aab140ddc1c Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 9 Apr 2025 07:51:58 +0000 Subject: [PATCH 013/122] chore(release): @trustvc/w3c-credential-status@1.2.3-alpha.2 [skip ci] ## [1.2.3-alpha.2](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-credential-status@1.2.3-alpha.1...@trustvc/w3c-credential-status@1.2.3-alpha.2) (2025-04-09) ### Bug Fixes * add cache for jws 2020 v1 ([#48](https://github.com/TrustVC/w3c/issues/48)) ([4a9f52a](https://github.com/TrustVC/w3c/commit/4a9f52a823e5836454c65239916fa5807c9d0be1)) --- packages/w3c-credential-status/CHANGELOG.md | 7 +++++++ packages/w3c-credential-status/package.json | 4 ++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/packages/w3c-credential-status/CHANGELOG.md b/packages/w3c-credential-status/CHANGELOG.md index 12059066..1e262cc1 100644 --- a/packages/w3c-credential-status/CHANGELOG.md +++ b/packages/w3c-credential-status/CHANGELOG.md @@ -1,3 +1,10 @@ +## [1.2.3-alpha.2](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-credential-status@1.2.3-alpha.1...@trustvc/w3c-credential-status@1.2.3-alpha.2) (2025-04-09) + + +### Bug Fixes + +* add cache for jws 2020 v1 ([#48](https://github.com/TrustVC/w3c/issues/48)) ([4a9f52a](https://github.com/TrustVC/w3c/commit/4a9f52a823e5836454c65239916fa5807c9d0be1)) + ## [1.2.3-alpha.1](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-credential-status@1.2.2...@trustvc/w3c-credential-status@1.2.3-alpha.1) (2025-04-09) diff --git a/packages/w3c-credential-status/package.json b/packages/w3c-credential-status/package.json index 2339bd97..68b194ef 100644 --- a/packages/w3c-credential-status/package.json +++ b/packages/w3c-credential-status/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c-credential-status", - "version": "1.2.3-alpha.1", + "version": "1.2.3-alpha.2", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", @@ -29,7 +29,7 @@ } }, "dependencies": { - "@trustvc/w3c-context": "^1.2.3-alpha.1", + "@trustvc/w3c-context": "^1.2.3-alpha.2", "@trustvc/w3c-issuer": "^1.2.1", "base64url-universal": "^2.0.0", "pako": "^2.1.0" From aea5752eeb9eb96bc828fe47c6a0d304e9a68f99 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 9 Apr 2025 07:52:30 +0000 Subject: [PATCH 014/122] chore(release): @trustvc/w3c-vc@1.2.7-alpha.3 [skip ci] ## [1.2.7-alpha.3](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.2.7-alpha.2...@trustvc/w3c-vc@1.2.7-alpha.3) (2025-04-09) ### Bug Fixes * add cache for jws 2020 v1 ([#48](https://github.com/TrustVC/w3c/issues/48)) ([4a9f52a](https://github.com/TrustVC/w3c/commit/4a9f52a823e5836454c65239916fa5807c9d0be1)) --- packages/w3c-vc/CHANGELOG.md | 7 +++++++ packages/w3c-vc/package.json | 4 ++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/packages/w3c-vc/CHANGELOG.md b/packages/w3c-vc/CHANGELOG.md index eef9a5a0..f7aba188 100644 --- a/packages/w3c-vc/CHANGELOG.md +++ b/packages/w3c-vc/CHANGELOG.md @@ -1,3 +1,10 @@ +## [1.2.7-alpha.3](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.2.7-alpha.2...@trustvc/w3c-vc@1.2.7-alpha.3) (2025-04-09) + + +### Bug Fixes + +* add cache for jws 2020 v1 ([#48](https://github.com/TrustVC/w3c/issues/48)) ([4a9f52a](https://github.com/TrustVC/w3c/commit/4a9f52a823e5836454c65239916fa5807c9d0be1)) + ## [1.2.7-alpha.2](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.2.7-alpha.1...@trustvc/w3c-vc@1.2.7-alpha.2) (2025-04-09) diff --git a/packages/w3c-vc/package.json b/packages/w3c-vc/package.json index 9dfe5924..005f2071 100644 --- a/packages/w3c-vc/package.json +++ b/packages/w3c-vc/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c-vc", - "version": "1.2.7-alpha.2", + "version": "1.2.7-alpha.3", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", @@ -32,7 +32,7 @@ }, "dependencies": { "@mattrglobal/jsonld-signatures-bbs": "^1.2.0", - "@trustvc/w3c-credential-status": "^1.2.3-alpha.1", + "@trustvc/w3c-credential-status": "^1.2.3-alpha.2", "@trustvc/w3c-issuer": "^1.2.1", "did-resolver": "^4.1.0", "jsonld": "^6.0.0", From b957e099bdc203a19d8af40fb88bcc441d4cf0eb Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 9 Apr 2025 07:53:00 +0000 Subject: [PATCH 015/122] chore(release): @trustvc/w3c-cli@1.2.7-alpha.3 [skip ci] ## [1.2.7-alpha.3](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-cli@1.2.7-alpha.2...@trustvc/w3c-cli@1.2.7-alpha.3) (2025-04-09) ### Bug Fixes * add cache for jws 2020 v1 ([#48](https://github.com/TrustVC/w3c/issues/48)) ([4a9f52a](https://github.com/TrustVC/w3c/commit/4a9f52a823e5836454c65239916fa5807c9d0be1)) --- apps/w3c-cli/CHANGELOG.md | 7 +++++++ apps/w3c-cli/package.json | 8 ++++---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/apps/w3c-cli/CHANGELOG.md b/apps/w3c-cli/CHANGELOG.md index 216cec9b..50700486 100644 --- a/apps/w3c-cli/CHANGELOG.md +++ b/apps/w3c-cli/CHANGELOG.md @@ -1,3 +1,10 @@ +## [1.2.7-alpha.3](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-cli@1.2.7-alpha.2...@trustvc/w3c-cli@1.2.7-alpha.3) (2025-04-09) + + +### Bug Fixes + +* add cache for jws 2020 v1 ([#48](https://github.com/TrustVC/w3c/issues/48)) ([4a9f52a](https://github.com/TrustVC/w3c/commit/4a9f52a823e5836454c65239916fa5807c9d0be1)) + ## [1.2.7-alpha.2](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-cli@1.2.7-alpha.1...@trustvc/w3c-cli@1.2.7-alpha.2) (2025-04-09) diff --git a/apps/w3c-cli/package.json b/apps/w3c-cli/package.json index f05c81c2..56514284 100644 --- a/apps/w3c-cli/package.json +++ b/apps/w3c-cli/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c-cli", - "version": "1.2.7-alpha.2", + "version": "1.2.7-alpha.3", "description": "CLI for TrustVC W3C", "main": "dist/main.js", "types": "dist/main.d.ts", @@ -34,9 +34,9 @@ }, "dependencies": { "@inquirer/prompts": "^5.3.8", - "@trustvc/w3c-context": "^1.2.3-alpha.1", - "@trustvc/w3c-credential-status": "^1.2.3-alpha.1", - "@trustvc/w3c-vc": "^1.2.7-alpha.2", + "@trustvc/w3c-context": "^1.2.3-alpha.2", + "@trustvc/w3c-credential-status": "^1.2.3-alpha.2", + "@trustvc/w3c-vc": "^1.2.7-alpha.3", "@trustvc/w3c-issuer": "^1.2.1", "@types/yargs": "^17.0.32", "chalk": "^4.1.2", From 8380e2d29f37640f8eeadb60b5e0f3cf9214b00b Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 9 Apr 2025 07:53:30 +0000 Subject: [PATCH 016/122] chore(release): @trustvc/w3c@1.2.7-alpha.3 [skip ci] ## [1.2.7-alpha.3](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.2.7-alpha.2...@trustvc/w3c@1.2.7-alpha.3) (2025-04-09) ### Bug Fixes * add cache for jws 2020 v1 ([#48](https://github.com/TrustVC/w3c/issues/48)) ([4a9f52a](https://github.com/TrustVC/w3c/commit/4a9f52a823e5836454c65239916fa5807c9d0be1)) --- packages/w3c/CHANGELOG.md | 7 +++++++ packages/w3c/package.json | 8 ++++---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/packages/w3c/CHANGELOG.md b/packages/w3c/CHANGELOG.md index 605eb647..bb990815 100644 --- a/packages/w3c/CHANGELOG.md +++ b/packages/w3c/CHANGELOG.md @@ -1,3 +1,10 @@ +## [1.2.7-alpha.3](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.2.7-alpha.2...@trustvc/w3c@1.2.7-alpha.3) (2025-04-09) + + +### Bug Fixes + +* add cache for jws 2020 v1 ([#48](https://github.com/TrustVC/w3c/issues/48)) ([4a9f52a](https://github.com/TrustVC/w3c/commit/4a9f52a823e5836454c65239916fa5807c9d0be1)) + ## [1.2.7-alpha.2](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.2.7-alpha.1...@trustvc/w3c@1.2.7-alpha.2) (2025-04-09) diff --git a/packages/w3c/package.json b/packages/w3c/package.json index 6a64871f..14730044 100644 --- a/packages/w3c/package.json +++ b/packages/w3c/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c", - "version": "1.2.7-alpha.2", + "version": "1.2.7-alpha.3", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", @@ -32,10 +32,10 @@ } }, "dependencies": { - "@trustvc/w3c-context": "^1.2.3-alpha.1", - "@trustvc/w3c-credential-status": "^1.2.3-alpha.1", + "@trustvc/w3c-context": "^1.2.3-alpha.2", + "@trustvc/w3c-credential-status": "^1.2.3-alpha.2", "@trustvc/w3c-issuer": "^1.2.1", - "@trustvc/w3c-vc": "^1.2.7-alpha.2" + "@trustvc/w3c-vc": "^1.2.7-alpha.3" }, "repository": { "type": "git", From ce1c81fd475cb336f669479970ed749d49bd1fa4 Mon Sep 17 00:00:00 2001 From: rongquan1 <85145303+rongquan1@users.noreply.github.com> Date: Thu, 24 Jul 2025 11:49:28 +0800 Subject: [PATCH 017/122] chore: add multikey and data integrity support (#65) * fix: add multikey and data integrity support --- .gitignore | 2 +- apps/w3c-cli/CHANGELOG.md | 75 ++- apps/w3c-cli/package.json | 10 +- .../src/commands/credentialStatus/create.ts | 22 +- .../src/commands/credentialStatus/update.ts | 39 +- apps/w3c-cli/src/commands/derive.ts | 45 +- apps/w3c-cli/src/commands/did.ts | 48 +- apps/w3c-cli/src/commands/key-pair.ts | 54 +-- apps/w3c-cli/src/commands/sign.ts | 50 +- apps/w3c-cli/src/commands/verify.ts | 48 +- apps/w3c-cli/src/utils.ts | 7 +- apps/w3c-cli/tests/commands/did.test.ts | 142 ++++-- apps/w3c-cli/tests/commands/key-pair.test.ts | 35 +- apps/w3c-cli/tests/commands/sign.test.ts | 199 ++++++++ apps/w3c-cli/tests/commands/verify.test.ts | 154 ++++++ apps/w3c-cli/tests/fixtures/mockCredential.ts | 39 ++ apps/w3c-cli/tests/fixtures/mockDidWeb.ts | 29 ++ apps/w3c-cli/tests/main.test.ts | 451 ++++++++++++++++++ netlify.toml | 10 + package-lock.json | 40 +- package.json | 3 + packages/w3c-context/CHANGELOG.md | 71 ++- packages/w3c-context/README.md | 172 ++++++- packages/w3c-context/package.json | 5 +- .../src/context/bill-of-lading-carrier.json | 107 +++++ packages/w3c-context/src/context/coo.json | 196 ++++++++ .../src/context/data-integrity-v2.json | 81 ++++ .../w3c-context/src/context/multikey-v1.json | 35 ++ .../src/context/promissory-note.json | 82 ++++ .../src/context/qrcode-context.json | 20 + .../src/context/render-method-context.json | 1 - .../src/context/status-list-2021-v1.json | 39 ++ .../src/context/warehouse-receipt.json | 89 ++++ packages/w3c-context/src/index.ts | 2 + packages/w3c-context/src/lib/index.ts | 55 ++- packages/w3c-credential-status/CHANGELOG.md | 71 ++- packages/w3c-credential-status/package.json | 6 +- .../w3c-credential-status/src/lib/index.ts | 25 +- .../w3c-credential-status/src/lib/utils.ts | 13 + packages/w3c-issuer/CHANGELOG.md | 21 + packages/w3c-issuer/package.json | 2 +- packages/w3c-issuer/src/did-web/index.ts | 3 +- packages/w3c-issuer/src/lib/index.ts | 26 +- packages/w3c-vc/CHANGELOG.md | 68 ++- packages/w3c-vc/package.json | 6 +- packages/w3c-vc/src/index.ts | 3 +- packages/w3c-vc/src/lib/helper/index.ts | 11 +- .../src/lib/sign/credentialStatus/index.ts | 20 +- packages/w3c-vc/src/lib/types.ts | 1 + packages/w3c-vc/src/lib/w3c-vc.test.ts | 6 + packages/w3c-vc/src/lib/w3c-vc.ts | 4 +- packages/w3c/CHANGELOG.md | 68 ++- packages/w3c/package.json | 10 +- scripts/copy-files.sh | 7 +- 54 files changed, 2505 insertions(+), 323 deletions(-) create mode 100644 apps/w3c-cli/tests/commands/sign.test.ts create mode 100644 apps/w3c-cli/tests/commands/verify.test.ts create mode 100644 apps/w3c-cli/tests/fixtures/mockCredential.ts create mode 100644 apps/w3c-cli/tests/fixtures/mockDidWeb.ts create mode 100644 apps/w3c-cli/tests/main.test.ts create mode 100644 netlify.toml create mode 100644 packages/w3c-context/src/context/bill-of-lading-carrier.json create mode 100644 packages/w3c-context/src/context/coo.json create mode 100644 packages/w3c-context/src/context/data-integrity-v2.json create mode 100644 packages/w3c-context/src/context/multikey-v1.json create mode 100644 packages/w3c-context/src/context/promissory-note.json create mode 100644 packages/w3c-context/src/context/qrcode-context.json create mode 100644 packages/w3c-context/src/context/status-list-2021-v1.json create mode 100644 packages/w3c-context/src/context/warehouse-receipt.json diff --git a/.gitignore b/.gitignore index bc6a8992..3a717b51 100644 --- a/.gitignore +++ b/.gitignore @@ -50,4 +50,4 @@ signed_vc*.json credentialStatus*.json derived_vc*.json reveal*.json -public/context/ +public/context/*.json diff --git a/apps/w3c-cli/CHANGELOG.md b/apps/w3c-cli/CHANGELOG.md index 50700486..9ac083eb 100644 --- a/apps/w3c-cli/CHANGELOG.md +++ b/apps/w3c-cli/CHANGELOG.md @@ -1,23 +1,86 @@ -## [1.2.7-alpha.3](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-cli@1.2.7-alpha.2...@trustvc/w3c-cli@1.2.7-alpha.3) (2025-04-09) +## [1.2.18](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-cli@1.2.17...@trustvc/w3c-cli@1.2.18) (2025-06-13) ### Bug Fixes -* add cache for jws 2020 v1 ([#48](https://github.com/TrustVC/w3c/issues/48)) ([4a9f52a](https://github.com/TrustVC/w3c/commit/4a9f52a823e5836454c65239916fa5807c9d0be1)) +* expired and redacted doc checks ([#64](https://github.com/TrustVC/w3c/issues/64)) ([4d0a65a](https://github.com/TrustVC/w3c/commit/4d0a65ad467e07bc0f837368f6ff93f84abfb0a8)) -## [1.2.7-alpha.2](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-cli@1.2.7-alpha.1...@trustvc/w3c-cli@1.2.7-alpha.2) (2025-04-09) +## [1.2.17](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-cli@1.2.16...@trustvc/w3c-cli@1.2.17) (2025-06-09) ### Bug Fixes -* add export ([#47](https://github.com/TrustVC/w3c/issues/47)) ([dae74e7](https://github.com/TrustVC/w3c/commit/dae74e779e8f26dcd84f63e9baea905d2eca91fc)) +* cli derive stringify error ([#63](https://github.com/TrustVC/w3c/issues/63)) ([79b9f4f](https://github.com/TrustVC/w3c/commit/79b9f4fbafcc498b289c6313d72fb4d78e425203)) -## [1.2.7-alpha.1](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-cli@1.2.6...@trustvc/w3c-cli@1.2.7-alpha.1) (2025-04-09) +## [1.2.16](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-cli@1.2.15...@trustvc/w3c-cli@1.2.16) (2025-05-30) ### Bug Fixes -* update fetchCredentialStatusVC to use documentLoader ([#46](https://github.com/TrustVC/w3c/issues/46)) ([7fe49f8](https://github.com/TrustVC/w3c/commit/7fe49f8e5a01cf36f4fdd87bccd72f87554a9072)) +* type errors ([#62](https://github.com/TrustVC/w3c/issues/62)) ([e4cf81f](https://github.com/TrustVC/w3c/commit/e4cf81f4cab187be464f92503bf0f0c39aef61d7)) + +## [1.2.15](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-cli@1.2.14...@trustvc/w3c-cli@1.2.15) (2025-05-21) + + +### Bug Fixes + +* coo context ([#59](https://github.com/TrustVC/w3c/issues/59)) ([b802c6f](https://github.com/TrustVC/w3c/commit/b802c6f8605387024d5a50d81e4edfa3da709ba7)) + +## [1.2.14](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-cli@1.2.13...@trustvc/w3c-cli@1.2.14) (2025-05-20) + + +### Bug Fixes + +* add template context ([#58](https://github.com/TrustVC/w3c/issues/58)) ([8a467b7](https://github.com/TrustVC/w3c/commit/8a467b738bebe935f00af525684e84bfd01fe6e9)) + +## [1.2.13](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-cli@1.2.12...@trustvc/w3c-cli@1.2.13) (2025-05-16) + + +### Bug Fixes + +* cli error messages ([#54](https://github.com/TrustVC/w3c/issues/54)) ([3825ce9](https://github.com/TrustVC/w3c/commit/3825ce9598479f52a75b2a8dbd38efc97730950a)) + +## [1.2.12](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-cli@1.2.11...@trustvc/w3c-cli@1.2.12) (2025-05-14) + + +### Bug Fixes + +* add qrcode context ([#55](https://github.com/TrustVC/w3c/issues/55)) ([19cd0df](https://github.com/TrustVC/w3c/commit/19cd0dfd20e848f744e1a5d6255557bde101d998)) + +## [1.2.11](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-cli@1.2.10...@trustvc/w3c-cli@1.2.11) (2025-04-24) + + +### Bug Fixes + +* update promissory note context ([#53](https://github.com/TrustVC/w3c/issues/53)) ([e032f45](https://github.com/TrustVC/w3c/commit/e032f4582da0983d2ca5648d7c55fac6bc97c1f6)) + +## [1.2.10](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-cli@1.2.9...@trustvc/w3c-cli@1.2.10) (2025-04-23) + + +### Bug Fixes + +* add promissory note context for w3c ([#52](https://github.com/TrustVC/w3c/issues/52)) ([54b866a](https://github.com/TrustVC/w3c/commit/54b866a66ff1db2466628fb32a1bb4820d71b7d1)) + +## [1.2.9](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-cli@1.2.8...@trustvc/w3c-cli@1.2.9) (2025-04-22) + + +### Bug Fixes + +* clean up resolver ([#51](https://github.com/TrustVC/w3c/issues/51)) ([936b5ec](https://github.com/TrustVC/w3c/commit/936b5ec23a372ae441bde9cd99701cbdd2408465)) + +## [1.2.8](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-cli@1.2.7...@trustvc/w3c-cli@1.2.8) (2025-04-10) + + +### Bug Fixes + +* add bls to context cache ([#50](https://github.com/TrustVC/w3c/issues/50)) ([a1988b0](https://github.com/TrustVC/w3c/commit/a1988b0ef2d82c95c3e285c93eedd61b050e4fd9)) + +## [1.2.7](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-cli@1.2.6...@trustvc/w3c-cli@1.2.7) (2025-04-09) + + +### Bug Fixes + +* update fetchCredentialStatusVC to use documentLoader and add cache for jws 2020 v1 ([#49](https://github.com/TrustVC/w3c/issues/49)) ([2c50901](https://github.com/TrustVC/w3c/commit/2c50901035aac696f75ef386bd8beca367f02db7)) ## [1.2.6](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-cli@1.2.5...@trustvc/w3c-cli@1.2.6) (2025-04-08) diff --git a/apps/w3c-cli/package.json b/apps/w3c-cli/package.json index 56514284..c82b54e4 100644 --- a/apps/w3c-cli/package.json +++ b/apps/w3c-cli/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c-cli", - "version": "1.2.7-alpha.3", + "version": "1.2.18", "description": "CLI for TrustVC W3C", "main": "dist/main.js", "types": "dist/main.d.ts", @@ -34,10 +34,10 @@ }, "dependencies": { "@inquirer/prompts": "^5.3.8", - "@trustvc/w3c-context": "^1.2.3-alpha.2", - "@trustvc/w3c-credential-status": "^1.2.3-alpha.2", - "@trustvc/w3c-vc": "^1.2.7-alpha.3", - "@trustvc/w3c-issuer": "^1.2.1", + "@trustvc/w3c-context": "^1.2.13", + "@trustvc/w3c-credential-status": "^1.2.13", + "@trustvc/w3c-vc": "^1.2.17", + "@trustvc/w3c-issuer": "^1.2.4", "@types/yargs": "^17.0.32", "chalk": "^4.1.2", "inquirer": "^10.0.1", diff --git a/apps/w3c-cli/src/commands/credentialStatus/create.ts b/apps/w3c-cli/src/commands/credentialStatus/create.ts index 6a6fac87..a5dac3a6 100644 --- a/apps/w3c-cli/src/commands/credentialStatus/create.ts +++ b/apps/w3c-cli/src/commands/credentialStatus/create.ts @@ -6,21 +6,24 @@ import { } from '@trustvc/w3c-credential-status'; import { signCredential, SignedVerifiableCredential } from '@trustvc/w3c-vc'; import chalk from 'chalk'; -import fs from 'fs'; import { CredentialStatusQuestionType } from '../../types'; -import { readJsonFile, writeFile } from '../../utils'; +import { isDirectoryValid, readJsonFile, writeFile } from '../../utils'; export const command = 'create'; export const describe = 'Create a new credential status'; export const handler = async () => { - const answers = await promptQuestions(); + try { + const answers = await promptQuestions(); - const signedCSVC = await createSignedCredentialStatus(answers); + const signedCSVC = await createSignedCredentialStatus(answers); - if (!signedCSVC) return; + if (!signedCSVC) return; - saveSignedCredentialStatus(signedCSVC, answers.outputPath); + saveSignedCredentialStatus(signedCSVC, answers.outputPath); + } catch (err: unknown) { + console.error(chalk.red(`Error: ${err instanceof Error ? err.message : err}`)); + } }; export const promptQuestions = async (): Promise => { @@ -63,12 +66,7 @@ export const promptQuestions = async (): Promise = required: true, }); - try { - fs.readdirSync(answers.outputPath, { encoding: 'utf-8' }); - } catch (err) { - console.error(chalk.red(`Invalid file path provided: ${answers.outputPath}`)); - return; - } + if (!isDirectoryValid(answers.outputPath)) throw new Error('Output path is not valid'); answers.length = await number({ message: 'Please enter the length of the status list (default 16KB - 131,072):', diff --git a/apps/w3c-cli/src/commands/credentialStatus/update.ts b/apps/w3c-cli/src/commands/credentialStatus/update.ts index cf19180b..fe3f283e 100644 --- a/apps/w3c-cli/src/commands/credentialStatus/update.ts +++ b/apps/w3c-cli/src/commands/credentialStatus/update.ts @@ -8,24 +8,27 @@ import { } from '@trustvc/w3c-credential-status'; import { signCredential } from '@trustvc/w3c-vc'; import chalk from 'chalk'; -import fs from 'fs'; import { CredentialStatusQuestionType } from '../../types'; +import { isDirectoryValid, readJsonFile } from '../../utils'; import { saveSignedCredentialStatus } from './create'; -import { readJsonFile } from '../../utils'; export const command = 'update'; export const describe = 'Update a credential status'; export const handler = async () => { - const answers = await promptQuestions(); + try { + const answers = await promptQuestions(); - if (!answers) return; + if (!answers) return; - const signedCSVC = await createSignedCredentialStatus(answers); + const signedCSVC = await createSignedCredentialStatus(answers); - if (!signedCSVC) return; + if (!signedCSVC) return; - saveSignedCredentialStatus(signedCSVC, answers.outputPath); + saveSignedCredentialStatus(signedCSVC, answers.outputPath); + } catch (err: unknown) { + console.error(chalk.red(`Error: ${err instanceof Error ? err.message : err}`)); + } }; export const promptQuestions = async (): Promise => { @@ -44,8 +47,7 @@ export const promptQuestions = async (): Promise = try { credentialStatusVC = await fetchCredentialStatusVC(answers.hostingUrl); } catch (err: unknown) { - console.error(chalk.red(`Invalid URL provided: ${answers.hostingUrl}`)); - return; + throw new Error(`Invalid URL provided: ${answers.hostingUrl}`); } answers.keyPairPath = await input({ @@ -55,12 +57,7 @@ export const promptQuestions = async (): Promise = }); // Validate and read the key pair file - try { - answers.keypairData = readJsonFile(answers.keyPairPath, 'key pair'); - } catch (err) { - console.error(chalk.red(`Invalid file path provided: ${answers.keyPairPath}`)); - return; - } + answers.keypairData = readJsonFile(answers.keyPairPath, 'key pair'); answers.outputPath = await input({ message: 'Please specify a directory path to save the credential status file (optional):', @@ -68,12 +65,7 @@ export const promptQuestions = async (): Promise = required: true, }); - try { - fs.readdirSync(answers.outputPath, { encoding: 'utf-8' }); - } catch (err) { - console.error(chalk.red(`Invalid file path provided: ${answers.outputPath}`)); - return; - } + if (!isDirectoryValid(answers.outputPath)) throw new Error('Output path is not valid'); answers.type = credentialStatusVC?.credentialSubject?.type; @@ -158,9 +150,8 @@ export const createSignedCredentialStatus = async (answers: CredentialStatusQues throw new Error('Invalid credential status type.'); } catch (err: unknown) { if (!(err instanceof Error)) { - console.error(chalk.red('An error occurred while signing the credential status.')); - return; + throw err; } - console.error(chalk.red(`Error signing credential status: ${err.message}`)); + throw new Error(`Error signing credential status: ${err.message}`); } }; diff --git a/apps/w3c-cli/src/commands/derive.ts b/apps/w3c-cli/src/commands/derive.ts index 15c3aff1..76b0d6ed 100644 --- a/apps/w3c-cli/src/commands/derive.ts +++ b/apps/w3c-cli/src/commands/derive.ts @@ -1,9 +1,8 @@ import { ContextDocument, SignedVerifiableCredential, deriveCredential } from '@trustvc/w3c-vc'; import chalk from 'chalk'; -import fs from 'fs'; import inquirer from 'inquirer'; import { CredentialQuestionType, QuestionType, RevealQuestionType } from '../types'; -import { isDirectoryValid, readJsonFile } from '../utils'; +import { isDirectoryValid, readJsonFile, writeFile } from '../utils'; export const command = 'derive'; export const describe = @@ -38,20 +37,24 @@ const outputPathPrompt: any = { }; export const handler = async () => { - const answers = await promptForInputs(); - if (!answers) return; - - const { revealData, credentialData, outputPath } = answers; - - // Derive the credential - const derived = await derivedCredential( - credentialData as SignedVerifiableCredential, - revealData as ContextDocument, - ); - if (!derived) return; - - // Save the derived credential - await saveDerivedCredential(derived, outputPath); + try { + const answers = await promptForInputs(); + if (!answers) return; + + const { revealData, credentialData, outputPath } = answers; + + // Derive the credential + const derived = await derivedCredential( + credentialData as SignedVerifiableCredential, + revealData as ContextDocument, + ); + if (!derived) return; + + // Save the derived credential + await saveDerivedCredential(derived, outputPath); + } catch (err: unknown) { + console.error(chalk.red(`Error: ${err instanceof Error ? err.message : err}`)); + } }; // Derived the credential with the provided parameters @@ -76,10 +79,10 @@ export const saveDerivedCredential = async ( ) => { const filePath = `${outputPath}/derived_vc.json`; try { - fs.writeFileSync(filePath, JSON.stringify(derivedCredential)); + writeFile(filePath, derivedCredential); console.log(chalk.green(`Derived credential saved successfully to ${filePath}`)); } catch (err) { - console.error(chalk.red(`Unable to save derived credential to ${filePath}`)); + throw new Error(`Unable to save derived credential to ${filePath}`); } }; @@ -90,18 +93,18 @@ export const promptForInputs = async () => { )) as CredentialQuestionType; const credentialData = readJsonFile(credentialPath, 'credential'); - if (!credentialData) return null; + if (!credentialData) throw new Error('Unable to read credential file'); const { revealPath }: RevealQuestionType = (await inquirer.prompt( revealPrompt, )) as RevealQuestionType; const revealData = readJsonFile(revealPath, 'reveal'); - if (!revealData) return null; + if (!revealData) throw new Error('Unable to read reveal file'); const { outputPath }: QuestionType = (await inquirer.prompt(outputPathPrompt)) as QuestionType; - if (!isDirectoryValid(outputPath)) return null; + if (!isDirectoryValid(outputPath)) throw new Error('Output path is not valid'); return { revealData, credentialData, outputPath }; }; diff --git a/apps/w3c-cli/src/commands/did.ts b/apps/w3c-cli/src/commands/did.ts index 6a93358a..1d65dbfa 100644 --- a/apps/w3c-cli/src/commands/did.ts +++ b/apps/w3c-cli/src/commands/did.ts @@ -1,22 +1,25 @@ import { IssuedDID, IssuedDIDOption, issueDID } from '@trustvc/w3c-issuer'; import chalk from 'chalk'; -import fs from 'fs'; import inquirer from 'inquirer'; import { KeyPairQuestionType, QuestionType } from '../types'; -import { writeFile } from '../utils'; +import { isDirectoryValid, readJsonFile, writeFile } from '../utils'; export const command = 'did'; export const describe = 'Generate a new DID token file from a key pair file and a domain name'; export const handler = async () => { - const answers = await promptQuestions(); - if (!answers) return; + try { + const answers = await promptQuestions(); + if (!answers) return; - const { keypairData, outputPath } = answers; - const did = await getIssuedDid(keypairData); - if (!did) return; + const { keypairData, outputPath } = answers; + const did = await getIssuedDid(keypairData); + if (!did) return; - await saveIssuedDid(did, outputPath); + await saveIssuedDid(did, outputPath); + } catch (err: unknown) { + console.error(chalk.red(`Error: ${err instanceof Error ? err.message : err}`)); + } }; export const getIssuedDid = async (keypairData: IssuedDIDOption): Promise => { @@ -27,13 +30,11 @@ export const getIssuedDid = async (keypairData: IssuedDIDOption): Promise { name: 'domainName', type: 'input', message: - 'Please enter your domain for hosting the did-web public key (e.g., https://example.com/.wellknown/did.json):', + 'Please enter your domain for hosting the did-web public key (e.g., https://example.com/.well-known/did.json):', required: true, }, { @@ -82,26 +83,15 @@ export const promptQuestions = async () => { )) as KeyPairQuestionType; // Validate and read the key pair file - let data: string; - try { - data = fs.readFileSync(keyPairPath, { encoding: 'utf8', flag: 'r' }); - } catch (err) { - console.error(chalk.red(`Invalid file path provided: ${keyPairPath}`)); - return; - } - - const keypairData: IssuedDIDOption = JSON.parse(data); + const keypairData: IssuedDIDOption = readJsonFile(keyPairPath, 'key pair'); + if (!keypairData) throw new Error('Unable to read key pair file'); // Prompt for the domain name and output path const { domainName, outputPath }: QuestionType = (await inquirer.prompt( questions, )) as QuestionType; - try { - fs.readdirSync(outputPath, { encoding: 'utf-8' }); - } catch (err) { - console.error(chalk.red(`Invalid file path provided: ${outputPath}`)); - return; - } + + if (!isDirectoryValid(outputPath)) throw new Error('Output path is not valid'); keypairData.domain = domainName; return { keypairData, domainName, outputPath }; diff --git a/apps/w3c-cli/src/commands/key-pair.ts b/apps/w3c-cli/src/commands/key-pair.ts index c13ea919..26ff1cb3 100644 --- a/apps/w3c-cli/src/commands/key-pair.ts +++ b/apps/w3c-cli/src/commands/key-pair.ts @@ -2,17 +2,21 @@ import { input, select } from '@inquirer/prompts'; import type { GeneratedKeyPair, GenerateKeyPairOptions } from '@trustvc/w3c-issuer'; import { generateKeyPair, VerificationType } from '@trustvc/w3c-issuer'; import chalk from 'chalk'; -import fs from 'fs'; import { GenerateInput } from '../types'; +import { isDirectoryValid, writeFile } from '../utils'; export const command = 'key-pair'; export const describe = 'Generate a new key pair file'; export const handler = async () => { - const answers = await promptQuestions(); - if (!answers) return; + try { + const answers = await promptQuestions(); + if (!answers) return; - await generateAndSaveKeyPair(answers); + await generateAndSaveKeyPair(answers); + } catch (err: unknown) { + console.error(chalk.red(`Error: ${err instanceof Error ? err.message : err}`)); + } }; export const promptQuestions = async (): Promise => { @@ -40,12 +44,10 @@ export const promptQuestions = async (): Promise => { required: true, }); - try { - fs.readdirSync(answers.keyPath, { encoding: 'utf-8' }); - } catch (err) { - console.error(chalk.red(`Invalid file path provided: ${answers.keyPath}`)); - return; + if (!isDirectoryValid(answers.keyPath)) { + throw new Error(`Invalid file path provided: ${answers.keyPath}`); } + return answers; }; @@ -67,31 +69,23 @@ export const generateAndSaveKeyPair = async ({ encAlgo, seedBase58, keyPath }: G } catch (err) { if (err instanceof Error) { if (err.message == 'Non-base58btc character') { - console.error( - chalk.red('Invalid seed provided. Please provide a valid seed in base58 format.'), - ); - return; + throw new Error('Invalid seed provided. Please provide a valid seed in base58 format.'); } } - console.error(chalk.red('Error generating keypair')); - return; + throw new Error('Error generating keypair'); } - try { - const keyPair: GeneratedKeyPair = { - type: keypairData.type, - }; - if (keypairData.type === VerificationType.Bls12381G2Key2020) { - keyPair.seedBase58 = keypairData.seedBase58; - keyPair.privateKeyBase58 = keypairData.privateKeyBase58; - keyPair.publicKeyBase58 = keypairData.publicKeyBase58; - } + const keyPair: GeneratedKeyPair = { + type: keypairData.type, + }; + if (keypairData.type === VerificationType.Bls12381G2Key2020) { + keyPair.seedBase58 = keypairData.seedBase58; + keyPair.privateKeyBase58 = keypairData.privateKeyBase58; + keyPair.publicKeyBase58 = keypairData.publicKeyBase58; + } - fs.writeFileSync(keyFilePath, JSON.stringify(keyPair)); - console.log(chalk.green(`File written successfully to ${keyFilePath}`)); + writeFile(keyFilePath, keyPair); + console.log(chalk.green(`File written successfully to ${keyFilePath}`)); - return keypairData; - } catch (err) { - console.error(chalk.red(`Unable to write file to ${keyFilePath}`)); - } + return keypairData; }; diff --git a/apps/w3c-cli/src/commands/sign.ts b/apps/w3c-cli/src/commands/sign.ts index eee8344d..75e25100 100644 --- a/apps/w3c-cli/src/commands/sign.ts +++ b/apps/w3c-cli/src/commands/sign.ts @@ -1,10 +1,9 @@ +import { PrivateKeyPair } from '@trustvc/w3c-issuer'; import { signCredential, VerifiableCredential } from '@trustvc/w3c-vc'; import chalk from 'chalk'; -import fs from 'fs'; import inquirer from 'inquirer'; import { CredentialQuestionType, KeyPairQuestionType, QuestionType } from '../types'; -import { PrivateKeyPair } from '@trustvc/w3c-issuer'; -import { isDirectoryValid, readJsonFile } from '../utils'; +import { isDirectoryValid, readJsonFile, writeFile } from '../utils'; export const command = 'sign'; export const describe = @@ -39,20 +38,24 @@ const outputPathPrompt: any = { }; export const handler = async () => { - const answers = await promptForInputs(); - if (!answers) return; - - const { keypairData, credentialData, outputPath } = answers; - - // Sign the credential - const signedCredential = await signCredentialWithKeyPair( - credentialData, - keypairData as PrivateKeyPair, - ); - if (!signedCredential) return; - - // Save the signed credential - await saveSignedCredential(signedCredential, outputPath); + try { + const answers = await promptForInputs(); + if (!answers) return; + + const { keypairData, credentialData, outputPath } = answers; + + // Sign the credential + const signedCredential = await signCredentialWithKeyPair( + credentialData, + keypairData as PrivateKeyPair, + ); + if (!signedCredential) return; + + // Save the signed credential + await saveSignedCredential(signedCredential, outputPath); + } catch (err: unknown) { + console.error(chalk.red(`Error: ${err instanceof Error ? err.message : err}`)); + } }; // Sign the credential with the provided key pair @@ -65,8 +68,7 @@ export const signCredentialWithKeyPair = async ( if (result?.signed) { return result.signed; } else { - console.error(chalk.red(`Error: ${result.error}`)); - return null; + throw new Error(result?.error); } }; @@ -77,10 +79,10 @@ export const saveSignedCredential = async ( ) => { const filePath = `${outputPath}/signed_vc.json`; try { - fs.writeFileSync(filePath, JSON.stringify(signedCredential)); + writeFile(filePath, signedCredential); console.log(chalk.green(`Signed credential saved successfully to ${filePath}`)); } catch (err) { - console.error(chalk.red(`Unable to save signed credential to ${filePath}`)); + throw new Error(`Unable to save signed credential to ${filePath}`); } }; @@ -91,18 +93,18 @@ export const promptForInputs = async () => { )) as KeyPairQuestionType; const keypairData = readJsonFile(keyPairPath, 'key pair'); - if (!keypairData) return null; + if (!keypairData) throw new Error('Unable to read key pair file'); const { credentialPath }: CredentialQuestionType = (await inquirer.prompt( credentialPrompt, )) as CredentialQuestionType; const credentialData = readJsonFile(credentialPath, 'credential'); - if (!credentialData) return null; + if (!credentialData) throw new Error('Unable to read credential file'); const { outputPath }: QuestionType = (await inquirer.prompt(outputPathPrompt)) as QuestionType; - if (!isDirectoryValid(outputPath)) return null; + if (!isDirectoryValid(outputPath)) throw new Error('Output path is not valid'); return { keypairData, credentialData, outputPath }; }; diff --git a/apps/w3c-cli/src/commands/verify.ts b/apps/w3c-cli/src/commands/verify.ts index 0085f75c..08f4ab9d 100644 --- a/apps/w3c-cli/src/commands/verify.ts +++ b/apps/w3c-cli/src/commands/verify.ts @@ -1,4 +1,10 @@ import { + GeneralCredentialStatus, + isCredentialStatusStatusList, +} from '@trustvc/w3c-credential-status'; +import { + CredentialStatus, + CredentialStatusResult, SignedVerifiableCredential, verifyCredential, verifyCredentialStatus, @@ -22,13 +28,17 @@ const credentialPrompt: any = { }; export const handler = async () => { - const answers = await promptForCredential(); - if (!answers) return; + try { + const answers = await promptForCredential(); + if (!answers) return; - const { credentialData } = answers; + const { credentialData } = answers; - // Verify the credential - await verifyCredentialData(credentialData as SignedVerifiableCredential); + // Verify the credential + await verifyCredentialData(credentialData as SignedVerifiableCredential); + } catch (err: unknown) { + console.error(chalk.red(`Error: ${err instanceof Error ? err.message : err}`)); + } }; // Verify the verifiable credential using the `verifyCredential` method @@ -37,9 +47,16 @@ export const verifyCredentialData = async ( ): Promise => { const result = await verifyCredential(credentialData); - let credentialStatusResult; - if (credentialData?.credentialStatus) { - credentialStatusResult = await verifyCredentialStatus(credentialData.credentialStatus); + let credentialStatusResult: CredentialStatusResult[] | undefined; + const credentialStatuses = [].concat(credentialData?.credentialStatus) || []; + + if ( + credentialStatuses && + credentialStatuses.every((cs: GeneralCredentialStatus) => isCredentialStatusStatusList(cs)) + ) { + credentialStatusResult = await Promise.all( + credentialStatuses.map((cs: CredentialStatus) => verifyCredentialStatus(cs)), + ); } if (result.verified) { @@ -52,14 +69,19 @@ export const verifyCredentialData = async ( } if (credentialStatusResult) { - if ('status' in credentialStatusResult) { + if (credentialStatusResult?.every((r) => 'status' in r)) { console.log( chalk.green( - `Credential status verification result: "${credentialStatusResult.purpose}:${credentialStatusResult.status}"`, + `Credential status verification result: "${credentialStatusResult.map((csr) => `${csr.purpose}:${csr.status}`)}"`, ), ); - } else if (credentialStatusResult.error) { - console.error(chalk.red(`Error: ${credentialStatusResult.error}`)); + } else if (credentialStatusResult?.some((r) => r?.error)) { + throw new Error( + `${credentialStatusResult + ?.filter((r) => r.error) + ?.map((r) => r.error) + ?.join(', ')}`, + ); } } }; @@ -71,7 +93,7 @@ export const promptForCredential = async () => { )) as CredentialQuestionType; const credentialData = readJsonFile(credentialPath, 'credential'); - if (!credentialData) return null; + if (!credentialData) throw new Error('Unable to read credential file'); return { credentialData }; }; diff --git a/apps/w3c-cli/src/utils.ts b/apps/w3c-cli/src/utils.ts index 7c066178..2ef7d8a4 100644 --- a/apps/w3c-cli/src/utils.ts +++ b/apps/w3c-cli/src/utils.ts @@ -6,7 +6,7 @@ export const writeFile = (path: string, data: T) => { fs.writeFileSync(path, JSON.stringify(data)); console.log(chalk.green(`File written successfully to ${path}`)); } catch (err) { - console.error(chalk.red(`Unable to write file to ${path}`)); + throw new Error(`Unable to write file to ${path}`); } }; @@ -16,8 +16,7 @@ export const readJsonFile = (filePath: string, fileType: string): T | null => const data = fs.readFileSync(filePath, { encoding: 'utf8' }); return JSON.parse(data) as T; } catch (err) { - console.error(chalk.red(`Invalid ${fileType} file path: ${filePath}`)); - return null; + throw new Error(`Invalid ${fileType} file path: ${filePath}`); } }; @@ -27,7 +26,7 @@ export const isDirectoryValid = (path: string): boolean => { fs.readdirSync(path, { encoding: 'utf-8' }); return true; } catch (err) { - console.error(chalk.red(`Invalid output directory path: ${path}`)); + console.warn(chalk.yellow(`Invalid directory path: ${path}`)); return false; } }; diff --git a/apps/w3c-cli/tests/commands/did.test.ts b/apps/w3c-cli/tests/commands/did.test.ts index adad5c83..398028f2 100644 --- a/apps/w3c-cli/tests/commands/did.test.ts +++ b/apps/w3c-cli/tests/commands/did.test.ts @@ -1,11 +1,10 @@ -import { VerificationType } from '@trustvc/w3c-issuer'; +import { IssuedDIDOption, VerificationType } from '@trustvc/w3c-issuer'; import chalk from 'chalk'; import fs from 'fs'; import inquirer from 'inquirer'; -import { beforeEach, describe, expect, it, vi } from 'vitest'; +import { beforeEach, describe, expect, it, MockedFunction, vi } from 'vitest'; import { getIssuedDid, promptQuestions, saveIssuedDid } from '../../src/commands/did'; import { IssueDidInput } from '../../src/types'; -import { IssuedDIDOption } from '@trustvc/w3c-issuer'; vi.mock('inquirer'); vi.mock('fs', async () => { @@ -14,6 +13,21 @@ vi.mock('fs', async () => { ...originalFs, }; }); +vi.mock('../../src/utils', async () => { + const originalUtils = await vi.importActual('../../src/utils'); + return { + ...originalUtils, + isDirectoryValid: vi.fn(), + }; +}); +vi.mock('@trustvc/w3c-issuer', async () => { + const originalModule = + await vi.importActual('@trustvc/w3c-issuer'); + return { + ...originalModule, + issueDID: vi.fn(), + }; +}); vi.mock('chalk', async () => { const originalChalk = await vi.importActual('chalk'); return { @@ -26,11 +40,13 @@ describe('did', () => { vi.clearAllMocks(); vi.resetAllMocks(); }); + describe('promptQuestions', () => { beforeEach(() => { vi.clearAllMocks(); vi.resetAllMocks(); }); + it('should return correct answers for valid file path', async () => { const input: IssueDidInput = { keyPairPath: './keypair.json', @@ -44,6 +60,10 @@ describe('did', () => { // Mocks the readFileSync function so that it successfully reads a file vi.spyOn(fs, 'readFileSync').mockReturnValue(JSON.stringify(mockKeypairData)); + // Mock isDirectoryValid to return true for this specific test case + const utils = await import('../../src/utils'); + (utils.isDirectoryValid as MockedFunction).mockReturnValue(true); + const answers: any = await promptQuestions(); expect(answers.domainName).toBe(input.domainName); @@ -64,16 +84,27 @@ describe('did', () => { }; (inquirer.prompt as any).mockResolvedValue(input); - const consoleLogSpy = vi.spyOn(console, 'error'); vi.spyOn(fs, 'readFileSync').mockImplementation(() => { throw new Error(); }); - await promptQuestions(); + await expect(promptQuestions()).rejects.toThrowError( + `Invalid key pair file path: ${input.keyPairPath}`, + ); + }); - expect(consoleLogSpy).toHaveBeenNthCalledWith( - 1, - chalk.red(`Invalid file path provided: ${input.keyPairPath}`), + it('should throw error for invalid keypair file content (not JSON)', async () => { + const input: IssueDidInput = { + keyPairPath: './keypair.json', + domainName: 'https://example.com', + outputPath: '.', + }; + (inquirer.prompt as any).mockResolvedValue(input); + + vi.spyOn(fs, 'readFileSync').mockReturnValue('invalid json'); // Not a JSON string + + await expect(promptQuestions()).rejects.toThrowError( + `Invalid key pair file path: ${input.keyPairPath}`, ); }); @@ -84,8 +115,6 @@ describe('did', () => { outputPath: './/bad-path', }; - const consoleLogSpy = vi.spyOn(console, 'error'); - vi.spyOn(fs, 'readFileSync').mockImplementation(() => { return '{}'; }); @@ -94,39 +123,96 @@ describe('did', () => { }); (inquirer.prompt as any).mockResolvedValue(input); - await promptQuestions(); + await expect(promptQuestions()).rejects.toThrowError(`Output path is not valid`); + }); - expect(consoleLogSpy).toHaveBeenNthCalledWith( - 1, - chalk.red(`Invalid file path provided: ${input.outputPath}`), - ); + it('should throw error if outputPath is a file', async () => { + const input: IssueDidInput = { + keyPairPath: './keypair.json', + domainName: 'https://example.com', + outputPath: './somefile.json', // outputPath is a file + }; + + vi.spyOn(fs, 'readFileSync').mockReturnValue('{}'); // Valid JSON + + // Mock isDirectoryValid to return false for this specific test case + const utils = await import('../../src/utils'); + (utils.isDirectoryValid as MockedFunction).mockReturnValue(false); + + (inquirer.prompt as any).mockResolvedValue(input); + await expect(promptQuestions()).rejects.toThrowError('Output path is not valid'); }); }); describe('getIssuedDid', () => { - beforeEach(() => { + let issueDIDMock: MockedFunction; + + beforeEach(async () => { vi.clearAllMocks(); vi.resetAllMocks(); + + const issuerModule = await import('@trustvc/w3c-issuer'); + issueDIDMock = issuerModule.issueDID as MockedFunction; }); - it('should throw error if getIssuedDid receives invalid domain name', async () => { - const consoleLogSpy = vi.spyOn(console, 'error'); + it('should throw error if getIssuedDid receives invalid domain name', async () => { const mockKeypairData: IssuedDIDOption = { type: VerificationType.Bls12381G1Key2020, domain: 'bad-domain-name', }; - await getIssuedDid(mockKeypairData); - expect(consoleLogSpy).toHaveBeenNthCalledWith( - 1, - chalk.red(`Error generating DID token: Invalid domain`), + issueDIDMock.mockRejectedValue(new Error('Invalid domain')); + await expect(getIssuedDid(mockKeypairData)).rejects.toThrowError( + 'Error generating DID token: Invalid domain', + ); + }); + + it('should return did details if domain name is valid', async () => { + const mockKeypairData: IssuedDIDOption = { + type: VerificationType.Bls12381G1Key2020, + domain: 'https://example.com', + }; + // Basic check, as the actual generation is done by an external library + issueDIDMock.mockResolvedValue({ + wellKnownDid: { id: 'did:web:example.com' }, + didKeyPairs: { id: 'did:web:example.com#key-1' }, + }); + const result = await getIssuedDid(mockKeypairData); + expect(result).toHaveProperty('wellKnownDid'); + expect(result).toHaveProperty('didKeyPairs'); + }); + + it('should log "KeyPair already exists" error and return undefined', async () => { + const mockKeypairData: IssuedDIDOption = { + type: VerificationType.Bls12381G1Key2020, + domain: 'example.com', + }; + const errorMessage = 'KeyPair already exists'; + issueDIDMock.mockRejectedValue(new Error(errorMessage)); + + await expect(getIssuedDid(mockKeypairData)).rejects.toThrowError( + 'Error generating DID token: KeyPair already exists in Did Document', + ); + }); + + it('should log generic "Error generating DID token" for other errors and return undefined', async () => { + const mockKeypairData: IssuedDIDOption = { + type: VerificationType.Bls12381G1Key2020, + domain: 'example.com', + }; + issueDIDMock.mockRejectedValue(new Error('Some other internal error')); + + await expect(getIssuedDid(mockKeypairData)).rejects.toThrowError( + 'Error generating DID token', ); }); }); + describe('saveIssuedDid', () => { beforeEach(() => { vi.clearAllMocks(); vi.resetAllMocks(); }); + it('should write files successfully', async () => { const consoleLogSpy = vi.spyOn(console, 'log'); @@ -146,21 +232,15 @@ describe('did', () => { chalk.green(`File written successfully to ./didKeyPairs.json`), ); }); + it('should throw error if writeFileSync fails', async () => { - const consoleLogSpy = vi.spyOn(console, 'error'); const writeFileMock = vi.spyOn(fs, 'writeFileSync'); writeFileMock.mockImplementation(() => { throw new Error(); }); - await saveIssuedDid({} as any, '.'); - expect(consoleLogSpy).toHaveBeenNthCalledWith( - 1, - chalk.red(`Unable to write file to ./wellknown.json`), - ); - expect(consoleLogSpy).toHaveBeenNthCalledWith( - 2, - chalk.red(`Unable to write file to ./didKeyPairs.json`), + await expect(saveIssuedDid({} as any, '.')).rejects.toThrowError( + 'Unable to write file to ./wellknown.json', ); }); }); diff --git a/apps/w3c-cli/tests/commands/key-pair.test.ts b/apps/w3c-cli/tests/commands/key-pair.test.ts index 38d07519..6472e418 100644 --- a/apps/w3c-cli/tests/commands/key-pair.test.ts +++ b/apps/w3c-cli/tests/commands/key-pair.test.ts @@ -73,15 +73,12 @@ describe('key-pair', () => { .mockResolvedValueOnce(input.keyPath); (prompts.select as any).mockResolvedValueOnce(input.encAlgo); const readDirMock = vi.spyOn(fs, 'readdirSync'); - const consoleErrorSpy = vi.spyOn(console, 'error'); readDirMock.mockImplementation(() => { throw new Error(); }); - await promptQuestions(); - - expect(consoleErrorSpy).toHaveBeenCalledWith( - chalk.red(`Invalid file path provided: ${input.keyPath}`), + await expect(promptQuestions()).rejects.toThrowError( + `Invalid file path provided: ${input.keyPath}`, ); }); }); @@ -156,13 +153,8 @@ describe('key-pair', () => { keyPath: '.', }; - const consoleLogSpy = vi.spyOn(console, 'error'); - - await generateAndSaveKeyPair(input); - - expect(consoleLogSpy).toHaveBeenNthCalledWith( - 1, - chalk.red('Invalid seed provided. Please provide a valid seed in base58 format.'), + await expect(generateAndSaveKeyPair(input)).rejects.toThrowError( + 'Invalid seed provided. Please provide a valid seed in base58 format.', ); }); @@ -172,14 +164,10 @@ describe('key-pair', () => { seedBase58: '', keyPath: '.', }; - - const consoleLogSpy = vi.spyOn(console, 'error'); vi.spyOn(w3cIssuer, 'generateKeyPair').mockImplementation(() => { throw new Error(); }); - await generateAndSaveKeyPair(input); - - expect(consoleLogSpy).toHaveBeenNthCalledWith(1, chalk.red('Error generating keypair')); + await expect(generateAndSaveKeyPair(input)).rejects.toThrowError('Error generating keypair'); }); it('should fail generateAndSaveKeyPair when unable to save file', async () => { @@ -188,22 +176,13 @@ describe('key-pair', () => { seedBase58: '', keyPath: '///invalid-key-path///', // This value doesn't really matter since we mock writeFil to always thro error below }; - // Automatically keys in "user input" that inquirer will receive - (prompts.input as any) - .mockResolvedValueOnce(input.seedBase58) - .mockResolvedValueOnce(input.keyPath); - (prompts.select as any).mockResolvedValueOnce(input.encAlgo); - const consoleLogSpy = vi.spyOn(console, 'error'); const writeFileMock = vi.spyOn(fs, 'writeFileSync'); writeFileMock.mockImplementation(() => { throw new Error(); }); - await generateAndSaveKeyPair(input); - - expect(consoleLogSpy).toHaveBeenNthCalledWith( - 1, - chalk.red(`Unable to write file to ${input.keyPath}/keypair.json`), + await expect(generateAndSaveKeyPair(input)).rejects.toThrowError( + `Unable to write file to ${input.keyPath}/keypair.json`, ); }); }); diff --git a/apps/w3c-cli/tests/commands/sign.test.ts b/apps/w3c-cli/tests/commands/sign.test.ts new file mode 100644 index 00000000..e8d6d8d2 --- /dev/null +++ b/apps/w3c-cli/tests/commands/sign.test.ts @@ -0,0 +1,199 @@ +import { VerifiableCredential } from '@trustvc/w3c-vc'; +import fs from 'fs'; +import inquirer from 'inquirer'; +import { beforeEach, describe, expect, it, vi } from 'vitest'; +import { + promptForInputs, + saveSignedCredential, + signCredentialWithKeyPair, +} from '../../src/commands/sign'; +import { mockCredential as freezedMockCredential } from '../fixtures/mockCredential'; +import { mockKeyPair } from '../fixtures/mockDidWeb'; + +vi.mock('inquirer'); +vi.mock('fs', async () => { + const originalFs = await vi.importActual('fs'); + return { + ...originalFs, + }; +}); +vi.mock('chalk', async () => { + const originalChalk = await vi.importActual('chalk'); + return { + ...originalChalk, + }; +}); + +let mockCredential: VerifiableCredential; + +describe('sign', () => { + beforeEach(() => { + vi.clearAllMocks(); + vi.resetAllMocks(); + }); + + describe('promptForInputs', () => { + beforeEach(() => { + vi.clearAllMocks(); + vi.resetAllMocks(); + }); + + it('should return correct answers for valid inputs', async () => { + const input = { + keyPairPath: './keypair.json', + credentialPath: './credential.json', + outputPath: '.', + }; + + (inquirer.prompt as any) + .mockResolvedValueOnce({ keyPairPath: input.keyPairPath }) + .mockResolvedValueOnce({ credentialPath: input.credentialPath }) + .mockResolvedValueOnce({ outputPath: input.outputPath }); + + vi.spyOn(fs, 'readFileSync') + .mockReturnValueOnce(JSON.stringify(mockKeyPair)) + .mockReturnValueOnce(JSON.stringify(freezedMockCredential)); + + const answers = await promptForInputs(); + + expect(answers.keypairData).toStrictEqual(mockKeyPair); + expect(answers.credentialData).toStrictEqual(freezedMockCredential); + expect(answers.outputPath).toBe(input.outputPath); + }); + + it('should throw error for invalid key pair file path', async () => { + const input = { + keyPairPath: './invalid-keypair.json', + }; + + (inquirer.prompt as any).mockResolvedValueOnce({ keyPairPath: input.keyPairPath }); + + vi.spyOn(fs, 'readFileSync').mockImplementation(() => { + throw new Error(); + }); + + await expect(promptForInputs()).rejects.toThrowError( + `Invalid key pair file path: ${input.keyPairPath}`, + ); + }); + + it('should throw error for invalid credential file path', async () => { + const input = { + keyPairPath: './keypair.json', + credentialPath: './invalid-credential.json', + }; + + (inquirer.prompt as any) + .mockResolvedValueOnce({ keyPairPath: input.keyPairPath }) + .mockResolvedValueOnce({ credentialPath: input.credentialPath }); + + vi.spyOn(fs, 'readFileSync') + .mockReturnValueOnce(JSON.stringify(mockKeyPair)) + .mockImplementationOnce(() => { + throw new Error(); + }); + + await expect(promptForInputs()).rejects.toThrowError( + `Invalid credential file path: ${input.credentialPath}`, + ); + }); + + it('should throw error for invalid output path', async () => { + const input = { + keyPairPath: './keypair.json', + credentialPath: './credential.json', + outputPath: './invalid-dir', + }; + + (inquirer.prompt as any) + .mockResolvedValueOnce({ keyPairPath: input.keyPairPath }) + .mockResolvedValueOnce({ credentialPath: input.credentialPath }) + .mockResolvedValueOnce({ outputPath: input.outputPath }); + + vi.spyOn(fs, 'readFileSync') + .mockReturnValueOnce(JSON.stringify(mockKeyPair)) + .mockReturnValueOnce(JSON.stringify(freezedMockCredential)); + + vi.spyOn(fs, 'readdirSync').mockImplementation(() => { + throw new Error(); + }); + + await expect(promptForInputs()).rejects.toThrowError('Output path is not valid'); + }); + }); + + describe('signCredentialWithKeyPair', () => { + beforeEach(() => { + vi.clearAllMocks(); + vi.resetAllMocks(); + vi.restoreAllMocks(); + + mockCredential = { ...freezedMockCredential }; + }); + + it('should successfully sign credential', async () => { + const result = await signCredentialWithKeyPair(mockCredential, mockKeyPair); + + expect(result).toMatchObject( + expect.objectContaining({ + ...mockCredential, + id: expect.stringContaining('urn:bnid:_:'), + proof: expect.objectContaining({ + type: expect.stringContaining('BbsBlsSignature2020'), + created: expect.stringContaining('Z'), + proofPurpose: 'assertionMethod', + verificationMethod: expect.stringContaining('did:web:trustvc.github.io:did:1'), + proofValue: expect.anything(), + }), + }), + ); + }); + + it('should throw error when signing fails', async () => { + // Using a key pair that is structurally different to ensure failure + const highlyInvalidKeyPair = { + ...mockKeyPair, + type: 'NonExistentKeyType', + privateKeyBase58: 'Invalid', + } as any; + + await expect( + signCredentialWithKeyPair(mockCredential, highlyInvalidKeyPair), + ).rejects.toThrowError(); + }); + }); + + describe('saveSignedCredential', () => { + beforeEach(() => { + vi.clearAllMocks(); + vi.resetAllMocks(); + }); + + it('should successfully save credential to specified path', () => { + const outputPath = '.'; + const signedCredential = { ...freezedMockCredential, id: 'test-id' }; // Add id for filename + + const writeFileSyncSpy = vi.spyOn(fs, 'writeFileSync'); + + saveSignedCredential(signedCredential, outputPath); + + expect(writeFileSyncSpy).toHaveBeenCalledWith( + `${outputPath}/signed_vc.json`, + JSON.stringify(signedCredential), + ); + }); + + it('should throw error if saving fails', async () => { + const outputPath = '.'; + const signedCredential = { ...mockCredential, id: 'test-id' }; + + vi.spyOn(fs, 'writeFileSync').mockImplementation(() => { + throw new Error('Save error'); + }); + + await expect(saveSignedCredential(signedCredential, outputPath)).rejects.toThrowError( + 'Unable to save signed credential to ./signed_vc.json', + ); + }); + }); +}); diff --git a/apps/w3c-cli/tests/commands/verify.test.ts b/apps/w3c-cli/tests/commands/verify.test.ts new file mode 100644 index 00000000..bf4e8fd5 --- /dev/null +++ b/apps/w3c-cli/tests/commands/verify.test.ts @@ -0,0 +1,154 @@ +import { isCredentialStatusStatusList } from '@trustvc/w3c-credential-status'; +import * as w3cVc from '@trustvc/w3c-vc'; +import { getDocumentLoader, verifyCredential, verifyCredentialStatus } from '@trustvc/w3c-vc'; +import chalk from 'chalk'; +import inquirer from 'inquirer'; +import { beforeEach, describe, expect, it, vi } from 'vitest'; +import * as verifyModule from '../../src/commands/verify'; +import * as utils from '../../src/utils'; +import { mockSignedCredential } from '../fixtures/mockCredential'; +import { mockWellKnown } from '../fixtures/mockDidWeb'; + +// Mock dependencies +vi.mock('inquirer'); +vi.mock('@trustvc/w3c-vc', async () => { + const original = await vi.importActual('@trustvc/w3c-vc'); + return { + ...original, + getDocumentLoader: vi.fn(), + verifyCredential: original.verifyCredential, + verifyCredentialStatus: vi.fn(), + }; +}); +vi.mock('@trustvc/w3c-credential-status', async () => { + const original = await vi.importActual( + '@trustvc/w3c-credential-status', + ); + return { + ...original, + isCredentialStatusStatusList: vi.fn(), + }; +}); +vi.mock('fs', async () => { + const originalFs = await vi.importActual('fs'); + return { + ...originalFs, + }; +}); +vi.mock('chalk', async () => { + const originalChalk = await vi.importActual('chalk'); + return { + ...originalChalk, + }; +}); +vi.mock('../../src/utils', () => ({ + readJsonFile: vi.fn(), +})); + +describe('verify', () => { + beforeEach(() => { + vi.clearAllMocks(); + vi.resetAllMocks(); + }); + + describe('promptForCredential', () => { + beforeEach(() => { + vi.clearAllMocks(); + vi.resetAllMocks(); + }); + + it('should return correct answers for valid credential input', async () => { + const input = { + credentialPath: './signed_vc.json', + }; + + (inquirer.prompt as any).mockResolvedValueOnce({ credentialPath: input.credentialPath }); + vi.spyOn(utils, 'readJsonFile').mockReturnValueOnce(mockSignedCredential); + + const answers = await verifyModule.promptForCredential(); + + expect(answers.credentialData).toStrictEqual(mockSignedCredential); + expect(utils.readJsonFile).toHaveBeenCalledWith(input.credentialPath, 'credential'); + }); + + it('should throw error for invalid credential file', async () => { + const input = { + credentialPath: './invalid-credential.json', + }; + + (inquirer.prompt as any).mockResolvedValueOnce({ credentialPath: input.credentialPath }); + vi.spyOn(utils, 'readJsonFile').mockReturnValueOnce(null); + + await expect(verifyModule.promptForCredential()).rejects.toThrowError( + 'Unable to read credential file', + ); + }); + }); + + describe('verifyCredentialData', () => { + beforeEach(() => { + vi.clearAllMocks(); + vi.resetAllMocks(); + }); + + it('should log successful verification when credential is valid', async () => { + const consoleLogSpy = vi.spyOn(console, 'log'); + const verifyResult = { verified: true }; + const verifyCredentialStatusResult = { purpose: 'revocation', status: 'active' }; + + const verifyCredentialSpy = vi.spyOn(w3cVc, 'verifyCredential'); + (getDocumentLoader as any).mockImplementationOnce(() => { + return getDocumentLoader({ + 'did:web:trustvc.github.io:did:1': mockWellKnown, + }); + }); + (isCredentialStatusStatusList as any).mockReturnValue(true); + (verifyCredentialStatus as any).mockResolvedValueOnce(verifyCredentialStatusResult); + + await verifyModule.verifyCredentialData(mockSignedCredential); + + expect(verifyCredentialSpy).toHaveBeenCalledWith(mockSignedCredential); + expect(isCredentialStatusStatusList).toHaveBeenCalled(); + expect(verifyCredentialStatus).toHaveBeenCalled(); + expect(consoleLogSpy).toHaveBeenNthCalledWith( + 1, + chalk.green(`Verification result: ${verifyResult.verified}`), + ); + expect(consoleLogSpy).toHaveBeenNthCalledWith( + 2, + expect.stringContaining('Credential status verification result'), + ); + }); + + it('should log error when credential verification fails', async () => { + const consoleErrorSpy = vi.spyOn(console, 'error'); + const verifyResult = { verified: false, error: 'Invalid signature' }; + + (verifyCredential as any).mockResolvedValueOnce(verifyResult); + (isCredentialStatusStatusList as any).mockReturnValue(false); + + await verifyModule.verifyCredentialData(mockSignedCredential); + + expect(verifyCredential).toHaveBeenCalledWith(mockSignedCredential); + expect(consoleErrorSpy).toHaveBeenCalledWith( + chalk.red(`Verification result: ${verifyResult.verified}`), + ); + expect(consoleErrorSpy).toHaveBeenCalledWith(chalk.red(`Error: ${verifyResult.error}`)); + }); + + it('should throw error when credential status verification fails', async () => { + const verifyResult = { verified: true }; + const statusError = 'Status list verification failed'; + + (verifyCredential as any).mockResolvedValueOnce(verifyResult); + (isCredentialStatusStatusList as any).mockReturnValue(true); + (verifyCredentialStatus as any).mockResolvedValueOnce({ + error: statusError, + }); + + await expect(verifyModule.verifyCredentialData(mockSignedCredential)).rejects.toThrowError( + statusError, + ); + }); + }); +}); diff --git a/apps/w3c-cli/tests/fixtures/mockCredential.ts b/apps/w3c-cli/tests/fixtures/mockCredential.ts new file mode 100644 index 00000000..34ed52c1 --- /dev/null +++ b/apps/w3c-cli/tests/fixtures/mockCredential.ts @@ -0,0 +1,39 @@ +import { RawVerifiableCredential, SignedVerifiableCredential } from '@trustvc/w3c-vc'; + +export const mockCredential = Object.freeze({ + '@context': [ + 'https://www.w3.org/2018/credentials/v1', + 'https://w3c-ccg.github.io/citizenship-vocab/contexts/citizenship-v1.jsonld', + 'https://w3id.org/security/bbs/v1', + 'https://w3id.org/vc/status-list/2021/v1', + ], + credentialStatus: { + id: 'https://trustvc.github.io/did/credentials/statuslist/1#1', + type: 'StatusList2021Entry', + statusPurpose: 'revocation', + statusListIndex: '10', + statusListCredential: 'https://trustvc.github.io/did/credentials/statuslist/1', + }, + credentialSubject: { + name: 'TrustVC', + birthDate: '2024-04-01T12:19:52Z', + type: ['PermanentResident', 'Person'], + }, + expirationDate: '2029-12-03T12:19:52Z', + issuer: 'did:web:trustvc.github.io:did:1', + type: ['VerifiableCredential'], + issuanceDate: '2024-04-01T12:19:52Z', +} as RawVerifiableCredential); + +export const mockSignedCredential = Object.freeze({ + ...mockCredential, + id: 'urn:uuid:0192b20e-0ba5-76d8-b682-7538c86a4d69', + proof: { + type: 'BbsBlsSignature2020', + created: '2024-11-11T00:43:34Z', + proofPurpose: 'assertionMethod', + proofValue: + 'hPm0Ef9HdptikoYojeF+X3xPyznAfPUROX5cBTzeINsvZJB0utLFfSMPrkgJCh9mYUHlKfzccE4m7waZyoLEkBLFiK2g54Q2i+CdtYBgDdkUDsoULSBMcH1MwGHwdjfXpldFNFrHFx/IAvLVniyeMQ==', + verificationMethod: 'did:web:trustvc.github.io:did:1#keys-1', + }, +} as SignedVerifiableCredential); diff --git a/apps/w3c-cli/tests/fixtures/mockDidWeb.ts b/apps/w3c-cli/tests/fixtures/mockDidWeb.ts new file mode 100644 index 00000000..d3c2d5a7 --- /dev/null +++ b/apps/w3c-cli/tests/fixtures/mockDidWeb.ts @@ -0,0 +1,29 @@ +import { DidWellKnownDocument, PrivateKeyPair, VerificationType } from '@trustvc/w3c-issuer'; + +export const mockKeyPair = Object.freeze({ + id: 'did:web:trustvc.github.io:did:1#keys-1', + type: VerificationType.Bls12381G2Key2020, + controller: 'did:web:trustvc.github.io:did:1', + seedBase58: 'GWP69tmSWJjqC1RoJ27FehcVqkVyeYAz6h5ABwoNSNdS', + privateKeyBase58: '4LDU56PUhA9ZEutnR1qCWQnUhtLtpLu2EHSq4h1o7vtF', + publicKeyBase58: + 'oRfEeWFresvhRtXCkihZbxyoi2JER7gHTJ5psXhHsdCoU1MttRMi3Yp9b9fpjmKh7bMgfWKLESiK2YovRd8KGzJsGuamoAXfqDDVhckxuc9nmsJ84skCSTijKeU4pfAcxeJ', +} as PrivateKeyPair); + +export const mockWellKnown = Object.freeze({ + id: 'did:web:trustvc.github.io:did:1', + verificationMethod: [ + { + type: 'Bls12381G2Key2020', + id: 'did:web:trustvc.github.io:did:1#keys-1', + controller: 'did:web:trustvc.github.io:did:1', + publicKeyBase58: + 'oRfEeWFresvhRtXCkihZbxyoi2JER7gHTJ5psXhHsdCoU1MttRMi3Yp9b9fpjmKh7bMgfWKLESiK2YovRd8KGzJsGuamoAXfqDDVhckxuc9nmsJ84skCSTijKeU4pfAcxeJ', + }, + ], + '@context': ['https://www.w3.org/ns/did/v1', 'https://w3id.org/security/suites/bls12381-2020/v1'], + authentication: ['did:web:trustvc.github.io:did:1#keys-1'], + assertionMethod: ['did:web:trustvc.github.io:did:1#keys-1'], + capabilityInvocation: ['did:web:trustvc.github.io:did:1#keys-1'], + capabilityDelegation: ['did:web:trustvc.github.io:did:1#keys-1'], +} as DidWellKnownDocument); diff --git a/apps/w3c-cli/tests/main.test.ts b/apps/w3c-cli/tests/main.test.ts new file mode 100644 index 00000000..bf61fbe7 --- /dev/null +++ b/apps/w3c-cli/tests/main.test.ts @@ -0,0 +1,451 @@ +import { isCredentialStatusStatusList } from '@trustvc/w3c-credential-status'; +import * as w3cIssuer from '@trustvc/w3c-issuer'; +import * as w3cVc from '@trustvc/w3c-vc'; +import { getDocumentLoader, verifyCredentialStatus } from '@trustvc/w3c-vc'; +import chalk from 'chalk'; +import inquirer from 'inquirer'; +import { beforeEach, describe, it, MockedFunction, vi } from 'vitest'; +import { handler as didHandler } from '../src/commands/did'; +import { handler as signHandler } from '../src/commands/sign'; +import * as verifyModule from '../src/commands/verify'; +import { handler as verifyHandler } from '../src/commands/verify'; +import { IssueDidInput } from '../src/types'; +import * as utils from '../src/utils'; +import { mockCredential, mockSignedCredential } from './fixtures/mockCredential'; +import { mockKeyPair, mockWellKnown } from './fixtures/mockDidWeb'; + +// Mock dependencies with Vitest +vi.mock('inquirer'); +vi.mock('../src/utils'); +vi.mock('@trustvc/w3c-vc', async () => { + const original = await vi.importActual('@trustvc/w3c-vc'); + return { + ...original, + getDocumentLoader: vi.fn(), + verifyCredential: original.verifyCredential, + verifyCredentialStatus: vi.fn(), + }; +}); +vi.mock('@trustvc/w3c-credential-status'); +vi.mock('chalk', async () => { + const originalChalk = await vi.importActual('chalk'); + return { + ...originalChalk, + }; +}); +vi.mock('../src/commands/did', async () => { + const original = + await vi.importActual('../src/commands/did'); + return { + ...original, // Use actual implementations by default + promptQuestions: original.promptQuestions, + getIssuedDid: original.getIssuedDid, + saveIssuedDid: original.saveIssuedDid, + }; +}); +vi.mock('@trustvc/w3c-issuer', async () => { + const original = + await vi.importActual('@trustvc/w3c-issuer'); + return { + ...original, + issueDID: original.issueDID, + queryDidDocument: original.queryDidDocument, + }; +}); + +describe('w3c-cli', () => { + beforeEach(() => { + vi.clearAllMocks(); + vi.resetAllMocks(); + }); + + describe('w3c-cli sign command', () => { + beforeEach(() => { + vi.clearAllMocks(); + vi.resetAllMocks(); + }); + + it('should successfully sign a credential and save it', async ({ expect }) => { + (inquirer.prompt as unknown as MockedFunction) + .mockResolvedValueOnce({ keyPairPath: './didKeyPairs.json' } as any) + .mockResolvedValueOnce({ credentialPath: './vc.json' } as any) + .mockResolvedValueOnce({ outputPath: './output' } as any); + + (utils.readJsonFile as MockedFunction) + .mockReturnValueOnce(mockKeyPair) + .mockReturnValueOnce({ ...mockCredential }); + (utils.isDirectoryValid as MockedFunction).mockReturnValue( + true, + ); + (utils.writeFile as MockedFunction).mockImplementation(() => { + /* do nothing */ + }); + + const signCredentialSpy = vi.spyOn(w3cVc, 'signCredential'); + + const consoleLogSpy = vi.spyOn(console, 'log'); + const consoleErrorSpy = vi.spyOn(console, 'error'); + + await signHandler(); + + expect(inquirer.prompt).toHaveBeenCalledTimes(3); + expect(utils.readJsonFile).toHaveBeenCalledWith('./didKeyPairs.json', 'key pair'); + expect(utils.readJsonFile).toHaveBeenCalledWith('./vc.json', 'credential'); + expect(utils.isDirectoryValid).toHaveBeenCalledWith('./output'); + expect(signCredentialSpy).toHaveBeenCalledWith( + expect.objectContaining(mockCredential), + mockKeyPair, + ); + expect(utils.writeFile).toHaveBeenCalledWith( + './output/signed_vc.json', + expect.objectContaining({ + ...mockSignedCredential, + id: expect.any(String), + proof: expect.objectContaining({ + ...mockSignedCredential.proof, + created: expect.any(String), + proofValue: expect.any(String), + }), + }), + ); + expect(consoleLogSpy).toHaveBeenCalledWith( + chalk.green('Signed credential saved successfully to ./output/signed_vc.json'), + ); + expect(consoleErrorSpy).not.toHaveBeenCalled(); + }); + + it('should log an error when key pair file is not found/invalid', async ({ expect }) => { + (inquirer.prompt as unknown as MockedFunction) + .mockResolvedValueOnce({ keyPairPath: './invalidKeyPair.json' } as any) + .mockResolvedValueOnce({ credentialPath: './vc.json' } as any) + .mockResolvedValueOnce({ outputPath: './output' } as any); + + (utils.readJsonFile as MockedFunction).mockImplementation( + (filePath) => { + if (filePath.includes('invalidKeyPair.json')) { + throw new Error('Key pair file not found or invalid.'); + } + if (filePath.includes('vc.json')) { + return mockCredential; + } + return {}; // Default return for any other path + }, + ); + + const consoleErrorSpy = vi.spyOn(console, 'error'); + const consoleLogSpy = vi.spyOn(console, 'log'); + + await signHandler(); + + expect(inquirer.prompt).toHaveBeenCalledTimes(1); + expect(utils.readJsonFile).toHaveBeenCalledWith('./invalidKeyPair.json', 'key pair'); + expect(consoleErrorSpy).toHaveBeenCalledWith( + chalk.red('Error: Key pair file not found or invalid.'), + ); + expect(consoleLogSpy).not.toHaveBeenCalled(); + }); + + it('should log an error when credential file is not found/invalid', async ({ expect }) => { + (inquirer.prompt as unknown as MockedFunction) + .mockResolvedValueOnce({ keyPairPath: './didKeyPairs.json' } as any) + .mockResolvedValueOnce({ credentialPath: './invalidVc.json' } as any) + .mockResolvedValueOnce({ outputPath: './output' } as any); + + (utils.readJsonFile as MockedFunction).mockImplementation( + (filePath) => { + if (filePath.includes('didKeyPairs.json')) { + return mockKeyPair; + } + if (filePath.includes('invalidVc.json')) { + throw new Error('Credential file not found or invalid.'); + } + return {}; // Default return for any other path + }, + ); + + const consoleErrorSpy = vi.spyOn(console, 'error'); + const consoleLogSpy = vi.spyOn(console, 'log'); + + await signHandler(); + + expect(inquirer.prompt).toHaveBeenCalledTimes(2); + expect(utils.readJsonFile).toHaveBeenCalledWith('./didKeyPairs.json', 'key pair'); + expect(utils.readJsonFile).toHaveBeenCalledWith('./invalidVc.json', 'credential'); + expect(consoleErrorSpy).toHaveBeenCalledWith( + chalk.red('Error: Credential file not found or invalid.'), + ); + expect(consoleLogSpy).not.toHaveBeenCalled(); + }); + + it('should log an error when output path is invalid', async ({ expect }) => { + (inquirer.prompt as unknown as MockedFunction) + .mockResolvedValueOnce({ keyPairPath: './didKeyPairs.json' } as any) + .mockResolvedValueOnce({ credentialPath: './vc.json' } as any) + .mockResolvedValueOnce({ outputPath: './invalidOutput' } as any); + + (utils.readJsonFile as MockedFunction) + .mockReturnValueOnce(mockKeyPair) + .mockReturnValueOnce(mockCredential); + (utils.isDirectoryValid as MockedFunction).mockReturnValue( + false, + ); + + const consoleErrorSpy = vi.spyOn(console, 'error'); + const consoleLogSpy = vi.spyOn(console, 'log'); + + await signHandler(); + + expect(inquirer.prompt).toHaveBeenCalledTimes(3); + expect(utils.readJsonFile).toHaveBeenCalledWith('./didKeyPairs.json', 'key pair'); + expect(utils.readJsonFile).toHaveBeenCalledWith('./vc.json', 'credential'); + expect(utils.isDirectoryValid).toHaveBeenCalledWith('./invalidOutput'); + expect(consoleErrorSpy).toHaveBeenCalledWith(chalk.red('Error: Output path is not valid')); + expect(consoleLogSpy).not.toHaveBeenCalled(); + }); + + it('should log an error during the signing process', async ({ expect }) => { + (inquirer.prompt as unknown as MockedFunction) + .mockResolvedValueOnce({ keyPairPath: './didKeyPairs.json' } as any) + .mockResolvedValueOnce({ credentialPath: './vc.json' } as any) + .mockResolvedValueOnce({ outputPath: './output' } as any); + + (utils.readJsonFile as MockedFunction) + .mockReturnValueOnce(mockKeyPair) + .mockReturnValueOnce(mockCredential); + (utils.isDirectoryValid as MockedFunction).mockReturnValue( + true, + ); + (w3cVc.signCredential as MockedFunction).mockRejectedValue( + new Error('Signing failed.'), + ); + + const consoleErrorSpy = vi.spyOn(console, 'error'); + const consoleLogSpy = vi.spyOn(console, 'log'); + + await signHandler(); + + expect(w3cVc.signCredential).toHaveBeenCalledWith(mockCredential, mockKeyPair); + expect(consoleErrorSpy).toHaveBeenCalledWith(chalk.red('Error: Signing failed.')); + expect(consoleLogSpy).not.toHaveBeenCalled(); + expect(utils.writeFile).not.toHaveBeenCalled(); + }); + + it('should log an error during file saving', async ({ expect }) => { + (inquirer.prompt as unknown as MockedFunction) + .mockResolvedValueOnce({ keyPairPath: './didKeyPairs.json' } as any) + .mockResolvedValueOnce({ credentialPath: './vc.json' } as any) + .mockResolvedValueOnce({ outputPath: './output' } as any); + + (utils.readJsonFile as MockedFunction) + .mockReturnValueOnce(mockKeyPair) + .mockReturnValueOnce(mockCredential); + (utils.isDirectoryValid as MockedFunction).mockReturnValue( + true, + ); + (w3cVc.signCredential as MockedFunction).mockResolvedValue({ + signed: mockSignedCredential, + } as any); + (utils.writeFile as MockedFunction).mockImplementation(() => { + throw new Error('File saving failed.'); + }); + + const consoleErrorSpy = vi.spyOn(console, 'error'); + const consoleLogSpy = vi.spyOn(console, 'log'); + + await signHandler(); + + expect(utils.writeFile).toHaveBeenCalledWith('./output/signed_vc.json', mockSignedCredential); + expect(consoleErrorSpy).toHaveBeenCalledWith( + chalk.red('Error: Unable to save signed credential to ./output/signed_vc.json'), + ); + expect(consoleLogSpy).not.toHaveBeenCalled(); + }); + }); + + describe('w3c-cli did command', () => { + let issueDIDSpy: MockedFunction; + let writeFileSpy: MockedFunction; + let consoleErrorSpy: MockedFunction; + + beforeEach(() => { + vi.clearAllMocks(); + vi.resetAllMocks(); + vi.restoreAllMocks(); + + issueDIDSpy = vi.spyOn(w3cIssuer, 'issueDID') as MockedFunction; + writeFileSpy = vi.spyOn(utils, 'writeFile') as MockedFunction; + consoleErrorSpy = vi.spyOn(console, 'error') as MockedFunction; + }); + + it('should generate a new DID token file', async ({ expect }) => { + const input: IssueDidInput = { + keyPairPath: './keypair.json', + domainName: 'https://example.com', + outputPath: '.', + }; + (inquirer.prompt as any).mockResolvedValue(input); + (utils.readJsonFile as MockedFunction).mockReturnValueOnce({ + ...mockKeyPair, + }); + (utils.isDirectoryValid as MockedFunction).mockReturnValue( + true, + ); + + await didHandler(); + + expect(issueDIDSpy).toHaveBeenCalledWith( + expect.objectContaining({ ...mockKeyPair, domain: input.domainName }), + ); + expect(writeFileSpy).toHaveBeenNthCalledWith(1, './wellknown.json', { + '@context': [ + 'https://www.w3.org/ns/did/v1', + 'https://w3id.org/security/suites/bls12381-2020/v1', + ], + assertionMethod: ['did:web:example.com#keys-1'], + authentication: ['did:web:example.com#keys-1'], + capabilityDelegation: ['did:web:example.com#keys-1'], + capabilityInvocation: ['did:web:example.com#keys-1'], + id: 'did:web:example.com', + verificationMethod: [ + { + controller: 'did:web:example.com', + id: 'did:web:example.com#keys-1', + publicKeyBase58: + 'oRfEeWFresvhRtXCkihZbxyoi2JER7gHTJ5psXhHsdCoU1MttRMi3Yp9b9fpjmKh7bMgfWKLESiK2YovRd8KGzJsGuamoAXfqDDVhckxuc9nmsJ84skCSTijKeU4pfAcxeJ', + type: 'Bls12381G2Key2020', + }, + ], + }); + expect(writeFileSpy).toHaveBeenNthCalledWith(2, './didKeyPairs.json', { + controller: 'did:web:example.com', + id: 'did:web:example.com#keys-1', + privateKeyBase58: '4LDU56PUhA9ZEutnR1qCWQnUhtLtpLu2EHSq4h1o7vtF', + publicKeyBase58: + 'oRfEeWFresvhRtXCkihZbxyoi2JER7gHTJ5psXhHsdCoU1MttRMi3Yp9b9fpjmKh7bMgfWKLESiK2YovRd8KGzJsGuamoAXfqDDVhckxuc9nmsJ84skCSTijKeU4pfAcxeJ', + seedBase58: 'GWP69tmSWJjqC1RoJ27FehcVqkVyeYAz6h5ABwoNSNdS', + type: 'Bls12381G2Key2020', + }); + }); + + it('should early exit if did already exists', async ({ expect }) => { + const input: IssueDidInput = { + keyPairPath: './keypair.json', + domainName: 'https://trustvc.github.io/did/1', + outputPath: '.', + }; + (inquirer.prompt as any).mockResolvedValue(input); + (utils.readJsonFile as MockedFunction).mockReturnValueOnce({ + ...mockKeyPair, + }); + (utils.isDirectoryValid as MockedFunction).mockReturnValue( + true, + ); + + await didHandler(); + + expect(issueDIDSpy).toHaveBeenCalledWith( + expect.objectContaining({ + ...mockKeyPair, + domain: input.domainName, + }), + ); + expect(writeFileSpy).not.toHaveBeenCalled(); + expect(consoleErrorSpy).toHaveBeenCalledWith( + chalk.red('Error: Error generating DID token: KeyPair already exists in Did Document'), + ); + }); + + it('should early exit if getIssuedDid throws error', async ({ expect }) => { + const input: IssueDidInput = { + keyPairPath: './keypair.json', + domainName: 'https://example.com', + outputPath: '.', + }; + (inquirer.prompt as any).mockResolvedValue(input); + (utils.readJsonFile as MockedFunction).mockReturnValueOnce({ + ...mockKeyPair, + }); + (utils.isDirectoryValid as MockedFunction).mockReturnValue( + true, + ); + + issueDIDSpy.mockRejectedValue(new Error('')); + + await didHandler(); + + expect(issueDIDSpy).toHaveBeenCalledWith({ + ...mockKeyPair, + domain: input.domainName, + }); + expect(writeFileSpy).not.toHaveBeenCalled(); + expect(consoleErrorSpy).toHaveBeenCalledWith(chalk.red('Error: Error generating DID token')); + }); + }); + + describe('w3c-cli verify command', () => { + beforeEach(() => { + vi.clearAllMocks(); + vi.resetAllMocks(); + }); + + it('should successfully verify credential when called with valid input', async ({ expect }) => { + const input = { + credentialPath: './signed_vc.json', + }; + + (inquirer.prompt as any).mockResolvedValueOnce({ credentialPath: input.credentialPath }); + vi.spyOn(utils, 'readJsonFile').mockReturnValueOnce(mockSignedCredential); + const consoleLogSpy = vi.spyOn(console, 'log'); + const verifyResult = { verified: true }; + + (getDocumentLoader as any).mockImplementationOnce(() => { + return getDocumentLoader({ + 'did:web:trustvc.github.io:did:1': mockWellKnown, + }); + }); + (isCredentialStatusStatusList as any).mockReturnValue(true); + (verifyCredentialStatus as any).mockResolvedValueOnce({ + purpose: 'revocation', + status: 'active', + }); + const verifyCredentialSpy = vi.spyOn(w3cVc, 'verifyCredential'); + + // Call the handler function + await verifyHandler(); + + expect(utils.readJsonFile).toHaveBeenCalledWith(input.credentialPath, 'credential'); + expect(verifyCredentialSpy).toHaveBeenCalledWith(mockSignedCredential); + expect(isCredentialStatusStatusList).toHaveBeenCalled(); + expect(verifyCredentialStatus).toHaveBeenCalled(); + expect(consoleLogSpy).toHaveBeenNthCalledWith( + 1, + chalk.green(`Verification result: ${verifyResult.verified}`), + ); + expect(consoleLogSpy).toHaveBeenNthCalledWith( + 2, + expect.stringContaining('Credential status verification result'), + ); + }); + + it('should handle errors gracefully', async ({ expect }) => { + const consoleErrorSpy = vi.spyOn(console, 'error'); + + // Mock inquirer to simulate the actual error that occurs + (inquirer.prompt as any).mockRejectedValueOnce(new Error('Verification failed')); + + await verifyHandler(); + + expect(consoleErrorSpy).toHaveBeenCalledWith(expect.stringMatching(/Error:.*/)); + }); + + it('should exit early if no answers are returned from prompt', async ({ expect }) => { + // Mock directly - this approach is more reliable + vi.spyOn(verifyModule, 'promptForCredential').mockResolvedValueOnce(undefined); + const verifySpy = vi.spyOn(verifyModule, 'verifyCredentialData'); + + await verifyHandler(); + + expect(verifySpy).not.toHaveBeenCalled(); + }); + }); +}); diff --git a/netlify.toml b/netlify.toml new file mode 100644 index 00000000..17fa921d --- /dev/null +++ b/netlify.toml @@ -0,0 +1,10 @@ +[[headers]] + for = "/*" + [headers.values] + Access-Control-Allow-Origin = "*" + +[[redirects]] + from = "https://trustvc.io/context/*" + to = "https://www.trustvc.io/context/:splat" + status = 200 + force = true diff --git a/package-lock.json b/package-lock.json index f8f80f6c..e781c678 100644 --- a/package-lock.json +++ b/package-lock.json @@ -65,6 +65,7 @@ "@types/jest": "^29.5.12", "@types/lodash": "^4.17.9", "@types/node": "^18.19.67", + "@types/uuid": "^10.0.0", "@typescript-eslint/eslint-plugin": "^7.17.0", "@typescript-eslint/parser": "^7.17.0", "@vitest/coverage-v8": "^1.6.0", @@ -115,14 +116,14 @@ }, "apps/w3c-cli": { "name": "@trustvc/w3c-cli", - "version": "1.0.1", + "version": "1.2.17", "license": "Apache-2.0", "dependencies": { "@inquirer/prompts": "^5.3.8", - "@trustvc/w3c-context": "^1.0.0", - "@trustvc/w3c-credential-status": "^1.0.0", - "@trustvc/w3c-issuer": "^1.0.0", - "@trustvc/w3c-vc": "^1.0.1", + "@trustvc/w3c-context": "^1.2.12", + "@trustvc/w3c-credential-status": "^1.2.12", + "@trustvc/w3c-issuer": "^1.2.3", + "@trustvc/w3c-vc": "^1.2.16", "@types/yargs": "^17.0.32", "chalk": "^4.1.2", "inquirer": "^10.0.1", @@ -32586,13 +32587,13 @@ }, "packages/w3c": { "name": "@trustvc/w3c", - "version": "1.0.1", + "version": "1.2.16", "license": "Apache-2.0", "dependencies": { - "@trustvc/w3c-context": "^1.0.0", - "@trustvc/w3c-credential-status": "^1.0.0", - "@trustvc/w3c-issuer": "^1.0.0", - "@trustvc/w3c-vc": "^1.0.1" + "@trustvc/w3c-context": "^1.2.12", + "@trustvc/w3c-credential-status": "^1.2.12", + "@trustvc/w3c-issuer": "^1.2.3", + "@trustvc/w3c-vc": "^1.2.16" }, "engines": { "node": ">=18.x" @@ -32600,10 +32601,11 @@ }, "packages/w3c-context": { "name": "@trustvc/w3c-context", - "version": "1.0.0", + "version": "1.2.12", "license": "Apache-2.0", "dependencies": { - "did-resolver": "^4.1.0" + "did-resolver": "^4.1.0", + "jsonld-signatures": "^7.0.0" }, "engines": { "node": ">=18.x" @@ -32611,11 +32613,11 @@ }, "packages/w3c-credential-status": { "name": "@trustvc/w3c-credential-status", - "version": "1.0.0", + "version": "1.2.12", "license": "Apache-2.0", "dependencies": { - "@trustvc/w3c-context": "^1.0.0", - "@trustvc/w3c-issuer": "^1.0.0", + "@trustvc/w3c-context": "^1.2.12", + "@trustvc/w3c-issuer": "^1.2.3", "base64url-universal": "^2.0.0", "pako": "^2.1.0" }, @@ -32625,7 +32627,7 @@ }, "packages/w3c-issuer": { "name": "@trustvc/w3c-issuer", - "version": "1.0.0", + "version": "1.2.3", "license": "Apache-2.0", "dependencies": { "@mattrglobal/bls12381-key-pair": "^1.2.1", @@ -32640,12 +32642,12 @@ }, "packages/w3c-vc": { "name": "@trustvc/w3c-vc", - "version": "1.0.1", + "version": "1.2.16", "license": "Apache-2.0", "dependencies": { "@mattrglobal/jsonld-signatures-bbs": "^1.2.0", - "@trustvc/w3c-credential-status": "^1.0.0", - "@trustvc/w3c-issuer": "^1.0.0", + "@trustvc/w3c-credential-status": "^1.2.12", + "@trustvc/w3c-issuer": "^1.2.3", "did-resolver": "^4.1.0", "jsonld": "^6.0.0", "jsonld-signatures": "7.0.0", diff --git a/package.json b/package.json index 7b1639dc..ac5d3e51 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,9 @@ "affected": "nx affected", "affected:lint": "nx affected:lint", "test": "nx run-many --target=test", + "test:skip-cache": "nx run-many --target=test --skip-nx-cache", "lint": "nx run-many --target=lint", + "lint:fix": "nx run-many --target=lint --fix", "build": "nx run-many --target=build", "copy-files": "bash ./scripts/copy-files.sh", "clean": "nx clear-cache && nx run-many --target=clean", @@ -52,6 +54,7 @@ "@types/jest": "^29.5.12", "@types/lodash": "^4.17.9", "@types/node": "^18.19.67", + "@types/uuid": "^10.0.0", "@typescript-eslint/eslint-plugin": "^7.17.0", "@typescript-eslint/parser": "^7.17.0", "@vitest/coverage-v8": "^1.6.0", diff --git a/packages/w3c-context/CHANGELOG.md b/packages/w3c-context/CHANGELOG.md index b020b39d..0fd9fa6f 100644 --- a/packages/w3c-context/CHANGELOG.md +++ b/packages/w3c-context/CHANGELOG.md @@ -1,16 +1,79 @@ -## [1.2.3-alpha.2](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-context@1.2.3-alpha.1...@trustvc/w3c-context@1.2.3-alpha.2) (2025-04-09) +## [1.2.13](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-context@1.2.12...@trustvc/w3c-context@1.2.13) (2025-06-13) ### Bug Fixes -* add cache for jws 2020 v1 ([#48](https://github.com/TrustVC/w3c/issues/48)) ([4a9f52a](https://github.com/TrustVC/w3c/commit/4a9f52a823e5836454c65239916fa5807c9d0be1)) +* expired and redacted doc checks ([#64](https://github.com/TrustVC/w3c/issues/64)) ([4d0a65a](https://github.com/TrustVC/w3c/commit/4d0a65ad467e07bc0f837368f6ff93f84abfb0a8)) -## [1.2.3-alpha.1](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-context@1.2.2...@trustvc/w3c-context@1.2.3-alpha.1) (2025-04-09) +## [1.2.12](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-context@1.2.11...@trustvc/w3c-context@1.2.12) (2025-05-30) ### Bug Fixes -* update fetchCredentialStatusVC to use documentLoader ([#46](https://github.com/TrustVC/w3c/issues/46)) ([7fe49f8](https://github.com/TrustVC/w3c/commit/7fe49f8e5a01cf36f4fdd87bccd72f87554a9072)) +* type errors ([#62](https://github.com/TrustVC/w3c/issues/62)) ([e4cf81f](https://github.com/TrustVC/w3c/commit/e4cf81f4cab187be464f92503bf0f0c39aef61d7)) + +## [1.2.11](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-context@1.2.10...@trustvc/w3c-context@1.2.11) (2025-05-21) + + +### Bug Fixes + +* coo context ([#59](https://github.com/TrustVC/w3c/issues/59)) ([b802c6f](https://github.com/TrustVC/w3c/commit/b802c6f8605387024d5a50d81e4edfa3da709ba7)) + +## [1.2.10](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-context@1.2.9...@trustvc/w3c-context@1.2.10) (2025-05-20) + + +### Bug Fixes + +* add template context ([#58](https://github.com/TrustVC/w3c/issues/58)) ([8a467b7](https://github.com/TrustVC/w3c/commit/8a467b738bebe935f00af525684e84bfd01fe6e9)) + +## [1.2.9](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-context@1.2.8...@trustvc/w3c-context@1.2.9) (2025-05-16) + + +### Bug Fixes + +* cli error messages ([#54](https://github.com/TrustVC/w3c/issues/54)) ([3825ce9](https://github.com/TrustVC/w3c/commit/3825ce9598479f52a75b2a8dbd38efc97730950a)) + +## [1.2.8](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-context@1.2.7...@trustvc/w3c-context@1.2.8) (2025-05-14) + + +### Bug Fixes + +* add qrcode context ([#55](https://github.com/TrustVC/w3c/issues/55)) ([19cd0df](https://github.com/TrustVC/w3c/commit/19cd0dfd20e848f744e1a5d6255557bde101d998)) + +## [1.2.7](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-context@1.2.6...@trustvc/w3c-context@1.2.7) (2025-04-24) + + +### Bug Fixes + +* update promissory note context ([#53](https://github.com/TrustVC/w3c/issues/53)) ([e032f45](https://github.com/TrustVC/w3c/commit/e032f4582da0983d2ca5648d7c55fac6bc97c1f6)) + +## [1.2.6](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-context@1.2.5...@trustvc/w3c-context@1.2.6) (2025-04-23) + + +### Bug Fixes + +* add promissory note context for w3c ([#52](https://github.com/TrustVC/w3c/issues/52)) ([54b866a](https://github.com/TrustVC/w3c/commit/54b866a66ff1db2466628fb32a1bb4820d71b7d1)) + +## [1.2.5](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-context@1.2.4...@trustvc/w3c-context@1.2.5) (2025-04-22) + + +### Bug Fixes + +* clean up resolver ([#51](https://github.com/TrustVC/w3c/issues/51)) ([936b5ec](https://github.com/TrustVC/w3c/commit/936b5ec23a372ae441bde9cd99701cbdd2408465)) + +## [1.2.4](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-context@1.2.3...@trustvc/w3c-context@1.2.4) (2025-04-10) + + +### Bug Fixes + +* add bls to context cache ([#50](https://github.com/TrustVC/w3c/issues/50)) ([a1988b0](https://github.com/TrustVC/w3c/commit/a1988b0ef2d82c95c3e285c93eedd61b050e4fd9)) + +## [1.2.3](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-context@1.2.2...@trustvc/w3c-context@1.2.3) (2025-04-09) + + +### Bug Fixes + +* update fetchCredentialStatusVC to use documentLoader and add cache for jws 2020 v1 ([#49](https://github.com/TrustVC/w3c/issues/49)) ([2c50901](https://github.com/TrustVC/w3c/commit/2c50901035aac696f75ef386bd8beca367f02db7)) ## [1.2.2](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-context@1.2.1...@trustvc/w3c-context@1.2.2) (2025-04-07) diff --git a/packages/w3c-context/README.md b/packages/w3c-context/README.md index 4fd04065..b8ca512b 100644 --- a/packages/w3c-context/README.md +++ b/packages/w3c-context/README.md @@ -1,9 +1,177 @@ # TrustVC W3C Context -A package to cache the commonly served JSON context schema in the `@context` within VCs. + +A comprehensive package that caches commonly used JSON-LD context schemas for W3C Verifiable Credentials and Data Integrity proofs. This package provides a document loader that resolves context URLs locally, improving performance and reliability for verifiable credential operations. + +## Features + +- **Local Context Caching**: Pre-cached JSON-LD contexts for faster resolution +- **W3C Standards Support**: Full support for W3C Verifiable Credentials and Data Integrity specifications +- **Cryptosuite Support**: Includes contexts for multiple cryptographic suites: + - BBS+ signatures (bbs-v1) + - JWS 2020 (jws-2020) + - BLS12-381 keys +- **DID Resolution**: Built-in support for DID document resolution +- **Custom Context Support**: Ability to add additional contexts at runtime +- **TypeScript Support**: Full TypeScript definitions included ## Installation -To install the package, use: ```sh npm install @trustvc/w3c-context ``` + +## Usage + +### Basic Document Loader + +```typescript +import { getDocumentLoader } from '@trustvc/w3c-context'; + +// Get a document loader with all cached contexts +const documentLoader = await getDocumentLoader(); + +// Use with jsonld-signatures or other JSON-LD libraries +const result = await documentLoader('https://w3id.org/security/data-integrity/v2'); +``` + +### With Additional Contexts + +```typescript +import { getDocumentLoader } from '@trustvc/w3c-context'; + +// Add custom contexts +const additionalContexts = { + 'https://example.com/my-context': { + "@context": { + "MyProperty": "https://example.com/vocab#MyProperty" + } + } +}; + +const documentLoader = await getDocumentLoader(additionalContexts); +``` + +### Available Context URLs + +The package includes the following pre-cached contexts: + +#### Core W3C Contexts +- `https://w3id.org/security/data-integrity/v2` - Data Integrity v2 +- `https://www.w3.org/ns/did/v1` - DID Core v1 +- `https://www.w3.org/2018/credentials/v1` - Verifiable Credentials v1 +- `https://www.w3.org/ns/credentials/v2` - Verifiable Credentials v2 +- `https://w3id.org/vc/status-list/2021/v1` - Status List 2021 v1 + +#### Cryptographic Suite Contexts +- `https://w3id.org/security/bbs/v1` - BBS+ v1 +- `https://w3id.org/security/suites/bls12381-2020/v1` - BLS12-381 2020 +- `https://w3id.org/security/suites/jws-2020/v1` - JWS 2020 + +#### TrustVC Business Contexts +- `https://trustvc.io/context/transferable-records-context.json` - Transferable Records +- `https://trustvc.io/context/render-method-context.json` - Render Methods +- `https://trustvc.io/context/attachments-context.json` - Attachments +- `https://trustvc.io/context/qrcode-context.json` - QR Code +- `https://trustvc.io/context/bill-of-lading.json` - Bill of Lading +- `https://trustvc.io/context/bill-of-lading-carrier.json` - Bill of Lading Carrier +- `https://trustvc.io/context/coo.json` - Certificate of Origin +- `https://trustvc.io/context/invoice.json` - Invoice +- `https://trustvc.io/context/promissory-note.json` - Promissory Note +- `https://trustvc.io/context/warehouse-receipt.json` - Warehouse Receipt + +### Context Constants + +You can import URL constants for type safety: + +```typescript +import { + DATA_INTEGRITY_V2_URL, + MULTIKEY_V1_URL, + VC_V1_URL +} from '@trustvc/w3c-context'; + +console.log(DATA_INTEGRITY_V2_URL); // https://w3id.org/security/data-integrity/v2 +console.log(MULTIKEY_V1_URL); // https://w3id.org/security/multikey/v1 +``` + +### Using Modern Cryptosuites + +For BBS-2023 and ECDSA-SD-2023, use the Data Integrity context: + +```typescript +import { DATA_INTEGRITY_V2_URL, VC_V1_URL } from '@trustvc/w3c-context'; + +// Create a credential with BBS-2023 or ECDSA-SD-2023 +const credential = { + "@context": [ + VC_V1_URL, + DATA_INTEGRITY_V2_URL // Supports BBS-2023, ECDSA-SD-2023 + ], + "type": ["VerifiableCredential"], + "credentialSubject": { + // ... credential data + }, + "proof": { + "type": "DataIntegrityProof", + "cryptosuite": "bbs-2023", // or "ecdsa-sd-2023" + // ... proof data + } +}; +``` + +### DID Resolution + +The document loader automatically resolves DID URLs: + +```typescript +const documentLoader = await getDocumentLoader(); + +// Resolves DID document +const didDoc = await documentLoader('did:web:example.com'); + +// Resolves specific verification method +const verificationMethod = await documentLoader('did:web:example.com#key-1'); +``` + +## API Reference + +### `getDocumentLoader(additionalContexts?)` + +Creates a document loader function that resolves JSON-LD contexts. + +**Parameters:** +- `additionalContexts` (optional): Record - Additional contexts to include + +**Returns:** Promise - A document loader function + +### Context Categories + +The package organizes contexts into several categories: + +- `contexts` - Core W3C and cryptographic contexts +- `trContexts` - Transferable records contexts +- `renderContexts` - Rendering method contexts +- `attachmentsContexts` - Attachment contexts +- `qrCodeContexts` - QR code contexts +- `templateContexts` - Business document templates + +## Development + +```sh +# Install dependencies +npm install + +# Build the package +npm run build + +# Run tests +npm test +``` + +## License + +MIT License - see LICENSE file for details. + +## Contributing + +Contributions are welcome! Please read our contributing guidelines and submit pull requests to our repository. diff --git a/packages/w3c-context/package.json b/packages/w3c-context/package.json index ba0d44ae..4ee7916d 100644 --- a/packages/w3c-context/package.json +++ b/packages/w3c-context/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c-context", - "version": "1.2.3-alpha.2", + "version": "1.2.13", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", @@ -33,7 +33,8 @@ } }, "dependencies": { - "did-resolver": "^4.1.0" + "did-resolver": "^4.1.0", + "jsonld-signatures": "^7.0.0" }, "repository": { "type": "git", diff --git a/packages/w3c-context/src/context/bill-of-lading-carrier.json b/packages/w3c-context/src/context/bill-of-lading-carrier.json new file mode 100644 index 00000000..cd244cad --- /dev/null +++ b/packages/w3c-context/src/context/bill-of-lading-carrier.json @@ -0,0 +1,107 @@ +{ + "@context": { + "@version": 1.1, + "@protected": true, + "BillOfLadingCarrier": { + "@id": "https://example.com/terms#BillOfLadingCarrier", + "@type": "@id", + "@context": { + "@protected": true, + "blNumber": { + "@id": "https://example.com/terms#blNumber" + }, + "scac": { + "@id": "https://example.com/terms#scac" + }, + "carrierName": { + "@id": "https://example.com/terms#carrierName" + }, + "logo": { + "@id": "https://example.com/terms#logo" + }, + "shipperName": { + "@id": "https://example.com/terms#shipperName" + }, + "shipperAddressStreet": { + "@id": "https://example.com/terms#shipperAddressStreet" + }, + "shipperAddressCountry": { + "@id": "https://example.com/terms#shipperAddressCountry" + }, + "onwardInlandRouting": { + "@id": "https://example.com/terms#onwardInlandRouting" + }, + "toOrderOfText": { + "@id": "https://example.com/terms#toOrderOfText" + }, + "consigneeName": { + "@id": "https://example.com/terms#consigneeName" + }, + "notifyPartyName": { + "@id": "https://example.com/terms#notifyPartyName" + }, + "vessel": { + "@id": "https://example.com/terms#vessel" + }, + "voyageNo": { + "@id": "https://example.com/terms#voyageNo" + }, + "portOfLoading": { + "@id": "https://example.com/terms#portOfLoading" + }, + "portOfDischarge": { + "@id": "https://example.com/terms#portOfDischarge" + }, + "placeOfReceipt": { + "@id": "https://example.com/terms#placeOfReceipt" + }, + "placeOfDelivery": { + "@id": "https://example.com/terms#placeOfDelivery" + }, + "packages": { + "@id": "https://example.com/terms#packages", + "@container": "@set", + "@context": { + "@protected": true, + "packagesDescription": { + "@id": "https://example.com/terms#packagesDescription" + }, + "packagesWeight": { + "@id": "https://example.com/terms#packagesWeight" + }, + "packagesMeasurement": { + "@id": "https://example.com/terms#packagesMeasurement" + } + } + }, + "carrierReceipt": { + "@id": "https://example.com/terms#carrierReceipt" + }, + "placeOfIssueBL": { + "@id": "https://example.com/terms#placeOfIssueBL" + }, + "numberOfOriginalBL": { + "@id": "https://example.com/terms#numberOfOriginalBL" + }, + "dateOfIssueBL": { + "@id": "https://example.com/terms#dateOfIssueBL" + }, + "shippedOnBoardDate": { + "@id": "https://example.com/terms#shippedOnBoardDate" + }, + "signForTermsAndCondition": { + "@id": "https://example.com/terms#signForTermsAndCondition" + }, + "signedForCarrierText": { + "@id": "https://example.com/terms#signedForCarrierText" + }, + "carrierSignature": { + "@id": "https://example.com/terms#carrierSignature" + }, + "termsOfCarriage": { + "@id": "https://example.com/terms#termsOfCarriage" + } + } + } + } +} diff --git a/packages/w3c-context/src/context/coo.json b/packages/w3c-context/src/context/coo.json new file mode 100644 index 00000000..35d20765 --- /dev/null +++ b/packages/w3c-context/src/context/coo.json @@ -0,0 +1,196 @@ +{ + "@context": { + "@version": 1.1, + "@protected": true, + "Coo": { + "@id": "https://example.com/terms#Coo", + "@type": "@id", + "@context": { + "@protected": true, + "cooId": { + "@id": "https://example.com/terms#cooId" + }, + "issueDateTime": { + "@id": "https://example.com/terms#issueDateTime" + }, + "signature": { + "@id": "https://example.com/terms#signature" + }, + "supplyChainConsignmentId": { + "@id": "https://example.com/terms#supplyChainConsignmentId" + }, + "supplyChainConsignmentInformation": { + "@id": "https://example.com/terms#supplyChainConsignmentInformation" + }, + "exportCountryCode": { + "@id": "https://example.com/terms#exportCountryCode" + }, + "exporterId": { + "@id": "https://example.com/terms#exporterId" + }, + "exporterName": { + "@id": "https://example.com/terms#exporterName" + }, + "exporterLine1": { + "@id": "https://example.com/terms#exporterLine1" + }, + "exporterLine2": { + "@id": "https://example.com/terms#exporterLine2" + }, + "exporterCityName": { + "@id": "https://example.com/terms#exporterCityName" + }, + "exporterPostcode": { + "@id": "https://example.com/terms#exporterPostcode" + }, + "exporterCountrySubDivisionName": { + "@id": "https://example.com/terms#exporterCountrySubDivisionName" + }, + "exporterCountryCode": { + "@id": "https://example.com/terms#exporterCountryCode" + }, + "importCountryCode": { + "@id": "https://example.com/terms#importCountryCode" + }, + "importerId": { + "@id": "https://example.com/terms#importerId" + }, + "importerName": { + "@id": "https://example.com/terms#importerName" + }, + "importerLine1": { + "@id": "https://example.com/terms#importerLine1" + }, + "importerLine2": { + "@id": "https://example.com/terms#importerLine2" + }, + "importerCityName": { + "@id": "https://example.com/terms#importerCityName" + }, + "importerPostcode": { + "@id": "https://example.com/terms#importerPostcode" + }, + "importerCountrySubDivisionName": { + "@id": "https://example.com/terms#importerCountrySubDivisionName" + }, + "importerCountryCode": { + "@id": "https://example.com/terms#importerCountryCode" + }, + "includedConsignmentItems": { + "@id": "https://example.com/terms#includedConsignmentItems", + "@container": "@set", + "@context": { + "includedConsignmentItemsId": { + "@id": "https://example.com/terms#includedConsignmentItemsId" + }, + "includedConsignmentItemsInformation": { + "@id": "https://example.com/terms#includedConsignmentItemsInformation" + }, + "originCriteriaText": { + "@id": "https://example.com/terms#originCriteriaText" + }, + "manufacturerId": { + "@id": "https://example.com/terms#manufacturerId" + }, + "manufacturerName": { + "@id": "https://example.com/terms#manufacturerName" + }, + "manufacturerLine1": { + "@id": "https://example.com/terms#manufacturerLine1" + }, + "manufacturerLine2": { + "@id": "https://example.com/terms#manufacturerLine2" + }, + "manufacturerCityName": { + "@id": "https://example.com/terms#manufacturerCityName" + }, + "manufacturerPostcode": { + "@id": "https://example.com/terms#manufacturerPostcode" + }, + "manufacturerCountrySubDivisionName": { + "@id": "https://example.com/terms#manufacturerCountrySubDivisionName" + }, + "manufacturerCountryCode": { + "@id": "https://example.com/terms#manufacturerCountryCode" + }, + "tradeLineItems": { + "@id": "https://example.com/terms#tradeLineItems", + "@container": "@set", + "@context": { + "sequenceNumber": { + "@id": "https://example.com/terms#sequenceNumber" + }, + "invoiceReferenceId": { + "@id": "https://example.com/terms#invoiceReferenceId" + }, + "formattedIssueDateTime": { + "@id": "https://example.com/terms#formattedIssueDateTime" + }, + "attachedBinaryFileUri": { + "@id": "https://example.com/terms#attachedBinaryFileUri" + }, + "tradeProductId": { + "@id": "https://example.com/terms#tradeProductId" + }, + "tradeProductDescription": { + "@id": "https://example.com/terms#tradeProductDescription" + }, + "harmonisedTariffclassCode": { + "@id": "https://example.com/terms#harmonisedTariffclassCode" + }, + "harmonisedTariffclassName": { + "@id": "https://example.com/terms#harmonisedTariffclassName" + }, + "originCountryCode": { + "@id": "https://example.com/terms#originCountryCode" + }, + "transportPackages": { + "@id": "https://example.com/terms#transportPackages", + "@container": "@set", + "@context": { + "transportPackagesId": { + "@id": "https://example.com/terms#transportPackagesId" + }, + "transportPackagesGrossVolume": { + "@id": "https://example.com/terms#transportPackagesGrossVolume" + }, + "transportPackagesGrossWeight": { + "@id": "https://example.com/terms#transportPackagesGrossWeight" + } + } + } + } + } + } + }, + "loadingBaseportLocationId": { + "@id": "https://example.com/terms#loadingBaseportLocationId" + }, + "loadingBaseportLocationName": { + "@id": "https://example.com/terms#loadingBaseportLocationName" + }, + "mainCarriageTransportMovementId": { + "@id": "https://example.com/terms#mainCarriageTransportMovementId" + }, + "mainCarriageTransportMovementInformation": { + "@id": "https://example.com/terms#mainCarriageTransportMovementInformation" + }, + "usedTransportMeansName": { + "@id": "https://example.com/terms#usedTransportMeansName" + }, + "usedTransportMeansId": { + "@id": "https://example.com/terms#usedTransportMeansId" + }, + "departureDateTime": { + "@id": "https://example.com/terms#departureDateTime" + }, + "unloadingBaseportLocationId": { + "@id": "https://example.com/terms#unloadingBaseportLocationId" + }, + "unloadingBaseportLocationName": { + "@id": "https://example.com/terms#unloadingBaseportLocationName" + } + } + } + } +} diff --git a/packages/w3c-context/src/context/data-integrity-v2.json b/packages/w3c-context/src/context/data-integrity-v2.json new file mode 100644 index 00000000..dfd8f35f --- /dev/null +++ b/packages/w3c-context/src/context/data-integrity-v2.json @@ -0,0 +1,81 @@ +{ + "@context": { + "id": "@id", + "type": "@type", + "@protected": true, + "proof": { + "@id": "https://w3id.org/security#proof", + "@type": "@id", + "@container": "@graph" + }, + "DataIntegrityProof": { + "@id": "https://w3id.org/security#DataIntegrityProof", + "@context": { + "@protected": true, + "id": "@id", + "type": "@type", + "challenge": "https://w3id.org/security#challenge", + "created": { + "@id": "http://purl.org/dc/terms/created", + "@type": "http://www.w3.org/2001/XMLSchema#dateTime" + }, + "domain": "https://w3id.org/security#domain", + "expires": { + "@id": "https://w3id.org/security#expiration", + "@type": "http://www.w3.org/2001/XMLSchema#dateTime" + }, + "nonce": "https://w3id.org/security#nonce", + "previousProof": { + "@id": "https://w3id.org/security#previousProof", + "@type": "@id" + }, + "proofPurpose": { + "@id": "https://w3id.org/security#proofPurpose", + "@type": "@vocab", + "@context": { + "@protected": true, + "id": "@id", + "type": "@type", + "assertionMethod": { + "@id": "https://w3id.org/security#assertionMethod", + "@type": "@id", + "@container": "@set" + }, + "authentication": { + "@id": "https://w3id.org/security#authenticationMethod", + "@type": "@id", + "@container": "@set" + }, + "capabilityInvocation": { + "@id": "https://w3id.org/security#capabilityInvocationMethod", + "@type": "@id", + "@container": "@set" + }, + "capabilityDelegation": { + "@id": "https://w3id.org/security#capabilityDelegationMethod", + "@type": "@id", + "@container": "@set" + }, + "keyAgreement": { + "@id": "https://w3id.org/security#keyAgreementMethod", + "@type": "@id", + "@container": "@set" + } + } + }, + "cryptosuite": { + "@id": "https://w3id.org/security#cryptosuite", + "@type": "https://w3id.org/security#cryptosuiteString" + }, + "proofValue": { + "@id": "https://w3id.org/security#proofValue", + "@type": "https://w3id.org/security#multibase" + }, + "verificationMethod": { + "@id": "https://w3id.org/security#verificationMethod", + "@type": "@id" + } + } + } + } +} diff --git a/packages/w3c-context/src/context/multikey-v1.json b/packages/w3c-context/src/context/multikey-v1.json new file mode 100644 index 00000000..43ac7f0c --- /dev/null +++ b/packages/w3c-context/src/context/multikey-v1.json @@ -0,0 +1,35 @@ +{ + "@context": { + "id": "@id", + "type": "@type", + "@protected": true, + "Multikey": { + "@id": "https://w3id.org/security#Multikey", + "@context": { + "@protected": true, + "id": "@id", + "type": "@type", + "controller": { + "@id": "https://w3id.org/security#controller", + "@type": "@id" + }, + "revoked": { + "@id": "https://w3id.org/security#revoked", + "@type": "http://www.w3.org/2001/XMLSchema#dateTime" + }, + "expires": { + "@id": "https://w3id.org/security#expiration", + "@type": "http://www.w3.org/2001/XMLSchema#dateTime" + }, + "publicKeyMultibase": { + "@id": "https://w3id.org/security#publicKeyMultibase", + "@type": "https://w3id.org/security#multibase" + }, + "secretKeyMultibase": { + "@id": "https://w3id.org/security#secretKeyMultibase", + "@type": "https://w3id.org/security#multibase" + } + } + } + } +} diff --git a/packages/w3c-context/src/context/promissory-note.json b/packages/w3c-context/src/context/promissory-note.json new file mode 100644 index 00000000..a5f93b64 --- /dev/null +++ b/packages/w3c-context/src/context/promissory-note.json @@ -0,0 +1,82 @@ +{ + "@context": { + "@version": 1.1, + "@protected": true, + "PromissoryNote": { + "@id": "https://example.com/terms#PromissoryNote", + "@type": "@id", + "@context": { + "@protected": true, + "logo": { + "@id": "https://example.com/terms#logo" + }, + "backgroundImage": { + "@id": "https://example.com/terms#backgroundImage" + }, + "pNoteId": { + "@id": "https://example.com/terms#pNoteId" + }, + "commitmentDate": { + "@id": "https://example.com/terms#commitmentDate" + }, + "drawerCompanyName": { + "@id": "https://example.com/terms#drawerCompanyName" + }, + "drawerCompanyNo": { + "@id": "https://example.com/terms#drawerCompanyNo" + }, + "drawerJurisdiction": { + "@id": "https://example.com/terms#drawerJurisdiction" + }, + "drawerEmail": { + "@id": "https://example.com/terms#drawerEmail" + }, + "drawerWalletAddress": { + "@id": "https://example.com/terms#drawerWalletAddress" + }, + "drawerPlaceOfIssue": { + "@id": "https://example.com/terms#drawerPlaceOfIssue" + }, + "draweeCompanyName": { + "@id": "https://example.com/terms#draweeCompanyName" + }, + "draweeCompanyNo": { + "@id": "https://example.com/terms#draweeCompanyNo" + }, + "draweeJurisdiction": { + "@id": "https://example.com/terms#draweeJurisdiction" + }, + "draweeEmail": { + "@id": "https://example.com/terms#draweeEmail" + }, + "draweeWalletAddress": { + "@id": "https://example.com/terms#draweeWalletAddress" + }, + "dueDate": { + "@id": "https://example.com/terms#dueDate" + }, + "currency": { + "@id": "https://example.com/terms#currency" + }, + "amount": { + "@id": "https://example.com/terms#amount" + }, + "clause": { + "@id": "https://example.com/terms#clause" + }, + "signerName": { + "@id": "https://example.com/terms#signerName" + }, + "signerPosition": { + "@id": "https://example.com/terms#signerPosition" + }, + "signerEmail": { + "@id": "https://example.com/terms#signerEmail" + }, + "signerTimeStamp": { + "@id": "https://example.com/terms#signerTimeStamp" + } + } + } + } +} diff --git a/packages/w3c-context/src/context/qrcode-context.json b/packages/w3c-context/src/context/qrcode-context.json new file mode 100644 index 00000000..ce608526 --- /dev/null +++ b/packages/w3c-context/src/context/qrcode-context.json @@ -0,0 +1,20 @@ +{ + "@context": { + "@version": 1.1, + "@protected": true, + "xsd": "http://www.w3.org/2001/XMLSchema#", + "qrCode": { + "@id": "https://example.org/terms#qrCode", + "@context": { + "@protected": true, + "uri": { + "@id": "https://example.org/terms#uri", + "@type": "xsd:anyURI" + }, + "type": { + "@id": "https://example.org/terms#type" + } + } + } + } +} diff --git a/packages/w3c-context/src/context/render-method-context.json b/packages/w3c-context/src/context/render-method-context.json index b8c0f597..98c0887b 100644 --- a/packages/w3c-context/src/context/render-method-context.json +++ b/packages/w3c-context/src/context/render-method-context.json @@ -22,4 +22,3 @@ } } } - \ No newline at end of file diff --git a/packages/w3c-context/src/context/status-list-2021-v1.json b/packages/w3c-context/src/context/status-list-2021-v1.json new file mode 100644 index 00000000..f3d2824d --- /dev/null +++ b/packages/w3c-context/src/context/status-list-2021-v1.json @@ -0,0 +1,39 @@ +{ + "@context": { + "@protected": true, + "StatusList2021Credential": { + "@id": "https://w3id.org/vc/status-list#StatusList2021Credential", + "@context": { + "@protected": true, + "id": "@id", + "type": "@type", + "description": "http://schema.org/description", + "name": "http://schema.org/name" + } + }, + "StatusList2021": { + "@id": "https://w3id.org/vc/status-list#StatusList2021", + "@context": { + "@protected": true, + "id": "@id", + "type": "@type", + "statusPurpose": "https://w3id.org/vc/status-list#statusPurpose", + "encodedList": "https://w3id.org/vc/status-list#encodedList" + } + }, + "StatusList2021Entry": { + "@id": "https://w3id.org/vc/status-list#StatusList2021Entry", + "@context": { + "@protected": true, + "id": "@id", + "type": "@type", + "statusPurpose": "https://w3id.org/vc/status-list#statusPurpose", + "statusListIndex": "https://w3id.org/vc/status-list#statusListIndex", + "statusListCredential": { + "@id": "https://w3id.org/vc/status-list#statusListCredential", + "@type": "@id" + } + } + } + } +} diff --git a/packages/w3c-context/src/context/warehouse-receipt.json b/packages/w3c-context/src/context/warehouse-receipt.json new file mode 100644 index 00000000..ac2f3f3b --- /dev/null +++ b/packages/w3c-context/src/context/warehouse-receipt.json @@ -0,0 +1,89 @@ +{ + "@context": { + "@version": 1.1, + "@protected": true, + "WarehouseReceipt": { + "@id": "https://example.com/terms#WarehouseReceipt", + "@type": "@id", + "@context": { + "@protected": true, + "logo": { + "@id": "https://example.com/terms#logo" + }, + "spl": { + "@id": "https://example.com/terms#spl" + }, + "warehouseReceipt": { + "@id": "https://example.com/terms#warehouseReceipt" + }, + "issuanceDate": { + "@id": "https://example.com/terms#issuanceDate" + }, + "ourRef": { + "@id": "https://example.com/terms#ourRef" + }, + "rentStartDate": { + "@id": "https://example.com/terms#rentStartDate" + }, + "yourRef": { + "@id": "https://example.com/terms#yourRef" + }, + "commodity": { + "@id": "https://example.com/terms#commodity" + }, + "documentType": { + "@id": "https://example.com/terms#documentType" + }, + "order": { + "@id": "https://example.com/terms#order" + }, + "account": { + "@id": "https://example.com/terms#account" + }, + "goods": { + "@id": "https://example.com/terms#goods", + "@container": "@set", + "@context": { + "@protected": true, + "brand": { + "@id": "https://example.com/terms#brand" + }, + "piles": { + "@id": "https://example.com/terms#piles" + }, + "bundles": { + "@id": "https://example.com/terms#bundles" + }, + "pieces": { + "@id": "https://example.com/terms#pieces" + }, + "netWeight": { + "@id": "https://example.com/terms#netWeight" + }, + "grossWeight": { + "@id": "https://example.com/terms#grossWeight" + } + } + }, + "totalNetWeight": { + "@id": "https://example.com/terms#totalNetWeight" + }, + "warehouseAddress": { + "@id": "https://example.com/terms#warehouseAddress" + }, + "markings": { + "@id": "https://example.com/terms#markings" + }, + "storageAndServicesTerms": { + "@id": "https://example.com/terms#storageAndServicesTerms" + }, + "signature": { + "@id": "https://example.com/terms#signature" + }, + "termsAndConditions": { + "@id": "https://example.com/terms#termsAndConditions" + } + } + } + } +} diff --git a/packages/w3c-context/src/index.ts b/packages/w3c-context/src/index.ts index e1bc2a74..b10c19da 100644 --- a/packages/w3c-context/src/index.ts +++ b/packages/w3c-context/src/index.ts @@ -1,2 +1,4 @@ export * from './lib/index'; +export type * from './lib/index'; export * from './lib/types'; +export type * from './lib/types'; diff --git a/packages/w3c-context/src/lib/index.ts b/packages/w3c-context/src/lib/index.ts index 8529e043..ad36502d 100644 --- a/packages/w3c-context/src/lib/index.ts +++ b/packages/w3c-context/src/lib/index.ts @@ -1,39 +1,59 @@ -import { Resolver } from 'did-resolver'; +import { queryDidDocument } from '@trustvc/w3c-issuer'; import { DocumentLoader, DocumentLoaderObject } from './types'; // @ts-ignore: No types available for jsonld-signatures import jsonldSignatures from 'jsonld-signatures'; -import { getResolver as webGetResolver } from 'web-did-resolver'; import attachmentsContext from '../context/attachments-context.json'; import bbsV1 from '../context/bbs-v1.json'; import bolContext from '../context/bill-of-lading.json'; +import bolcContext from '../context/bill-of-lading-carrier.json'; +import cooContext from '../context/coo.json'; import credentialsV1 from '../context/credentials-v1.json'; import credentialsV2 from '../context/credentials-v2.json'; +import dataIntegrityV2 from '../context/data-integrity-v2.json'; import didV1 from '../context/did-v1.json'; import invoiceContext from '../context/invoice.json'; import jwsV1 from '../context/jws-2020-v1.json'; +import multikeyV1 from '../context/multikey-v1.json'; +import promissoryNoteContext from '../context/promissory-note.json'; +import qrCodeContext from '../context/qrcode-context.json'; import renderContext from '../context/render-method-context.json'; +import statusList2021V1 from '../context/status-list-2021-v1.json'; import trContext from '../context/transferable-records-context.json'; +import warehouseReceiptContext from '../context/warehouse-receipt.json'; import { Document } from './types'; +export const DATA_INTEGRITY_V2_URL = 'https://w3id.org/security/data-integrity/v2'; export const DID_V1_URL = 'https://www.w3.org/ns/did/v1'; export const VC_V1_URL = 'https://www.w3.org/2018/credentials/v1'; export const VC_V2_URL = 'https://www.w3.org/ns/credentials/v2'; +export const BBS_V1_URL = 'https://w3id.org/security/bbs/v1'; +export const BLS12381_2020_V1_URL = 'https://w3id.org/security/suites/bls12381-2020/v1'; +export const JWS_V1_URL = 'https://w3id.org/security/suites/jws-2020/v1'; +export const MULTIKEY_V1_URL = 'https://w3id.org/security/multikey/v1'; +export const STATUS_LIST_2021_CREDENTIAL_URL = 'https://w3id.org/vc/status-list/2021/v1'; + export const TR_CONTEXT_URL = 'https://trustvc.io/context/transferable-records-context.json'; export const RENDER_CONTEXT_URL = 'https://trustvc.io/context/render-method-context.json'; export const ATTACHMENTS_CONTEXT_URL = 'https://trustvc.io/context/attachments-context.json'; +export const QRCODE_CONTEXT_URL = 'https://trustvc.io/context/qrcode-context.json'; + export const BOL_CONTEXT_URL = 'https://trustvc.io/context/bill-of-lading.json'; +export const BOLC_CONTEXT_URL = 'https://trustvc.io/context/bill-of-lading-carrier.json'; +export const COO_CONTEXT_URL = 'https://trustvc.io/context/coo.json'; export const INVOICE_CONTEXT_URL = 'https://trustvc.io/context/invoice.json'; - -export const BBS_V1_URL = 'https://w3id.org/security/bbs/v1'; -export const JWS_V1_URL = 'https://w3id.org/security/suites/jws-2020/v1'; -export const STATUS_LIST_2021_CREDENTIAL_URL = 'https://w3id.org/vc/status-list/2021/v1'; +export const PROMISSORY_NOTE_CONTEXT_URL = 'https://trustvc.io/context/promissory-note.json'; +export const WAREHOUSE_RECEIPT_CONTEXT_URL = 'https://trustvc.io/context/warehouse-receipt.json'; export const contexts: { [key: string]: Document } = { + [DATA_INTEGRITY_V2_URL]: dataIntegrityV2, [DID_V1_URL]: didV1, [VC_V1_URL]: credentialsV1, [VC_V2_URL]: credentialsV2, [BBS_V1_URL]: bbsV1, + [BLS12381_2020_V1_URL]: bbsV1, [JWS_V1_URL]: jwsV1, + [MULTIKEY_V1_URL]: multikeyV1, + [STATUS_LIST_2021_CREDENTIAL_URL]: statusList2021V1, }; export const trContexts: { [key: string]: Document } = { @@ -48,12 +68,17 @@ export const attachmentsContexts: { [key: string]: Document } = { [ATTACHMENTS_CONTEXT_URL]: attachmentsContext, }; -export const bolContexts: { [key: string]: Document } = { - [BOL_CONTEXT_URL]: bolContext, +export const qrCodeContexts: { [key: string]: Document } = { + [QRCODE_CONTEXT_URL]: qrCodeContext, }; -export const invoiceContexts: { [key: string]: Document } = { +export const templateContexts: { [key: string]: Document } = { + [BOL_CONTEXT_URL]: bolContext, + [BOLC_CONTEXT_URL]: bolcContext, + [COO_CONTEXT_URL]: cooContext, [INVOICE_CONTEXT_URL]: invoiceContext, + [PROMISSORY_NOTE_CONTEXT_URL]: promissoryNoteContext, + [WAREHOUSE_RECEIPT_CONTEXT_URL]: warehouseReceiptContext, }; export const CredentialContextVersion = { @@ -80,8 +105,8 @@ export async function getDocumentLoader( trContexts, renderContexts, attachmentsContexts, - bolContexts, - invoiceContexts, + qrCodeContexts, + templateContexts, additionalContexts, ].forEach((context) => { if (!context) return; @@ -95,14 +120,10 @@ export async function getDocumentLoader( }); const resolveDid = async (did: string) => { - const resolver = new Resolver({ - ...webGetResolver(), - }); - const doc = await resolver.resolve(did); - + const { wellKnownDid } = await queryDidDocument({ did }); const result: DocumentLoaderObject = { contextUrl: null, - document: doc.didDocument, + document: wellKnownDid, documentUrl: did, }; diff --git a/packages/w3c-credential-status/CHANGELOG.md b/packages/w3c-credential-status/CHANGELOG.md index 1e262cc1..76f85104 100644 --- a/packages/w3c-credential-status/CHANGELOG.md +++ b/packages/w3c-credential-status/CHANGELOG.md @@ -1,16 +1,79 @@ -## [1.2.3-alpha.2](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-credential-status@1.2.3-alpha.1...@trustvc/w3c-credential-status@1.2.3-alpha.2) (2025-04-09) +## [1.2.13](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-credential-status@1.2.12...@trustvc/w3c-credential-status@1.2.13) (2025-06-13) ### Bug Fixes -* add cache for jws 2020 v1 ([#48](https://github.com/TrustVC/w3c/issues/48)) ([4a9f52a](https://github.com/TrustVC/w3c/commit/4a9f52a823e5836454c65239916fa5807c9d0be1)) +* expired and redacted doc checks ([#64](https://github.com/TrustVC/w3c/issues/64)) ([4d0a65a](https://github.com/TrustVC/w3c/commit/4d0a65ad467e07bc0f837368f6ff93f84abfb0a8)) -## [1.2.3-alpha.1](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-credential-status@1.2.2...@trustvc/w3c-credential-status@1.2.3-alpha.1) (2025-04-09) +## [1.2.12](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-credential-status@1.2.11...@trustvc/w3c-credential-status@1.2.12) (2025-05-30) ### Bug Fixes -* update fetchCredentialStatusVC to use documentLoader ([#46](https://github.com/TrustVC/w3c/issues/46)) ([7fe49f8](https://github.com/TrustVC/w3c/commit/7fe49f8e5a01cf36f4fdd87bccd72f87554a9072)) +* type errors ([#62](https://github.com/TrustVC/w3c/issues/62)) ([e4cf81f](https://github.com/TrustVC/w3c/commit/e4cf81f4cab187be464f92503bf0f0c39aef61d7)) + +## [1.2.11](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-credential-status@1.2.10...@trustvc/w3c-credential-status@1.2.11) (2025-05-21) + + +### Bug Fixes + +* coo context ([#59](https://github.com/TrustVC/w3c/issues/59)) ([b802c6f](https://github.com/TrustVC/w3c/commit/b802c6f8605387024d5a50d81e4edfa3da709ba7)) + +## [1.2.10](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-credential-status@1.2.9...@trustvc/w3c-credential-status@1.2.10) (2025-05-20) + + +### Bug Fixes + +* add template context ([#58](https://github.com/TrustVC/w3c/issues/58)) ([8a467b7](https://github.com/TrustVC/w3c/commit/8a467b738bebe935f00af525684e84bfd01fe6e9)) + +## [1.2.9](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-credential-status@1.2.8...@trustvc/w3c-credential-status@1.2.9) (2025-05-16) + + +### Bug Fixes + +* cli error messages ([#54](https://github.com/TrustVC/w3c/issues/54)) ([3825ce9](https://github.com/TrustVC/w3c/commit/3825ce9598479f52a75b2a8dbd38efc97730950a)) + +## [1.2.8](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-credential-status@1.2.7...@trustvc/w3c-credential-status@1.2.8) (2025-05-14) + + +### Bug Fixes + +* add qrcode context ([#55](https://github.com/TrustVC/w3c/issues/55)) ([19cd0df](https://github.com/TrustVC/w3c/commit/19cd0dfd20e848f744e1a5d6255557bde101d998)) + +## [1.2.7](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-credential-status@1.2.6...@trustvc/w3c-credential-status@1.2.7) (2025-04-24) + + +### Bug Fixes + +* update promissory note context ([#53](https://github.com/TrustVC/w3c/issues/53)) ([e032f45](https://github.com/TrustVC/w3c/commit/e032f4582da0983d2ca5648d7c55fac6bc97c1f6)) + +## [1.2.6](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-credential-status@1.2.5...@trustvc/w3c-credential-status@1.2.6) (2025-04-23) + + +### Bug Fixes + +* add promissory note context for w3c ([#52](https://github.com/TrustVC/w3c/issues/52)) ([54b866a](https://github.com/TrustVC/w3c/commit/54b866a66ff1db2466628fb32a1bb4820d71b7d1)) + +## [1.2.5](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-credential-status@1.2.4...@trustvc/w3c-credential-status@1.2.5) (2025-04-22) + + +### Bug Fixes + +* clean up resolver ([#51](https://github.com/TrustVC/w3c/issues/51)) ([936b5ec](https://github.com/TrustVC/w3c/commit/936b5ec23a372ae441bde9cd99701cbdd2408465)) + +## [1.2.4](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-credential-status@1.2.3...@trustvc/w3c-credential-status@1.2.4) (2025-04-10) + + +### Bug Fixes + +* add bls to context cache ([#50](https://github.com/TrustVC/w3c/issues/50)) ([a1988b0](https://github.com/TrustVC/w3c/commit/a1988b0ef2d82c95c3e285c93eedd61b050e4fd9)) + +## [1.2.3](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-credential-status@1.2.2...@trustvc/w3c-credential-status@1.2.3) (2025-04-09) + + +### Bug Fixes + +* update fetchCredentialStatusVC to use documentLoader and add cache for jws 2020 v1 ([#49](https://github.com/TrustVC/w3c/issues/49)) ([2c50901](https://github.com/TrustVC/w3c/commit/2c50901035aac696f75ef386bd8beca367f02db7)) ## [1.2.2](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-credential-status@1.2.1...@trustvc/w3c-credential-status@1.2.2) (2025-04-07) diff --git a/packages/w3c-credential-status/package.json b/packages/w3c-credential-status/package.json index 68b194ef..29c7d8ef 100644 --- a/packages/w3c-credential-status/package.json +++ b/packages/w3c-credential-status/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c-credential-status", - "version": "1.2.3-alpha.2", + "version": "1.2.13", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", @@ -29,8 +29,8 @@ } }, "dependencies": { - "@trustvc/w3c-context": "^1.2.3-alpha.2", - "@trustvc/w3c-issuer": "^1.2.1", + "@trustvc/w3c-context": "^1.2.13", + "@trustvc/w3c-issuer": "^1.2.4", "base64url-universal": "^2.0.0", "pako": "^2.1.0" }, diff --git a/packages/w3c-credential-status/src/lib/index.ts b/packages/w3c-credential-status/src/lib/index.ts index c81efb03..f93556f0 100644 --- a/packages/w3c-credential-status/src/lib/index.ts +++ b/packages/w3c-credential-status/src/lib/index.ts @@ -9,8 +9,15 @@ import { VCBitstringCredentialSubjectType, VCCredentialStatusType, } from './BitstringStatusList/types'; -import { CreateVCCredentialStatusOptions, RawCredentialStatusVC } from './types'; -import { getValidFromDateFromCredentialStatusVC } from './utils'; +import { + CreateVCCredentialStatusOptions, + GeneralCredentialStatus, + RawCredentialStatusVC, +} from './types'; +import { + assertCredentialStatusStatusListType, + getValidFromDateFromCredentialStatusVC, +} from './utils'; export const VCCredentialStatusTypeToVCCredentialSubjectType: Record< VCCredentialStatusType, @@ -80,3 +87,17 @@ export const createCredentialStatusPayload = async ( throw err; } }; + +/** + * Checks if the input credential status is a StatusList2021Credential. + * @param {GeneralCredentialStatus} credentialStatus - The credential status to be checked. + * @returns {boolean} - Returns true if the credential status is a StatusList2021Credential, false otherwise. + */ +export const isCredentialStatusStatusList = (credentialStatus: GeneralCredentialStatus) => { + try { + assertCredentialStatusStatusListType(credentialStatus?.type); + return true; + } catch (err) { + return false; + } +}; diff --git a/packages/w3c-credential-status/src/lib/utils.ts b/packages/w3c-credential-status/src/lib/utils.ts index d1a90ec3..ad8af4a3 100644 --- a/packages/w3c-credential-status/src/lib/utils.ts +++ b/packages/w3c-credential-status/src/lib/utils.ts @@ -27,6 +27,19 @@ export const assertCredentialStatusType = (type: T): void => { } }; +/** + * Asserts the type of the credential status statusList. + * @param type - The type of the credential status. + * @throws {Error} - Throws an error if the type is not supported. + */ +export const assertCredentialStatusStatusListType = (type: T): void => { + const supportedTypes: T[] = ['StatusList2021Entry'] as T[]; + + if (!supportedTypes.includes(type)) { + throw new Error(`Unsupported type: ${type}`); + } +}; + /** * Asserts the statusListIndex is a valid number. * @param statusListIndex - The index of the statusList in the statusListCredential. diff --git a/packages/w3c-issuer/CHANGELOG.md b/packages/w3c-issuer/CHANGELOG.md index ff21be6b..536a9047 100644 --- a/packages/w3c-issuer/CHANGELOG.md +++ b/packages/w3c-issuer/CHANGELOG.md @@ -1,3 +1,24 @@ +## [1.2.4](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-issuer@1.2.3...@trustvc/w3c-issuer@1.2.4) (2025-06-13) + + +### Bug Fixes + +* expired and redacted doc checks ([#64](https://github.com/TrustVC/w3c/issues/64)) ([4d0a65a](https://github.com/TrustVC/w3c/commit/4d0a65ad467e07bc0f837368f6ff93f84abfb0a8)) + +## [1.2.3](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-issuer@1.2.2...@trustvc/w3c-issuer@1.2.3) (2025-05-16) + + +### Bug Fixes + +* cli error messages ([#54](https://github.com/TrustVC/w3c/issues/54)) ([3825ce9](https://github.com/TrustVC/w3c/commit/3825ce9598479f52a75b2a8dbd38efc97730950a)) + +## [1.2.2](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-issuer@1.2.1...@trustvc/w3c-issuer@1.2.2) (2025-04-22) + + +### Bug Fixes + +* clean up resolver ([#51](https://github.com/TrustVC/w3c/issues/51)) ([936b5ec](https://github.com/TrustVC/w3c/commit/936b5ec23a372ae441bde9cd99701cbdd2408465)) + ## [1.2.1](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-issuer@1.2.0...@trustvc/w3c-issuer@1.2.1) (2024-12-17) diff --git a/packages/w3c-issuer/package.json b/packages/w3c-issuer/package.json index 6eb4267e..c4e6a54f 100644 --- a/packages/w3c-issuer/package.json +++ b/packages/w3c-issuer/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c-issuer", - "version": "1.2.1", + "version": "1.2.4", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", diff --git a/packages/w3c-issuer/src/did-web/index.ts b/packages/w3c-issuer/src/did-web/index.ts index fb8d7802..a5c7ec2d 100644 --- a/packages/w3c-issuer/src/did-web/index.ts +++ b/packages/w3c-issuer/src/did-web/index.ts @@ -1,6 +1,7 @@ import { generateKeyPair } from './keyPair'; import { issueDID } from './wellKnown'; +import { queryDidDocument } from './wellKnown/query'; export * from './keyPair/types'; export * from './wellKnown/types'; -export { generateKeyPair, issueDID }; +export { generateKeyPair, issueDID, queryDidDocument }; diff --git a/packages/w3c-issuer/src/lib/index.ts b/packages/w3c-issuer/src/lib/index.ts index b9b74619..cb5339f4 100644 --- a/packages/w3c-issuer/src/lib/index.ts +++ b/packages/w3c-issuer/src/lib/index.ts @@ -51,16 +51,24 @@ export const parseMultibase = async (multibase: string): Promise => * @returns {string} - Domain name (e.g., example.com/part/index) */ export const getDomain = (domain: Readonly): string | undefined => { - // convert domain https://example.com/part/index?id=123 to example.com - const domainRegex = new RegExp(/.+\..+/); - const pathNameRegex = new RegExp(/\/.+/); - if (!domain || !domainRegex.test(domain)) { - return; + if (!domain || domain.trim() === '') { + return undefined; } - const parsedUrl = domain.startsWith('http') ? domain : 'http://' + domain; + try { + // Ensure we have a protocol for the URL constructor + const parsedUrl = domain.startsWith('http') ? domain : 'http://' + domain; + const url = new URL(parsedUrl); - const url = new URL(parsedUrl); - const validPathName = pathNameRegex.test(url.pathname); - return url.hostname + (validPathName ? url.pathname : ''); + // Basic validation: ensure the hostname has at least one dot (for TLD) + if (!url.hostname.includes('.')) { + return undefined; + } + + // Return hostname with pathname if it exists and isn't just '/' + return url.hostname + (url.pathname !== '/' ? url.pathname : ''); + } catch (error) { + // If URL parsing fails, the domain is invalid + return undefined; + } }; diff --git a/packages/w3c-vc/CHANGELOG.md b/packages/w3c-vc/CHANGELOG.md index f7aba188..d68c34bf 100644 --- a/packages/w3c-vc/CHANGELOG.md +++ b/packages/w3c-vc/CHANGELOG.md @@ -1,23 +1,79 @@ -## [1.2.7-alpha.3](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.2.7-alpha.2...@trustvc/w3c-vc@1.2.7-alpha.3) (2025-04-09) +## [1.2.17](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.2.16...@trustvc/w3c-vc@1.2.17) (2025-06-13) ### Bug Fixes -* add cache for jws 2020 v1 ([#48](https://github.com/TrustVC/w3c/issues/48)) ([4a9f52a](https://github.com/TrustVC/w3c/commit/4a9f52a823e5836454c65239916fa5807c9d0be1)) +* expired and redacted doc checks ([#64](https://github.com/TrustVC/w3c/issues/64)) ([4d0a65a](https://github.com/TrustVC/w3c/commit/4d0a65ad467e07bc0f837368f6ff93f84abfb0a8)) -## [1.2.7-alpha.2](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.2.7-alpha.1...@trustvc/w3c-vc@1.2.7-alpha.2) (2025-04-09) +## [1.2.16](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.2.15...@trustvc/w3c-vc@1.2.16) (2025-05-30) ### Bug Fixes -* add export ([#47](https://github.com/TrustVC/w3c/issues/47)) ([dae74e7](https://github.com/TrustVC/w3c/commit/dae74e779e8f26dcd84f63e9baea905d2eca91fc)) +* type errors ([#62](https://github.com/TrustVC/w3c/issues/62)) ([e4cf81f](https://github.com/TrustVC/w3c/commit/e4cf81f4cab187be464f92503bf0f0c39aef61d7)) -## [1.2.7-alpha.1](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.2.6...@trustvc/w3c-vc@1.2.7-alpha.1) (2025-04-09) +## [1.2.15](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.2.14...@trustvc/w3c-vc@1.2.15) (2025-05-21) ### Bug Fixes -* update fetchCredentialStatusVC to use documentLoader ([#46](https://github.com/TrustVC/w3c/issues/46)) ([7fe49f8](https://github.com/TrustVC/w3c/commit/7fe49f8e5a01cf36f4fdd87bccd72f87554a9072)) +* coo context ([#59](https://github.com/TrustVC/w3c/issues/59)) ([b802c6f](https://github.com/TrustVC/w3c/commit/b802c6f8605387024d5a50d81e4edfa3da709ba7)) + +## [1.2.14](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.2.13...@trustvc/w3c-vc@1.2.14) (2025-05-20) + + +### Bug Fixes + +* add template context ([#58](https://github.com/TrustVC/w3c/issues/58)) ([8a467b7](https://github.com/TrustVC/w3c/commit/8a467b738bebe935f00af525684e84bfd01fe6e9)) + +## [1.2.13](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.2.12...@trustvc/w3c-vc@1.2.13) (2025-05-16) + + +### Bug Fixes + +* cli error messages ([#54](https://github.com/TrustVC/w3c/issues/54)) ([3825ce9](https://github.com/TrustVC/w3c/commit/3825ce9598479f52a75b2a8dbd38efc97730950a)) + +## [1.2.12](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.2.11...@trustvc/w3c-vc@1.2.12) (2025-05-14) + + +### Bug Fixes + +* add qrcode context ([#55](https://github.com/TrustVC/w3c/issues/55)) ([19cd0df](https://github.com/TrustVC/w3c/commit/19cd0dfd20e848f744e1a5d6255557bde101d998)) + +## [1.2.11](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.2.10...@trustvc/w3c-vc@1.2.11) (2025-04-24) + + +### Bug Fixes + +* update promissory note context ([#53](https://github.com/TrustVC/w3c/issues/53)) ([e032f45](https://github.com/TrustVC/w3c/commit/e032f4582da0983d2ca5648d7c55fac6bc97c1f6)) + +## [1.2.10](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.2.9...@trustvc/w3c-vc@1.2.10) (2025-04-23) + + +### Bug Fixes + +* add promissory note context for w3c ([#52](https://github.com/TrustVC/w3c/issues/52)) ([54b866a](https://github.com/TrustVC/w3c/commit/54b866a66ff1db2466628fb32a1bb4820d71b7d1)) + +## [1.2.9](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.2.8...@trustvc/w3c-vc@1.2.9) (2025-04-22) + + +### Bug Fixes + +* clean up resolver ([#51](https://github.com/TrustVC/w3c/issues/51)) ([936b5ec](https://github.com/TrustVC/w3c/commit/936b5ec23a372ae441bde9cd99701cbdd2408465)) + +## [1.2.8](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.2.7...@trustvc/w3c-vc@1.2.8) (2025-04-10) + + +### Bug Fixes + +* add bls to context cache ([#50](https://github.com/TrustVC/w3c/issues/50)) ([a1988b0](https://github.com/TrustVC/w3c/commit/a1988b0ef2d82c95c3e285c93eedd61b050e4fd9)) + +## [1.2.7](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.2.6...@trustvc/w3c-vc@1.2.7) (2025-04-09) + + +### Bug Fixes + +* update fetchCredentialStatusVC to use documentLoader and add cache for jws 2020 v1 ([#49](https://github.com/TrustVC/w3c/issues/49)) ([2c50901](https://github.com/TrustVC/w3c/commit/2c50901035aac696f75ef386bd8beca367f02db7)) ## [1.2.6](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.2.5...@trustvc/w3c-vc@1.2.6) (2025-04-08) diff --git a/packages/w3c-vc/package.json b/packages/w3c-vc/package.json index 005f2071..3cb3de55 100644 --- a/packages/w3c-vc/package.json +++ b/packages/w3c-vc/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c-vc", - "version": "1.2.7-alpha.3", + "version": "1.2.17", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", @@ -32,8 +32,8 @@ }, "dependencies": { "@mattrglobal/jsonld-signatures-bbs": "^1.2.0", - "@trustvc/w3c-credential-status": "^1.2.3-alpha.2", - "@trustvc/w3c-issuer": "^1.2.1", + "@trustvc/w3c-credential-status": "^1.2.13", + "@trustvc/w3c-issuer": "^1.2.4", "did-resolver": "^4.1.0", "jsonld": "^6.0.0", "jsonld-signatures": "7.0.0", diff --git a/packages/w3c-vc/src/index.ts b/packages/w3c-vc/src/index.ts index ff29334d..75c05c4d 100644 --- a/packages/w3c-vc/src/index.ts +++ b/packages/w3c-vc/src/index.ts @@ -9,7 +9,8 @@ import { import { getDocumentLoader } from '@trustvc/w3c-context'; export * from './lib/types'; -export { +export type * from './lib/types'; +export type { ContextDocument, DocumentLoader, Document, diff --git a/packages/w3c-vc/src/lib/helper/index.ts b/packages/w3c-vc/src/lib/helper/index.ts index df395f1f..cdfb58da 100644 --- a/packages/w3c-vc/src/lib/helper/index.ts +++ b/packages/w3c-vc/src/lib/helper/index.ts @@ -7,10 +7,11 @@ import { TransferableRecordsCredentialStatus, } from '@trustvc/w3c-credential-status'; import { BBSPrivateKeyPair, PrivateKeyPair, VerificationType } from '@trustvc/w3c-issuer'; +import { createHash } from 'crypto'; // @ts-ignore: No types available for jsonld import * as jsonld from 'jsonld'; import { v7 as uuidv7 } from 'uuid'; -import { assertCredentialStatus } from '../sign/credentialStatus'; +import { assertCredentialStatuses } from '../sign/credentialStatus'; import { CredentialStatus, CredentialSubject, @@ -19,7 +20,6 @@ import { RawVerifiableCredential, VerifiableCredential, } from '../types'; -import { createHash } from 'crypto'; /** * Validates a key pair object to ensure it contains the required properties. @@ -180,7 +180,8 @@ export function _checkCredential( assertDateString({ credential, prop: 'expirationDate' }); if (mode === 'verify') { if (now > new Date(credential.expirationDate)) { - throw new Error('Credential has expired.'); + console.warn('Credential has expired.'); + // throw new Error('Credential has expired.'); } } } @@ -222,9 +223,7 @@ export function _checkCredential( } // Validate credentialStatus field if present - jsonld.getValues(credential, 'credentialStatus').forEach((cs: CredentialStatus) => { - assertCredentialStatus(cs, mode); - }); + assertCredentialStatuses(credential, mode); // Validate that certain fields, if present, are objects with a type property for (const prop of mustHaveType) { diff --git a/packages/w3c-vc/src/lib/sign/credentialStatus/index.ts b/packages/w3c-vc/src/lib/sign/credentialStatus/index.ts index 155da2bd..2a27bf95 100644 --- a/packages/w3c-vc/src/lib/sign/credentialStatus/index.ts +++ b/packages/w3c-vc/src/lib/sign/credentialStatus/index.ts @@ -1,5 +1,7 @@ +// @ts-ignore: No types available for jsonld +import * as jsonld from 'jsonld'; import { _checkCredentialStatus, _validateUriId } from '../../helper'; -import { CredentialStatus } from '../../types'; +import { CredentialStatus, VerifiableCredential } from '../../types'; export const assertCredentialStatus = ( cs: CredentialStatus, @@ -15,3 +17,19 @@ export const assertCredentialStatus = ( _checkCredentialStatus(cs, mode); }; + +export const assertCredentialStatuses = ( + credential: T, + mode: 'sign' | 'verify' = 'verify', +): void => { + const cses = jsonld.getValues(credential, 'credentialStatus'); + cses.forEach((cs: T) => assertCredentialStatus(cs as CredentialStatus, mode)); + if ( + cses.some((cs: CredentialStatus) => cs?.type === 'TransferableRecords') && + credential?.credentialStatus?.type !== 'TransferableRecords' + ) { + throw new Error( + '"credentialStatus" TransferableRecords must be the only credential status and must be an object.', + ); + } +}; diff --git a/packages/w3c-vc/src/lib/types.ts b/packages/w3c-vc/src/lib/types.ts index 00dc1969..8439b906 100644 --- a/packages/w3c-vc/src/lib/types.ts +++ b/packages/w3c-vc/src/lib/types.ts @@ -50,6 +50,7 @@ export type SignedVerifiableCredential = { credentialStatus?: CredentialStatuses; credentialSubject: CredentialSubjects; renderMethod?: Record; + qrCode?: Record; proof?: Proof; } & Record; diff --git a/packages/w3c-vc/src/lib/w3c-vc.test.ts b/packages/w3c-vc/src/lib/w3c-vc.test.ts index 1d9bfc10..b903aee0 100644 --- a/packages/w3c-vc/src/lib/w3c-vc.test.ts +++ b/packages/w3c-vc/src/lib/w3c-vc.test.ts @@ -10,8 +10,13 @@ const modifiedCredential: any = { 'https://trustvc.io/context/transferable-records-context.json', 'https://trustvc.io/context/render-method-context.json', 'https://trustvc.io/context/attachments-context.json', + 'https://trustvc.io/context/qrcode-context.json', 'https://trustvc.io/context/bill-of-lading.json', ], + qrCode: { + type: 'TrustVCQRCode', + uri: 'https://localhost:3000/qrcode', + }, credentialStatus: { type: 'TransferableRecords', tokenNetwork: { @@ -67,6 +72,7 @@ const revealDocument: any = { 'https://trustvc.io/context/transferable-records-context.json', 'https://trustvc.io/context/render-method-context.json', 'https://trustvc.io/context/attachments-context.json', + 'https://trustvc.io/context/qrcode-context.json', 'https://trustvc.io/context/bill-of-lading.json', ], credentialSubject: { diff --git a/packages/w3c-vc/src/lib/w3c-vc.ts b/packages/w3c-vc/src/lib/w3c-vc.ts index 7025350d..bf45d80c 100644 --- a/packages/w3c-vc/src/lib/w3c-vc.ts +++ b/packages/w3c-vc/src/lib/w3c-vc.ts @@ -41,7 +41,9 @@ export const isRawDocument = (document: RawVerifiableCredential | unknown): bool * @param {SignedVerifiableCredential | unknown} document - The signed credential to be checked. * @returns {boolean} - Returns true if the document is a signed credential, false otherwise. */ -export const isSignedDocument = (document: SignedVerifiableCredential | unknown): boolean => { +export const isSignedDocument = ( + document: SignedVerifiableCredential | unknown, +): document is SignedVerifiableCredential => { try { _checkCredential(document, undefined, 'verify'); } catch (err) { diff --git a/packages/w3c/CHANGELOG.md b/packages/w3c/CHANGELOG.md index bb990815..f0136347 100644 --- a/packages/w3c/CHANGELOG.md +++ b/packages/w3c/CHANGELOG.md @@ -1,23 +1,79 @@ -## [1.2.7-alpha.3](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.2.7-alpha.2...@trustvc/w3c@1.2.7-alpha.3) (2025-04-09) +## [1.2.17](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.2.16...@trustvc/w3c@1.2.17) (2025-06-13) ### Bug Fixes -* add cache for jws 2020 v1 ([#48](https://github.com/TrustVC/w3c/issues/48)) ([4a9f52a](https://github.com/TrustVC/w3c/commit/4a9f52a823e5836454c65239916fa5807c9d0be1)) +* expired and redacted doc checks ([#64](https://github.com/TrustVC/w3c/issues/64)) ([4d0a65a](https://github.com/TrustVC/w3c/commit/4d0a65ad467e07bc0f837368f6ff93f84abfb0a8)) -## [1.2.7-alpha.2](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.2.7-alpha.1...@trustvc/w3c@1.2.7-alpha.2) (2025-04-09) +## [1.2.16](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.2.15...@trustvc/w3c@1.2.16) (2025-05-30) ### Bug Fixes -* add export ([#47](https://github.com/TrustVC/w3c/issues/47)) ([dae74e7](https://github.com/TrustVC/w3c/commit/dae74e779e8f26dcd84f63e9baea905d2eca91fc)) +* type errors ([#62](https://github.com/TrustVC/w3c/issues/62)) ([e4cf81f](https://github.com/TrustVC/w3c/commit/e4cf81f4cab187be464f92503bf0f0c39aef61d7)) -## [1.2.7-alpha.1](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.2.6...@trustvc/w3c@1.2.7-alpha.1) (2025-04-09) +## [1.2.15](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.2.14...@trustvc/w3c@1.2.15) (2025-05-21) ### Bug Fixes -* update fetchCredentialStatusVC to use documentLoader ([#46](https://github.com/TrustVC/w3c/issues/46)) ([7fe49f8](https://github.com/TrustVC/w3c/commit/7fe49f8e5a01cf36f4fdd87bccd72f87554a9072)) +* coo context ([#59](https://github.com/TrustVC/w3c/issues/59)) ([b802c6f](https://github.com/TrustVC/w3c/commit/b802c6f8605387024d5a50d81e4edfa3da709ba7)) + +## [1.2.14](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.2.13...@trustvc/w3c@1.2.14) (2025-05-20) + + +### Bug Fixes + +* add template context ([#58](https://github.com/TrustVC/w3c/issues/58)) ([8a467b7](https://github.com/TrustVC/w3c/commit/8a467b738bebe935f00af525684e84bfd01fe6e9)) + +## [1.2.13](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.2.12...@trustvc/w3c@1.2.13) (2025-05-16) + + +### Bug Fixes + +* cli error messages ([#54](https://github.com/TrustVC/w3c/issues/54)) ([3825ce9](https://github.com/TrustVC/w3c/commit/3825ce9598479f52a75b2a8dbd38efc97730950a)) + +## [1.2.12](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.2.11...@trustvc/w3c@1.2.12) (2025-05-14) + + +### Bug Fixes + +* add qrcode context ([#55](https://github.com/TrustVC/w3c/issues/55)) ([19cd0df](https://github.com/TrustVC/w3c/commit/19cd0dfd20e848f744e1a5d6255557bde101d998)) + +## [1.2.11](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.2.10...@trustvc/w3c@1.2.11) (2025-04-24) + + +### Bug Fixes + +* update promissory note context ([#53](https://github.com/TrustVC/w3c/issues/53)) ([e032f45](https://github.com/TrustVC/w3c/commit/e032f4582da0983d2ca5648d7c55fac6bc97c1f6)) + +## [1.2.10](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.2.9...@trustvc/w3c@1.2.10) (2025-04-23) + + +### Bug Fixes + +* add promissory note context for w3c ([#52](https://github.com/TrustVC/w3c/issues/52)) ([54b866a](https://github.com/TrustVC/w3c/commit/54b866a66ff1db2466628fb32a1bb4820d71b7d1)) + +## [1.2.9](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.2.8...@trustvc/w3c@1.2.9) (2025-04-22) + + +### Bug Fixes + +* clean up resolver ([#51](https://github.com/TrustVC/w3c/issues/51)) ([936b5ec](https://github.com/TrustVC/w3c/commit/936b5ec23a372ae441bde9cd99701cbdd2408465)) + +## [1.2.8](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.2.7...@trustvc/w3c@1.2.8) (2025-04-10) + + +### Bug Fixes + +* add bls to context cache ([#50](https://github.com/TrustVC/w3c/issues/50)) ([a1988b0](https://github.com/TrustVC/w3c/commit/a1988b0ef2d82c95c3e285c93eedd61b050e4fd9)) + +## [1.2.7](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.2.6...@trustvc/w3c@1.2.7) (2025-04-09) + + +### Bug Fixes + +* update fetchCredentialStatusVC to use documentLoader and add cache for jws 2020 v1 ([#49](https://github.com/TrustVC/w3c/issues/49)) ([2c50901](https://github.com/TrustVC/w3c/commit/2c50901035aac696f75ef386bd8beca367f02db7)) ## [1.2.6](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.2.5...@trustvc/w3c@1.2.6) (2025-04-08) diff --git a/packages/w3c/package.json b/packages/w3c/package.json index 14730044..391c2fb3 100644 --- a/packages/w3c/package.json +++ b/packages/w3c/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c", - "version": "1.2.7-alpha.3", + "version": "1.2.17", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", @@ -32,10 +32,10 @@ } }, "dependencies": { - "@trustvc/w3c-context": "^1.2.3-alpha.2", - "@trustvc/w3c-credential-status": "^1.2.3-alpha.2", - "@trustvc/w3c-issuer": "^1.2.1", - "@trustvc/w3c-vc": "^1.2.7-alpha.3" + "@trustvc/w3c-context": "^1.2.13", + "@trustvc/w3c-credential-status": "^1.2.13", + "@trustvc/w3c-issuer": "^1.2.4", + "@trustvc/w3c-vc": "^1.2.17" }, "repository": { "type": "git", diff --git a/scripts/copy-files.sh b/scripts/copy-files.sh index bd1274a0..ba0ce714 100644 --- a/scripts/copy-files.sh +++ b/scripts/copy-files.sh @@ -13,12 +13,17 @@ rm -rf ./public mkdir -p "$DEST_DIR" # List of files to copy -FILES=("attachments-context.json" "bill-of-lading.json" "invoice.json" "render-method-context.json" "transferable-records-context.json") +FILES=("attachments-context.json" "bill-of-lading.json" "bill-of-lading-carrier.json" "coo.json" "invoice.json" "promissory-note.json" "qrcode-context.json" "render-method-context.json" "transferable-records-context.json" "warehouse-receipt.json") # Copy each file for FILE in "${FILES[@]}"; do cp "$SOURCE_DIR/$FILE" "$DEST_DIR/" done +echo "[[headers]] + for = \"/*\" + [headers.values] + Access-Control-Allow-Origin = \"*\"" > ./public/netlify.toml + # Optional: output a message when done echo "Files have been copied to $DEST_DIR" From 2511e385cf8d9329355d7b274a36bbad010148e8 Mon Sep 17 00:00:00 2001 From: rongquan1 <85145303+rongquan1@users.noreply.github.com> Date: Fri, 25 Jul 2025 10:35:57 +0800 Subject: [PATCH 018/122] chore: safely rebase alpha on top of main (#66) * fix: update fetchCredentialStatusVC to use documentLoader and add cache for jws 2020 v1 (#49) Co-authored-by: nghaninn * chore(release): @trustvc/w3c-context@1.2.3 [skip ci] ## [1.2.3](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-context@1.2.2...@trustvc/w3c-context@1.2.3) (2025-04-09) ### Bug Fixes * update fetchCredentialStatusVC to use documentLoader and add cache for jws 2020 v1 ([#49](https://github.com/TrustVC/w3c/issues/49)) ([2c50901](https://github.com/TrustVC/w3c/commit/2c50901035aac696f75ef386bd8beca367f02db7)) * chore(release): @trustvc/w3c-credential-status@1.2.3 [skip ci] ## [1.2.3](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-credential-status@1.2.2...@trustvc/w3c-credential-status@1.2.3) (2025-04-09) ### Bug Fixes * update fetchCredentialStatusVC to use documentLoader and add cache for jws 2020 v1 ([#49](https://github.com/TrustVC/w3c/issues/49)) ([2c50901](https://github.com/TrustVC/w3c/commit/2c50901035aac696f75ef386bd8beca367f02db7)) * chore(release): @trustvc/w3c-vc@1.2.7 [skip ci] ## [1.2.7](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.2.6...@trustvc/w3c-vc@1.2.7) (2025-04-09) ### Bug Fixes * update fetchCredentialStatusVC to use documentLoader and add cache for jws 2020 v1 ([#49](https://github.com/TrustVC/w3c/issues/49)) ([2c50901](https://github.com/TrustVC/w3c/commit/2c50901035aac696f75ef386bd8beca367f02db7)) * chore(release): @trustvc/w3c-cli@1.2.7 [skip ci] ## [1.2.7](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-cli@1.2.6...@trustvc/w3c-cli@1.2.7) (2025-04-09) ### Bug Fixes * update fetchCredentialStatusVC to use documentLoader and add cache for jws 2020 v1 ([#49](https://github.com/TrustVC/w3c/issues/49)) ([2c50901](https://github.com/TrustVC/w3c/commit/2c50901035aac696f75ef386bd8beca367f02db7)) * chore(release): @trustvc/w3c@1.2.7 [skip ci] ## [1.2.7](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.2.6...@trustvc/w3c@1.2.7) (2025-04-09) ### Bug Fixes * update fetchCredentialStatusVC to use documentLoader and add cache for jws 2020 v1 ([#49](https://github.com/TrustVC/w3c/issues/49)) ([2c50901](https://github.com/TrustVC/w3c/commit/2c50901035aac696f75ef386bd8beca367f02db7)) * fix: add bls to context cache (#50) * fix: add bls to context cache * fix: update cli error --------- Co-authored-by: nghaninn * chore(release): @trustvc/w3c-context@1.2.4 [skip ci] ## [1.2.4](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-context@1.2.3...@trustvc/w3c-context@1.2.4) (2025-04-10) ### Bug Fixes * add bls to context cache ([#50](https://github.com/TrustVC/w3c/issues/50)) ([a1988b0](https://github.com/TrustVC/w3c/commit/a1988b0ef2d82c95c3e285c93eedd61b050e4fd9)) * chore(release): @trustvc/w3c-credential-status@1.2.4 [skip ci] ## [1.2.4](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-credential-status@1.2.3...@trustvc/w3c-credential-status@1.2.4) (2025-04-10) ### Bug Fixes * add bls to context cache ([#50](https://github.com/TrustVC/w3c/issues/50)) ([a1988b0](https://github.com/TrustVC/w3c/commit/a1988b0ef2d82c95c3e285c93eedd61b050e4fd9)) * chore(release): @trustvc/w3c-vc@1.2.8 [skip ci] ## [1.2.8](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.2.7...@trustvc/w3c-vc@1.2.8) (2025-04-10) ### Bug Fixes * add bls to context cache ([#50](https://github.com/TrustVC/w3c/issues/50)) ([a1988b0](https://github.com/TrustVC/w3c/commit/a1988b0ef2d82c95c3e285c93eedd61b050e4fd9)) * chore(release): @trustvc/w3c-cli@1.2.8 [skip ci] ## [1.2.8](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-cli@1.2.7...@trustvc/w3c-cli@1.2.8) (2025-04-10) ### Bug Fixes * add bls to context cache ([#50](https://github.com/TrustVC/w3c/issues/50)) ([a1988b0](https://github.com/TrustVC/w3c/commit/a1988b0ef2d82c95c3e285c93eedd61b050e4fd9)) * chore(release): @trustvc/w3c@1.2.8 [skip ci] ## [1.2.8](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.2.7...@trustvc/w3c@1.2.8) (2025-04-10) ### Bug Fixes * add bls to context cache ([#50](https://github.com/TrustVC/w3c/issues/50)) ([a1988b0](https://github.com/TrustVC/w3c/commit/a1988b0ef2d82c95c3e285c93eedd61b050e4fd9)) * fix: clean up resolver (#51) Co-authored-by: nghaninn * chore(release): @trustvc/w3c-issuer@1.2.2 [skip ci] ## [1.2.2](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-issuer@1.2.1...@trustvc/w3c-issuer@1.2.2) (2025-04-22) ### Bug Fixes * clean up resolver ([#51](https://github.com/TrustVC/w3c/issues/51)) ([936b5ec](https://github.com/TrustVC/w3c/commit/936b5ec23a372ae441bde9cd99701cbdd2408465)) * chore(release): @trustvc/w3c-context@1.2.5 [skip ci] ## [1.2.5](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-context@1.2.4...@trustvc/w3c-context@1.2.5) (2025-04-22) ### Bug Fixes * clean up resolver ([#51](https://github.com/TrustVC/w3c/issues/51)) ([936b5ec](https://github.com/TrustVC/w3c/commit/936b5ec23a372ae441bde9cd99701cbdd2408465)) * chore(release): @trustvc/w3c-credential-status@1.2.5 [skip ci] ## [1.2.5](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-credential-status@1.2.4...@trustvc/w3c-credential-status@1.2.5) (2025-04-22) ### Bug Fixes * clean up resolver ([#51](https://github.com/TrustVC/w3c/issues/51)) ([936b5ec](https://github.com/TrustVC/w3c/commit/936b5ec23a372ae441bde9cd99701cbdd2408465)) * chore(release): @trustvc/w3c-vc@1.2.9 [skip ci] ## [1.2.9](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.2.8...@trustvc/w3c-vc@1.2.9) (2025-04-22) ### Bug Fixes * clean up resolver ([#51](https://github.com/TrustVC/w3c/issues/51)) ([936b5ec](https://github.com/TrustVC/w3c/commit/936b5ec23a372ae441bde9cd99701cbdd2408465)) * chore(release): @trustvc/w3c-cli@1.2.9 [skip ci] ## [1.2.9](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-cli@1.2.8...@trustvc/w3c-cli@1.2.9) (2025-04-22) ### Bug Fixes * clean up resolver ([#51](https://github.com/TrustVC/w3c/issues/51)) ([936b5ec](https://github.com/TrustVC/w3c/commit/936b5ec23a372ae441bde9cd99701cbdd2408465)) * chore(release): @trustvc/w3c@1.2.9 [skip ci] ## [1.2.9](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.2.8...@trustvc/w3c@1.2.9) (2025-04-22) ### Bug Fixes * clean up resolver ([#51](https://github.com/TrustVC/w3c/issues/51)) ([936b5ec](https://github.com/TrustVC/w3c/commit/936b5ec23a372ae441bde9cd99701cbdd2408465)) * fix: add promissory note context for w3c (#52) * fix: add promissory note context for w3c * fix: add to cache * chore(release): @trustvc/w3c-context@1.2.6 [skip ci] ## [1.2.6](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-context@1.2.5...@trustvc/w3c-context@1.2.6) (2025-04-23) ### Bug Fixes * add promissory note context for w3c ([#52](https://github.com/TrustVC/w3c/issues/52)) ([54b866a](https://github.com/TrustVC/w3c/commit/54b866a66ff1db2466628fb32a1bb4820d71b7d1)) * chore(release): @trustvc/w3c-credential-status@1.2.6 [skip ci] ## [1.2.6](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-credential-status@1.2.5...@trustvc/w3c-credential-status@1.2.6) (2025-04-23) ### Bug Fixes * add promissory note context for w3c ([#52](https://github.com/TrustVC/w3c/issues/52)) ([54b866a](https://github.com/TrustVC/w3c/commit/54b866a66ff1db2466628fb32a1bb4820d71b7d1)) * chore(release): @trustvc/w3c-vc@1.2.10 [skip ci] ## [1.2.10](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.2.9...@trustvc/w3c-vc@1.2.10) (2025-04-23) ### Bug Fixes * add promissory note context for w3c ([#52](https://github.com/TrustVC/w3c/issues/52)) ([54b866a](https://github.com/TrustVC/w3c/commit/54b866a66ff1db2466628fb32a1bb4820d71b7d1)) * chore(release): @trustvc/w3c-cli@1.2.10 [skip ci] ## [1.2.10](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-cli@1.2.9...@trustvc/w3c-cli@1.2.10) (2025-04-23) ### Bug Fixes * add promissory note context for w3c ([#52](https://github.com/TrustVC/w3c/issues/52)) ([54b866a](https://github.com/TrustVC/w3c/commit/54b866a66ff1db2466628fb32a1bb4820d71b7d1)) * chore(release): @trustvc/w3c@1.2.10 [skip ci] ## [1.2.10](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.2.9...@trustvc/w3c@1.2.10) (2025-04-23) ### Bug Fixes * add promissory note context for w3c ([#52](https://github.com/TrustVC/w3c/issues/52)) ([54b866a](https://github.com/TrustVC/w3c/commit/54b866a66ff1db2466628fb32a1bb4820d71b7d1)) * fix: update promissory note context (#53) * chore(release): @trustvc/w3c-context@1.2.7 [skip ci] ## [1.2.7](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-context@1.2.6...@trustvc/w3c-context@1.2.7) (2025-04-24) ### Bug Fixes * update promissory note context ([#53](https://github.com/TrustVC/w3c/issues/53)) ([e032f45](https://github.com/TrustVC/w3c/commit/e032f4582da0983d2ca5648d7c55fac6bc97c1f6)) * chore(release): @trustvc/w3c-credential-status@1.2.7 [skip ci] ## [1.2.7](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-credential-status@1.2.6...@trustvc/w3c-credential-status@1.2.7) (2025-04-24) ### Bug Fixes * update promissory note context ([#53](https://github.com/TrustVC/w3c/issues/53)) ([e032f45](https://github.com/TrustVC/w3c/commit/e032f4582da0983d2ca5648d7c55fac6bc97c1f6)) * chore(release): @trustvc/w3c-vc@1.2.11 [skip ci] ## [1.2.11](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.2.10...@trustvc/w3c-vc@1.2.11) (2025-04-24) ### Bug Fixes * update promissory note context ([#53](https://github.com/TrustVC/w3c/issues/53)) ([e032f45](https://github.com/TrustVC/w3c/commit/e032f4582da0983d2ca5648d7c55fac6bc97c1f6)) * chore(release): @trustvc/w3c-cli@1.2.11 [skip ci] ## [1.2.11](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-cli@1.2.10...@trustvc/w3c-cli@1.2.11) (2025-04-24) ### Bug Fixes * update promissory note context ([#53](https://github.com/TrustVC/w3c/issues/53)) ([e032f45](https://github.com/TrustVC/w3c/commit/e032f4582da0983d2ca5648d7c55fac6bc97c1f6)) * chore(release): @trustvc/w3c@1.2.11 [skip ci] ## [1.2.11](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.2.10...@trustvc/w3c@1.2.11) (2025-04-24) ### Bug Fixes * update promissory note context ([#53](https://github.com/TrustVC/w3c/issues/53)) ([e032f45](https://github.com/TrustVC/w3c/commit/e032f4582da0983d2ca5648d7c55fac6bc97c1f6)) * fix: add qrcode context (#55) * chore(release): @trustvc/w3c-context@1.2.8 [skip ci] ## [1.2.8](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-context@1.2.7...@trustvc/w3c-context@1.2.8) (2025-05-14) ### Bug Fixes * add qrcode context ([#55](https://github.com/TrustVC/w3c/issues/55)) ([19cd0df](https://github.com/TrustVC/w3c/commit/19cd0dfd20e848f744e1a5d6255557bde101d998)) * chore(release): @trustvc/w3c-credential-status@1.2.8 [skip ci] ## [1.2.8](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-credential-status@1.2.7...@trustvc/w3c-credential-status@1.2.8) (2025-05-14) ### Bug Fixes * add qrcode context ([#55](https://github.com/TrustVC/w3c/issues/55)) ([19cd0df](https://github.com/TrustVC/w3c/commit/19cd0dfd20e848f744e1a5d6255557bde101d998)) * chore(release): @trustvc/w3c-vc@1.2.12 [skip ci] ## [1.2.12](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.2.11...@trustvc/w3c-vc@1.2.12) (2025-05-14) ### Bug Fixes * add qrcode context ([#55](https://github.com/TrustVC/w3c/issues/55)) ([19cd0df](https://github.com/TrustVC/w3c/commit/19cd0dfd20e848f744e1a5d6255557bde101d998)) * chore(release): @trustvc/w3c-cli@1.2.12 [skip ci] ## [1.2.12](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-cli@1.2.11...@trustvc/w3c-cli@1.2.12) (2025-05-14) ### Bug Fixes * add qrcode context ([#55](https://github.com/TrustVC/w3c/issues/55)) ([19cd0df](https://github.com/TrustVC/w3c/commit/19cd0dfd20e848f744e1a5d6255557bde101d998)) * chore(release): @trustvc/w3c@1.2.12 [skip ci] ## [1.2.12](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.2.11...@trustvc/w3c@1.2.12) (2025-05-14) ### Bug Fixes * add qrcode context ([#55](https://github.com/TrustVC/w3c/issues/55)) ([19cd0df](https://github.com/TrustVC/w3c/commit/19cd0dfd20e848f744e1a5d6255557bde101d998)) * fix: cli error messages (#54) * fix: cli error messages * test: add test for sign command * ci: test updated ci * test: add test * ci: fix test error * fix: resolve code scan error - js/polynomial-redos * chore: revert changes * chore: revert changes * fix: resolve cors error * fix: resolve script error --------- Co-authored-by: nghaninn * chore(release): @trustvc/w3c-issuer@1.2.3 [skip ci] ## [1.2.3](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-issuer@1.2.2...@trustvc/w3c-issuer@1.2.3) (2025-05-16) ### Bug Fixes * cli error messages ([#54](https://github.com/TrustVC/w3c/issues/54)) ([3825ce9](https://github.com/TrustVC/w3c/commit/3825ce9598479f52a75b2a8dbd38efc97730950a)) * chore(release): @trustvc/w3c-context@1.2.9 [skip ci] ## [1.2.9](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-context@1.2.8...@trustvc/w3c-context@1.2.9) (2025-05-16) ### Bug Fixes * cli error messages ([#54](https://github.com/TrustVC/w3c/issues/54)) ([3825ce9](https://github.com/TrustVC/w3c/commit/3825ce9598479f52a75b2a8dbd38efc97730950a)) * chore(release): @trustvc/w3c-credential-status@1.2.9 [skip ci] ## [1.2.9](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-credential-status@1.2.8...@trustvc/w3c-credential-status@1.2.9) (2025-05-16) ### Bug Fixes * cli error messages ([#54](https://github.com/TrustVC/w3c/issues/54)) ([3825ce9](https://github.com/TrustVC/w3c/commit/3825ce9598479f52a75b2a8dbd38efc97730950a)) * chore(release): @trustvc/w3c-vc@1.2.13 [skip ci] ## [1.2.13](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.2.12...@trustvc/w3c-vc@1.2.13) (2025-05-16) ### Bug Fixes * cli error messages ([#54](https://github.com/TrustVC/w3c/issues/54)) ([3825ce9](https://github.com/TrustVC/w3c/commit/3825ce9598479f52a75b2a8dbd38efc97730950a)) * chore(release): @trustvc/w3c-cli@1.2.13 [skip ci] ## [1.2.13](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-cli@1.2.12...@trustvc/w3c-cli@1.2.13) (2025-05-16) ### Bug Fixes * cli error messages ([#54](https://github.com/TrustVC/w3c/issues/54)) ([3825ce9](https://github.com/TrustVC/w3c/commit/3825ce9598479f52a75b2a8dbd38efc97730950a)) * chore(release): @trustvc/w3c@1.2.13 [skip ci] ## [1.2.13](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.2.12...@trustvc/w3c@1.2.13) (2025-05-16) ### Bug Fixes * cli error messages ([#54](https://github.com/TrustVC/w3c/issues/54)) ([3825ce9](https://github.com/TrustVC/w3c/commit/3825ce9598479f52a75b2a8dbd38efc97730950a)) * chore: fix cors (#56) Co-authored-by: nghaninn * chore: fix cors (#57) * chore: fix cors * chore: attempt to resolve cors --------- Co-authored-by: nghaninn * fix: add template context (#58) * chore(release): @trustvc/w3c-context@1.2.10 [skip ci] ## [1.2.10](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-context@1.2.9...@trustvc/w3c-context@1.2.10) (2025-05-20) ### Bug Fixes * add template context ([#58](https://github.com/TrustVC/w3c/issues/58)) ([8a467b7](https://github.com/TrustVC/w3c/commit/8a467b738bebe935f00af525684e84bfd01fe6e9)) * chore(release): @trustvc/w3c-credential-status@1.2.10 [skip ci] ## [1.2.10](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-credential-status@1.2.9...@trustvc/w3c-credential-status@1.2.10) (2025-05-20) ### Bug Fixes * add template context ([#58](https://github.com/TrustVC/w3c/issues/58)) ([8a467b7](https://github.com/TrustVC/w3c/commit/8a467b738bebe935f00af525684e84bfd01fe6e9)) * chore(release): @trustvc/w3c-vc@1.2.14 [skip ci] ## [1.2.14](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.2.13...@trustvc/w3c-vc@1.2.14) (2025-05-20) ### Bug Fixes * add template context ([#58](https://github.com/TrustVC/w3c/issues/58)) ([8a467b7](https://github.com/TrustVC/w3c/commit/8a467b738bebe935f00af525684e84bfd01fe6e9)) * chore(release): @trustvc/w3c-cli@1.2.14 [skip ci] ## [1.2.14](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-cli@1.2.13...@trustvc/w3c-cli@1.2.14) (2025-05-20) ### Bug Fixes * add template context ([#58](https://github.com/TrustVC/w3c/issues/58)) ([8a467b7](https://github.com/TrustVC/w3c/commit/8a467b738bebe935f00af525684e84bfd01fe6e9)) * chore(release): @trustvc/w3c@1.2.14 [skip ci] ## [1.2.14](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.2.13...@trustvc/w3c@1.2.14) (2025-05-20) ### Bug Fixes * add template context ([#58](https://github.com/TrustVC/w3c/issues/58)) ([8a467b7](https://github.com/TrustVC/w3c/commit/8a467b738bebe935f00af525684e84bfd01fe6e9)) * fix: coo context (#59) * chore(release): @trustvc/w3c-context@1.2.11 [skip ci] ## [1.2.11](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-context@1.2.10...@trustvc/w3c-context@1.2.11) (2025-05-21) ### Bug Fixes * coo context ([#59](https://github.com/TrustVC/w3c/issues/59)) ([b802c6f](https://github.com/TrustVC/w3c/commit/b802c6f8605387024d5a50d81e4edfa3da709ba7)) * chore(release): @trustvc/w3c-credential-status@1.2.11 [skip ci] ## [1.2.11](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-credential-status@1.2.10...@trustvc/w3c-credential-status@1.2.11) (2025-05-21) ### Bug Fixes * coo context ([#59](https://github.com/TrustVC/w3c/issues/59)) ([b802c6f](https://github.com/TrustVC/w3c/commit/b802c6f8605387024d5a50d81e4edfa3da709ba7)) * chore(release): @trustvc/w3c-vc@1.2.15 [skip ci] ## [1.2.15](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.2.14...@trustvc/w3c-vc@1.2.15) (2025-05-21) ### Bug Fixes * coo context ([#59](https://github.com/TrustVC/w3c/issues/59)) ([b802c6f](https://github.com/TrustVC/w3c/commit/b802c6f8605387024d5a50d81e4edfa3da709ba7)) * chore(release): @trustvc/w3c-cli@1.2.15 [skip ci] ## [1.2.15](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-cli@1.2.14...@trustvc/w3c-cli@1.2.15) (2025-05-21) ### Bug Fixes * coo context ([#59](https://github.com/TrustVC/w3c/issues/59)) ([b802c6f](https://github.com/TrustVC/w3c/commit/b802c6f8605387024d5a50d81e4edfa3da709ba7)) * chore(release): @trustvc/w3c@1.2.15 [skip ci] ## [1.2.15](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.2.14...@trustvc/w3c@1.2.15) (2025-05-21) ### Bug Fixes * coo context ([#59](https://github.com/TrustVC/w3c/issues/59)) ([b802c6f](https://github.com/TrustVC/w3c/commit/b802c6f8605387024d5a50d81e4edfa3da709ba7)) * chore: add netlify.toml (#60) Co-authored-by: nghaninn * chore: attempt to fix netlify (#61) Co-authored-by: nghaninn * fix: type errors (#62) Co-authored-by: nghaninn * chore(release): @trustvc/w3c-context@1.2.12 [skip ci] ## [1.2.12](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-context@1.2.11...@trustvc/w3c-context@1.2.12) (2025-05-30) ### Bug Fixes * type errors ([#62](https://github.com/TrustVC/w3c/issues/62)) ([e4cf81f](https://github.com/TrustVC/w3c/commit/e4cf81f4cab187be464f92503bf0f0c39aef61d7)) * chore(release): @trustvc/w3c-credential-status@1.2.12 [skip ci] ## [1.2.12](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-credential-status@1.2.11...@trustvc/w3c-credential-status@1.2.12) (2025-05-30) ### Bug Fixes * type errors ([#62](https://github.com/TrustVC/w3c/issues/62)) ([e4cf81f](https://github.com/TrustVC/w3c/commit/e4cf81f4cab187be464f92503bf0f0c39aef61d7)) * chore(release): @trustvc/w3c-vc@1.2.16 [skip ci] ## [1.2.16](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.2.15...@trustvc/w3c-vc@1.2.16) (2025-05-30) ### Bug Fixes * type errors ([#62](https://github.com/TrustVC/w3c/issues/62)) ([e4cf81f](https://github.com/TrustVC/w3c/commit/e4cf81f4cab187be464f92503bf0f0c39aef61d7)) * chore(release): @trustvc/w3c-cli@1.2.16 [skip ci] ## [1.2.16](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-cli@1.2.15...@trustvc/w3c-cli@1.2.16) (2025-05-30) ### Bug Fixes * type errors ([#62](https://github.com/TrustVC/w3c/issues/62)) ([e4cf81f](https://github.com/TrustVC/w3c/commit/e4cf81f4cab187be464f92503bf0f0c39aef61d7)) * chore(release): @trustvc/w3c@1.2.16 [skip ci] ## [1.2.16](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.2.15...@trustvc/w3c@1.2.16) (2025-05-30) ### Bug Fixes * type errors ([#62](https://github.com/TrustVC/w3c/issues/62)) ([e4cf81f](https://github.com/TrustVC/w3c/commit/e4cf81f4cab187be464f92503bf0f0c39aef61d7)) * fix: cli derive stringify error (#63) Co-authored-by: nghaninn * chore(release): @trustvc/w3c-cli@1.2.17 [skip ci] ## [1.2.17](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-cli@1.2.16...@trustvc/w3c-cli@1.2.17) (2025-06-09) ### Bug Fixes * cli derive stringify error ([#63](https://github.com/TrustVC/w3c/issues/63)) ([79b9f4f](https://github.com/TrustVC/w3c/commit/79b9f4fbafcc498b289c6313d72fb4d78e425203)) * fix: expired and redacted doc checks (#64) * chore(release): @trustvc/w3c-issuer@1.2.4 [skip ci] ## [1.2.4](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-issuer@1.2.3...@trustvc/w3c-issuer@1.2.4) (2025-06-13) ### Bug Fixes * expired and redacted doc checks ([#64](https://github.com/TrustVC/w3c/issues/64)) ([4d0a65a](https://github.com/TrustVC/w3c/commit/4d0a65ad467e07bc0f837368f6ff93f84abfb0a8)) * chore(release): @trustvc/w3c-context@1.2.13 [skip ci] ## [1.2.13](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-context@1.2.12...@trustvc/w3c-context@1.2.13) (2025-06-13) ### Bug Fixes * expired and redacted doc checks ([#64](https://github.com/TrustVC/w3c/issues/64)) ([4d0a65a](https://github.com/TrustVC/w3c/commit/4d0a65ad467e07bc0f837368f6ff93f84abfb0a8)) * chore(release): @trustvc/w3c-credential-status@1.2.13 [skip ci] ## [1.2.13](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-credential-status@1.2.12...@trustvc/w3c-credential-status@1.2.13) (2025-06-13) ### Bug Fixes * expired and redacted doc checks ([#64](https://github.com/TrustVC/w3c/issues/64)) ([4d0a65a](https://github.com/TrustVC/w3c/commit/4d0a65ad467e07bc0f837368f6ff93f84abfb0a8)) * chore(release): @trustvc/w3c-vc@1.2.17 [skip ci] ## [1.2.17](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.2.16...@trustvc/w3c-vc@1.2.17) (2025-06-13) ### Bug Fixes * expired and redacted doc checks ([#64](https://github.com/TrustVC/w3c/issues/64)) ([4d0a65a](https://github.com/TrustVC/w3c/commit/4d0a65ad467e07bc0f837368f6ff93f84abfb0a8)) * chore(release): @trustvc/w3c-cli@1.2.18 [skip ci] ## [1.2.18](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-cli@1.2.17...@trustvc/w3c-cli@1.2.18) (2025-06-13) ### Bug Fixes * expired and redacted doc checks ([#64](https://github.com/TrustVC/w3c/issues/64)) ([4d0a65a](https://github.com/TrustVC/w3c/commit/4d0a65ad467e07bc0f837368f6ff93f84abfb0a8)) * chore(release): @trustvc/w3c@1.2.17 [skip ci] ## [1.2.17](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.2.16...@trustvc/w3c@1.2.17) (2025-06-13) ### Bug Fixes * expired and redacted doc checks ([#64](https://github.com/TrustVC/w3c/issues/64)) ([4d0a65a](https://github.com/TrustVC/w3c/commit/4d0a65ad467e07bc0f837368f6ff93f84abfb0a8)) * chore: add multikey and data integrity support (#65) * fix: add multikey and data integrity support --------- Co-authored-by: Ng Han Inn <43451336+nghaninn@users.noreply.github.com> Co-authored-by: nghaninn Co-authored-by: semantic-release-bot Co-authored-by: RishabhS7 <59636880+RishabhS7@users.noreply.github.com> From 1ad1690d39a003434283df429ebb7c176d4da71a Mon Sep 17 00:00:00 2001 From: rongquan1 <85145303+rongquan1@users.noreply.github.com> Date: Thu, 31 Jul 2025 10:42:00 +0800 Subject: [PATCH 019/122] feat: add bbs-2023 and ecdsa-sd-2023 key generation and did support (#67) * feat: add bbs-2023 and ecdsa-sd-2023 key generation and did support * fix: build issue * fix: refactor test --- apps/w3c-cli/tests/main.test.ts | 37 +++- package-lock.json | 126 +++++++++-- packages/declaration.d.ts | 2 + packages/w3c-credential-status/tsconfig.json | 2 +- packages/w3c-issuer/package.json | 2 + packages/w3c-issuer/src/did-web/README.md | 15 +- .../w3c-issuer/src/did-web/keyPair/bbs2023.ts | 39 ++++ .../src/did-web/keyPair/ecdsaSd2023.ts | 31 +++ .../src/did-web/keyPair/index.test.ts | 83 ++++++- .../w3c-issuer/src/did-web/keyPair/index.ts | 62 ++++-- .../w3c-issuer/src/did-web/keyPair/types.ts | 9 +- .../src/did-web/wellKnown/generate.test.ts | 202 ++++++++++++++++++ .../src/did-web/wellKnown/generate.ts | 17 +- .../src/did-web/wellKnown/index.test.ts | 186 +++++++++++++++- .../w3c-issuer/src/did-web/wellKnown/index.ts | 32 ++- .../w3c-issuer/src/did-web/wellKnown/types.ts | 24 ++- packages/w3c-issuer/src/lib/types.ts | 9 +- packages/w3c-issuer/tsconfig.build.json | 2 +- packages/w3c-issuer/tsconfig.json | 2 +- packages/w3c-vc/tsconfig.json | 2 +- packages/w3c/tsconfig.json | 2 +- 21 files changed, 819 insertions(+), 67 deletions(-) create mode 100644 packages/declaration.d.ts create mode 100644 packages/w3c-issuer/src/did-web/keyPair/bbs2023.ts create mode 100644 packages/w3c-issuer/src/did-web/keyPair/ecdsaSd2023.ts diff --git a/apps/w3c-cli/tests/main.test.ts b/apps/w3c-cli/tests/main.test.ts index bf61fbe7..f7bc21e4 100644 --- a/apps/w3c-cli/tests/main.test.ts +++ b/apps/w3c-cli/tests/main.test.ts @@ -291,6 +291,39 @@ describe('w3c-cli', () => { true, ); + // Mock the issueDID function to return expected structure + issueDIDSpy.mockResolvedValue({ + wellKnownDid: { + '@context': [ + 'https://www.w3.org/ns/did/v1', + 'https://w3id.org/security/suites/bls12381-2020/v1', + ], + assertionMethod: ['did:web:example.com#keys-1'], + authentication: ['did:web:example.com#keys-1'], + capabilityDelegation: ['did:web:example.com#keys-1'], + capabilityInvocation: ['did:web:example.com#keys-1'], + id: 'did:web:example.com', + verificationMethod: [ + { + controller: 'did:web:example.com', + id: 'did:web:example.com#keys-1', + publicKeyBase58: + 'oRfEeWFresvhRtXCkihZbxyoi2JER7gHTJ5psXhHsdCoU1MttRMi3Yp9b9fpjmKh7bMgfWKLESiK2YovRd8KGzJsGuamoAXfqDDVhckxuc9nmsJ84skCSTijKeU4pfAcxeJ', + type: w3cIssuer.VerificationType.Bls12381G2Key2020, + }, + ], + }, + didKeyPairs: { + controller: 'did:web:example.com', + id: 'did:web:example.com#keys-1', + privateKeyBase58: '4LDU56PUhA9ZEutnR1qCWQnUhtLtpLu2EHSq4h1o7vtF', + publicKeyBase58: + 'oRfEeWFresvhRtXCkihZbxyoi2JER7gHTJ5psXhHsdCoU1MttRMi3Yp9b9fpjmKh7bMgfWKLESiK2YovRd8KGzJsGuamoAXfqDDVhckxuc9nmsJ84skCSTijKeU4pfAcxeJ', + seedBase58: 'GWP69tmSWJjqC1RoJ27FehcVqkVyeYAz6h5ABwoNSNdS', + type: w3cIssuer.VerificationType.Bls12381G2Key2020, + }, + }); + await didHandler(); expect(issueDIDSpy).toHaveBeenCalledWith( @@ -312,7 +345,7 @@ describe('w3c-cli', () => { id: 'did:web:example.com#keys-1', publicKeyBase58: 'oRfEeWFresvhRtXCkihZbxyoi2JER7gHTJ5psXhHsdCoU1MttRMi3Yp9b9fpjmKh7bMgfWKLESiK2YovRd8KGzJsGuamoAXfqDDVhckxuc9nmsJ84skCSTijKeU4pfAcxeJ', - type: 'Bls12381G2Key2020', + type: w3cIssuer.VerificationType.Bls12381G2Key2020, }, ], }); @@ -323,7 +356,7 @@ describe('w3c-cli', () => { publicKeyBase58: 'oRfEeWFresvhRtXCkihZbxyoi2JER7gHTJ5psXhHsdCoU1MttRMi3Yp9b9fpjmKh7bMgfWKLESiK2YovRd8KGzJsGuamoAXfqDDVhckxuc9nmsJ84skCSTijKeU4pfAcxeJ', seedBase58: 'GWP69tmSWJjqC1RoJ27FehcVqkVyeYAz6h5ABwoNSNdS', - type: 'Bls12381G2Key2020', + type: w3cIssuer.VerificationType.Bls12381G2Key2020, }); }); diff --git a/package-lock.json b/package-lock.json index e781c678..5eb86913 100644 --- a/package-lock.json +++ b/package-lock.json @@ -116,14 +116,14 @@ }, "apps/w3c-cli": { "name": "@trustvc/w3c-cli", - "version": "1.2.17", + "version": "1.2.18", "license": "Apache-2.0", "dependencies": { "@inquirer/prompts": "^5.3.8", - "@trustvc/w3c-context": "^1.2.12", - "@trustvc/w3c-credential-status": "^1.2.12", - "@trustvc/w3c-issuer": "^1.2.3", - "@trustvc/w3c-vc": "^1.2.16", + "@trustvc/w3c-context": "^1.2.13", + "@trustvc/w3c-credential-status": "^1.2.13", + "@trustvc/w3c-issuer": "^1.2.4", + "@trustvc/w3c-vc": "^1.2.17", "@types/yargs": "^17.0.32", "chalk": "^4.1.2", "inquirer": "^10.0.1", @@ -2749,6 +2749,31 @@ "uuid": "dist/bin/uuid" } }, + "node_modules/@digitalbazaar/bbs-signatures": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@digitalbazaar/bbs-signatures/-/bbs-signatures-3.0.0.tgz", + "integrity": "sha512-mQMCMnCWAraVSswJg1kJK/qmUrb3jMoWB9c8kOmztsWfnMZJcyYAcavuF8jgrVZ5cl/ZRNMK61ZbIvkqd6BE6g==", + "dependencies": { + "@noble/curves": "^1.3.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@digitalbazaar/bbs-signatures/node_modules/@noble/curves": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.4.tgz", + "integrity": "sha512-2bKONnuM53lINoDrSmK8qP8W271ms7pygDhZt4SiLOoLwBtoHqeCFi6RG42V8zd3mLHuJFhU/Bmaqo4nX0/kBw==", + "dependencies": { + "@noble/hashes": "1.8.0" + }, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@digitalbazaar/bitstring": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/@digitalbazaar/bitstring/-/bitstring-3.1.0.tgz", @@ -2761,11 +2786,52 @@ "node": ">=16" } }, + "node_modules/@digitalbazaar/bls12-381-multikey": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@digitalbazaar/bls12-381-multikey/-/bls12-381-multikey-2.1.0.tgz", + "integrity": "sha512-JelU85fNhvHl2/mqRdmrtrE2ZQJ0//+UwI0l/YFmvsOr6YN2GuKPzdkfXjpm7f3UvnBqz5f8QKFTb9mVa7mVVg==", + "dependencies": { + "@digitalbazaar/bbs-signatures": "^3.0.0", + "@noble/curves": "^1.3.0", + "base58-universal": "^2.0.0", + "base64url-universal": "^2.0.0", + "cborg": "^4.2.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@digitalbazaar/bls12-381-multikey/node_modules/@noble/curves": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.4.tgz", + "integrity": "sha512-2bKONnuM53lINoDrSmK8qP8W271ms7pygDhZt4SiLOoLwBtoHqeCFi6RG42V8zd3mLHuJFhU/Bmaqo4nX0/kBw==", + "dependencies": { + "@noble/hashes": "1.8.0" + }, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@digitalbazaar/credentials-context": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/@digitalbazaar/credentials-context/-/credentials-context-3.1.0.tgz", "integrity": "sha512-VKflyFbcid6xH3FJMrd8U9DeCjbYXa2aO3l8yy7MzP6O/0v0EZTV56hMfJT5fN6TSVtQmShv2R3oPCFqFbc2Tg==" }, + "node_modules/@digitalbazaar/ecdsa-multikey": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@digitalbazaar/ecdsa-multikey/-/ecdsa-multikey-1.8.0.tgz", + "integrity": "sha512-Xo4oBCb0bJv6PYNBrLBZfR/jA2uNd9Bi+YTnadFtxTbhMQrSN0nTw3OnTBOOC7zxtL3t4N00ZweQM4zhsV6gVQ==", + "dependencies": { + "base58-universal": "^2.0.0", + "base64url-universal": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/@digitalbazaar/http-client": { "version": "3.4.1", "resolved": "https://registry.npmjs.org/@digitalbazaar/http-client/-/http-client-3.4.1.tgz", @@ -4761,9 +4827,9 @@ } }, "node_modules/@noble/hashes": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.5.0.tgz", - "integrity": "sha512-1j6kQFb7QRru7eKN3ZDvRcP13rugwdxZqCjbiAVZfIJwgj2A65UmT4TgARXGlXgnRkORLTDTrO19ZErt7+QXgA==", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", "engines": { "node": "^14.21.3 || >=16" }, @@ -12393,6 +12459,14 @@ "node": ">=0.10.0" } }, + "node_modules/base58-universal": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base58-universal/-/base58-universal-2.0.0.tgz", + "integrity": "sha512-BgkgF8zVLOAygszG4W8NkLm7iXrw80VYAOcedrzANrIhS14+4W6zVqjyGTFUBM/FpqkHUt8aAYd4DbBBfn3zKg==", + "engines": { + "node": ">=14" + } + }, "node_modules/base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", @@ -12838,6 +12912,14 @@ "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", "dev": true }, + "node_modules/cborg": { + "version": "4.2.12", + "resolved": "https://registry.npmjs.org/cborg/-/cborg-4.2.12.tgz", + "integrity": "sha512-z126yLoavS75cdTuiKu61RC3Y3trqtDAgQRa5Q0dpHn1RmqhIedptWXKnk0lQ5yo/GmcV9myvIkzFgZ8GnqSog==", + "bin": { + "cborg": "lib/bin.js" + } + }, "node_modules/chai": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/chai/-/chai-4.5.0.tgz", @@ -32587,13 +32669,13 @@ }, "packages/w3c": { "name": "@trustvc/w3c", - "version": "1.2.16", + "version": "1.2.17", "license": "Apache-2.0", "dependencies": { - "@trustvc/w3c-context": "^1.2.12", - "@trustvc/w3c-credential-status": "^1.2.12", - "@trustvc/w3c-issuer": "^1.2.3", - "@trustvc/w3c-vc": "^1.2.16" + "@trustvc/w3c-context": "^1.2.13", + "@trustvc/w3c-credential-status": "^1.2.13", + "@trustvc/w3c-issuer": "^1.2.4", + "@trustvc/w3c-vc": "^1.2.17" }, "engines": { "node": ">=18.x" @@ -32601,7 +32683,7 @@ }, "packages/w3c-context": { "name": "@trustvc/w3c-context", - "version": "1.2.12", + "version": "1.2.13", "license": "Apache-2.0", "dependencies": { "did-resolver": "^4.1.0", @@ -32613,11 +32695,11 @@ }, "packages/w3c-credential-status": { "name": "@trustvc/w3c-credential-status", - "version": "1.2.12", + "version": "1.2.13", "license": "Apache-2.0", "dependencies": { - "@trustvc/w3c-context": "^1.2.12", - "@trustvc/w3c-issuer": "^1.2.3", + "@trustvc/w3c-context": "^1.2.13", + "@trustvc/w3c-issuer": "^1.2.4", "base64url-universal": "^2.0.0", "pako": "^2.1.0" }, @@ -32627,9 +32709,11 @@ }, "packages/w3c-issuer": { "name": "@trustvc/w3c-issuer", - "version": "1.2.3", + "version": "1.2.4", "license": "Apache-2.0", "dependencies": { + "@digitalbazaar/bls12-381-multikey": "^2.1.0", + "@digitalbazaar/ecdsa-multikey": "^1.8.0", "@mattrglobal/bls12381-key-pair": "^1.2.1", "bip39": "^3.1.0", "did-resolver": "^4.1.0", @@ -32642,12 +32726,12 @@ }, "packages/w3c-vc": { "name": "@trustvc/w3c-vc", - "version": "1.2.16", + "version": "1.2.17", "license": "Apache-2.0", "dependencies": { "@mattrglobal/jsonld-signatures-bbs": "^1.2.0", - "@trustvc/w3c-credential-status": "^1.2.12", - "@trustvc/w3c-issuer": "^1.2.3", + "@trustvc/w3c-credential-status": "^1.2.13", + "@trustvc/w3c-issuer": "^1.2.4", "did-resolver": "^4.1.0", "jsonld": "^6.0.0", "jsonld-signatures": "7.0.0", diff --git a/packages/declaration.d.ts b/packages/declaration.d.ts new file mode 100644 index 00000000..a0939395 --- /dev/null +++ b/packages/declaration.d.ts @@ -0,0 +1,2 @@ +declare module '@digitalbazaar/bls12-381-multikey'; +declare module '@digitalbazaar/ecdsa-multikey'; diff --git a/packages/w3c-credential-status/tsconfig.json b/packages/w3c-credential-status/tsconfig.json index d19c6f7a..7de45906 100644 --- a/packages/w3c-credential-status/tsconfig.json +++ b/packages/w3c-credential-status/tsconfig.json @@ -2,5 +2,5 @@ "extends": "../../tsconfig.base.json", "compilerOptions": { }, - "include": ["src/**/*"] + "include": ["src/**/*", "../declaration.d.ts"] } diff --git a/packages/w3c-issuer/package.json b/packages/w3c-issuer/package.json index c4e6a54f..148fbd2d 100644 --- a/packages/w3c-issuer/package.json +++ b/packages/w3c-issuer/package.json @@ -29,6 +29,8 @@ } }, "dependencies": { + "@digitalbazaar/bls12-381-multikey": "^2.1.0", + "@digitalbazaar/ecdsa-multikey": "^1.8.0", "@mattrglobal/bls12381-key-pair": "^1.2.1", "bip39": "^3.1.0", "did-resolver": "^4.1.0", diff --git a/packages/w3c-issuer/src/did-web/README.md b/packages/w3c-issuer/src/did-web/README.md index bd380a4d..00b1023b 100644 --- a/packages/w3c-issuer/src/did-web/README.md +++ b/packages/w3c-issuer/src/did-web/README.md @@ -21,22 +21,27 @@ This guide explains how to self-host a Decentralized Identifier (DID) using the ## Step-by-Step Setup ### 1. Generate DID Document - **Use [`TrustVC W3C Issuer`](../../README.md) to generate your DID Document**: Our tool simplifies the process of creating a compliant DID Document. -- **Review your DID Document**: Ensure the generated file contains the required properties, such as `id`, `verificationMethod`, and `authentication`. Here's an example using the `BbsBlsSignature2020` verification method: +- **Review your DID Document**: Ensure the generated file contains the required properties, such as `id`, `verificationMethod`, and `authentication`. Here's an example using the modern `Multikey` verification method with ECDSA-SD-2023: ```json { - "@context": "https://www.w3.org/ns/did/v1", + "@context": [ + "https://www.w3.org/ns/did/v1", + "https://w3id.org/security/multikey/v1" + ], "id": "did:web:yourdomain.com", "verificationMethod": [{ "id": "did:web:yourdomain.com#key-1", - "type": "BbsBlsSignature2020", + "type": "Multikey", "controller": "did:web:yourdomain.com", - "publicKeyBase58": "2qz8jVcPgs6xzL5mZHTZGkXQaDe5BsVofLpqqBfAw1Nc" + "publicKeyMultibase": "zDnaekGZTbQBerwcehBSXLqAg6s55hVEBms1zFy89VHXtJSa9" }], "authentication": [ "did:web:yourdomain.com#key-1" + ], + "assertionMethod": [ + "did:web:yourdomain.com#key-1" ] } - ``` - **Save the document** as `did.json`. ### 2. Host DID Document diff --git a/packages/w3c-issuer/src/did-web/keyPair/bbs2023.ts b/packages/w3c-issuer/src/did-web/keyPair/bbs2023.ts new file mode 100644 index 00000000..bc2a3d1f --- /dev/null +++ b/packages/w3c-issuer/src/did-web/keyPair/bbs2023.ts @@ -0,0 +1,39 @@ +import * as Bls12381Multikey from '@digitalbazaar/bls12-381-multikey'; +import { base58btc } from 'multiformats/bases/base58'; +import { DidWebGeneratedKeyPair, DidWebGenerateKeyPairOptions } from './types'; +import { VerificationType } from '../../lib/types'; + +/** + * Generate BBS-2023 key pair using Bls12381Multikey. + * + * @param {DidWebGenerateKeyPairOptions} options - Options for key pair generation + * @returns {Promise} - Generated BBS-2023 key pair + */ +export const generateBbs2023KeyPair = async ({ + seed, +}: DidWebGenerateKeyPairOptions): Promise => { + if (!seed) { + throw new Error('Invalid seed'); + } + + // Generate BBS key pair using the new BBS-2023 algorithm + const bbsKeyPair = await Bls12381Multikey.generateBbsKeyPair({ + algorithm: 'BBS-BLS12-381-SHA-256', + seed, + }); + + // Export the key pair to get multibase-encoded keys + const exportedKeys = await bbsKeyPair.export({ + publicKey: true, + secretKey: true, + }); + + const keyPair: DidWebGeneratedKeyPair = { + type: VerificationType.Multikey, + seedBase58: base58btc.encode(seed).slice(1), + secretKeyMultibase: exportedKeys.secretKeyMultibase, + publicKeyMultibase: exportedKeys.publicKeyMultibase, + }; + + return keyPair; +}; diff --git a/packages/w3c-issuer/src/did-web/keyPair/ecdsaSd2023.ts b/packages/w3c-issuer/src/did-web/keyPair/ecdsaSd2023.ts new file mode 100644 index 00000000..d41126d0 --- /dev/null +++ b/packages/w3c-issuer/src/did-web/keyPair/ecdsaSd2023.ts @@ -0,0 +1,31 @@ +import * as EcdsaMultikey from '@digitalbazaar/ecdsa-multikey'; +import { DidWebGeneratedKeyPair } from './types'; +import { VerificationType } from '../../lib/types'; + +/** + * Generate ECDSA-SD-2023 key pair using EcdsaMultikey. + * Note: ECDSA key generation does not support deterministic seed-based generation. + * Keys are generated randomly using secure cryptographic methods. + * + * @returns {Promise} - Generated ECDSA-SD-2023 key pair + */ +export const generateEcdsaSd2023KeyPair = async (): Promise => { + // Generate ECDSA key pair using P-256 curve for ECDSA-SD-2023 + const ecdsaKeyPair = await EcdsaMultikey.generate({ + curve: 'P-256', + }); + + // Export the key pair to get multibase-encoded keys + const exportedKeys = await ecdsaKeyPair.export({ + publicKey: true, + secretKey: true, + }); + + const keyPair: DidWebGeneratedKeyPair = { + type: VerificationType.Multikey, + secretKeyMultibase: exportedKeys.secretKeyMultibase, + publicKeyMultibase: exportedKeys.publicKeyMultibase, + }; + + return keyPair; +}; diff --git a/packages/w3c-issuer/src/did-web/keyPair/index.test.ts b/packages/w3c-issuer/src/did-web/keyPair/index.test.ts index e960cb27..fa944124 100644 --- a/packages/w3c-issuer/src/did-web/keyPair/index.test.ts +++ b/packages/w3c-issuer/src/did-web/keyPair/index.test.ts @@ -1,7 +1,8 @@ import { omit } from 'lodash'; import { describe, expect, it } from 'vitest'; import { generateKeyPair } from './index'; -import { VerificationType } from '../../lib/types'; +import { CryptoSuite, VerificationType } from '../../lib/types'; + describe('keyPair', () => { const seedBase58 = 'CxBwAH4ftdc9XkLhw7DkFAESxh3NEdetMyJXKrPiAKAX'; const privateKeyBase58 = '7e1VnFeqvMjqoq61qhGE2dgnQmgNDAYEX1FGzwywf2h7'; @@ -10,7 +11,7 @@ describe('keyPair', () => { const invalidPublicKeyBase58 = 'invalidPublicKeyBase58'; const invalidPrivateKeyBase58 = 'invalidPrivateKeyBase58'; - describe('generateKeyPair', () => { + describe('Legacy BLS12-381 Key Generation', () => { it('should fail to generateKeyPair without any input', async () => { await expect(generateKeyPair({} as any)).rejects.toThrowError('Invalid key pair type'); }); @@ -116,4 +117,82 @@ describe('keyPair', () => { ).rejects.toThrowError('Public key does not match'); }); }); + + describe('BBS2023 Key Generation', () => { + it('should generateKeyPair with BBS2023 type', async () => { + const keyPair = await generateKeyPair({ type: CryptoSuite.Bbs2023 }); + expect(keyPair.type).toBe('Multikey'); + expect(typeof keyPair.secretKeyMultibase).toBe('string'); + expect(keyPair.secretKeyMultibase?.length).toBeGreaterThan(1); + expect(typeof keyPair.publicKeyMultibase).toBe('string'); + expect(keyPair.publicKeyMultibase?.length).toBeGreaterThan(1); + // BBS-2023 keys should be multibase encoded (BLS12-381 format) + expect(keyPair.secretKeyMultibase).toMatch(/^z/); + expect(keyPair.publicKeyMultibase).toMatch(/^zUC/); + }); + + it('should generateKeyPair with BBS2023 type and seed', async () => { + const keyPair = await generateKeyPair({ + type: CryptoSuite.Bbs2023, + seedBase58, + }); + + expect(keyPair.type).toBe('Multikey'); + expect(keyPair.seedBase58).toBe(seedBase58); + expect(typeof keyPair.secretKeyMultibase).toBe('string'); + expect(keyPair.secretKeyMultibase?.length).toBeGreaterThan(1); + expect(typeof keyPair.publicKeyMultibase).toBe('string'); + expect(keyPair.publicKeyMultibase?.length).toBeGreaterThan(1); + // BBS-2023 keys should be multibase encoded (BLS12-381 format) + expect(keyPair.secretKeyMultibase).toMatch(/^z/); + expect(keyPair.publicKeyMultibase).toMatch(/^zUC/); + }); + + it('should generate deterministic BBS2023 keys with same seed', async () => { + const keyPair1 = await generateKeyPair({ + type: CryptoSuite.Bbs2023, + seedBase58, + }); + + const keyPair2 = await generateKeyPair({ + type: CryptoSuite.Bbs2023, + seedBase58, + }); + + expect(keyPair1.secretKeyMultibase).toBe(keyPair2.secretKeyMultibase); + expect(keyPair1.publicKeyMultibase).toBe(keyPair2.publicKeyMultibase); + expect(keyPair1.seedBase58).toBe(keyPair2.seedBase58); + }); + }); + + describe('ECDSASD2023 Key Generation', () => { + it('should generate ECDSASD2023 key pair without seed', async () => { + const keyPair = await generateKeyPair({ + type: CryptoSuite.EcdsaSd2023, + }); + + expect(keyPair.type).toBe('Multikey'); + expect(typeof keyPair.secretKeyMultibase).toBe('string'); + expect(keyPair.secretKeyMultibase?.length).toBeGreaterThan(1); + expect(typeof keyPair.publicKeyMultibase).toBe('string'); + expect(keyPair.publicKeyMultibase?.length).toBeGreaterThan(1); + // Keys should be multibase encoded (start with 'z') + expect(keyPair.secretKeyMultibase).toMatch(/^z/); + expect(keyPair.publicKeyMultibase).toMatch(/^zDn/); + }); + + it('should generate different ECDSASD2023 keys on each call', async () => { + const keyPair1 = await generateKeyPair({ + type: CryptoSuite.EcdsaSd2023, + }); + + const keyPair2 = await generateKeyPair({ + type: CryptoSuite.EcdsaSd2023, + }); + + // ECDSA-SD-2023 keys are random - should be different each time + expect(keyPair1.secretKeyMultibase).not.toBe(keyPair2.secretKeyMultibase); + expect(keyPair1.publicKeyMultibase).not.toBe(keyPair2.publicKeyMultibase); + }); + }); }); diff --git a/packages/w3c-issuer/src/did-web/keyPair/index.ts b/packages/w3c-issuer/src/did-web/keyPair/index.ts index abe36266..605ae15f 100644 --- a/packages/w3c-issuer/src/did-web/keyPair/index.ts +++ b/packages/w3c-issuer/src/did-web/keyPair/index.ts @@ -1,8 +1,32 @@ import crypto from 'crypto'; import { parseMultibase } from '../../lib'; -import { GeneratedKeyPair, GenerateKeyPairOptions, VerificationType } from '../../lib/types'; +import { + CryptoSuite, + GeneratedKeyPair, + GenerateKeyPairOptions, + VerificationType, +} from '../../lib/types'; import { generateBls12381KeyPair } from './bls12381'; import { DidWebGeneratedKeyPair } from './types'; +import { generateBbs2023KeyPair } from './bbs2023'; +import { generateEcdsaSd2023KeyPair } from './ecdsaSd2023'; + +/** + * Generate modern cryptosuite key pair (BBS-2023 or ECDSA-SD-2023) + */ +const generateModernCryptosuite = async ( + type: CryptoSuite, + keyPairOptions: GenerateKeyPairOptions, +): Promise => { + switch (type) { + case CryptoSuite.Bbs2023: + return await generateBbs2023KeyPair(keyPairOptions); + case CryptoSuite.EcdsaSd2023: + return await generateEcdsaSd2023KeyPair(); + default: + throw new Error(`Unsupported modern cryptosuite: ${type}`); + } +}; /** * Generate key pair based on the type. @@ -10,7 +34,7 @@ import { DidWebGeneratedKeyPair } from './types'; * If private key and public key are provided, it will be verified against the generated seed's key pair. * * @param {GenerateKeyPairOptions} keyPairOptions - * @param {VerificationType} keyPairOptions.type - Type of key pair to generate, supported types are Bls12381G2Key2020 and EcdsaSecp256k1RecoveryMethod2020 + * @param {VerificationType} keyPairOptions.type - Type of key pair to generate, supported types are Bls12381G2Key2020, Multikey, and EcdsaSecp256k1RecoveryMethod2020 * * @param {string} keyPairOptions.seedBase58 - Seed in base58 format (optional) * @param {string} keyPairOptions.privateKeyBase58 - Private key in base58 format (optional) @@ -33,7 +57,13 @@ export const generateKeyPair = async ( let seed: Uint8Array | undefined; - if (type !== VerificationType.EcdsaSecp256k1RecoveryMethod2020) { + // Only prepare seed for types that actually support/use seeds + const seedSupportedTypes: (VerificationType | CryptoSuite)[] = [ + VerificationType.Bls12381G2Key2020, // Legacy BLS + CryptoSuite.Bbs2023, // Modern BBS-2023 + ]; + + if (seedSupportedTypes.includes(type)) { if (seedBase58) { seed = await parseMultibase('z' + seedBase58); } @@ -42,18 +72,24 @@ export const generateKeyPair = async ( let generatedKeyPair: GeneratedKeyPair; - switch (type) { - case VerificationType.Ed25519VerificationKey2018: - throw new Error('Unsupported key pair type'); - case VerificationType.Bls12381G2Key2020: - generatedKeyPair = await generateBls12381KeyPair(keyPairOptions); - break; - default: - throw new Error('Unsupported key pair type'); + // Check if it's a modern cryptosuite + if (Object.values(CryptoSuite).includes(type as CryptoSuite)) { + generatedKeyPair = await generateModernCryptosuite(type as CryptoSuite, keyPairOptions); + } else { + // Legacy key pair generation + switch (type) { + case VerificationType.Ed25519VerificationKey2018: + throw new Error('Unsupported key pair type'); + case VerificationType.Bls12381G2Key2020: + generatedKeyPair = await generateBls12381KeyPair(keyPairOptions); + break; + default: + throw new Error('Unsupported key pair type'); + } } - // If seed is provided, check against provided private key and public key - if (seedBase58) { + // If seed is provided, validate against provided keys (legacy format only) + if (seedBase58 && type === VerificationType.Bls12381G2Key2020) { generatedKeyPair = generatedKeyPair as DidWebGeneratedKeyPair; if (privateKeyBase58 && privateKeyBase58 !== generatedKeyPair.privateKeyBase58) { throw new Error('Private key does not match'); diff --git a/packages/w3c-issuer/src/did-web/keyPair/types.ts b/packages/w3c-issuer/src/did-web/keyPair/types.ts index da7dee05..0ff40d91 100644 --- a/packages/w3c-issuer/src/did-web/keyPair/types.ts +++ b/packages/w3c-issuer/src/did-web/keyPair/types.ts @@ -5,11 +5,18 @@ export type DidWebGenerateKeyPairOptions = BaseKeyPair & { seedBase58?: string; privateKeyBase58?: string; publicKeyBase58?: string; + secretKeyMultibase?: string; + publicKeyMultibase?: string; }; export type DidWebGeneratedKeyPair = Pick< DidWebGenerateKeyPairOptions, - 'type' | 'seedBase58' | 'privateKeyBase58' | 'publicKeyBase58' + | 'type' + | 'seedBase58' + | 'privateKeyBase58' + | 'publicKeyBase58' + | 'secretKeyMultibase' + | 'publicKeyMultibase' > & { seed?: Uint8Array; privateKey?: Uint8Array; diff --git a/packages/w3c-issuer/src/did-web/wellKnown/generate.test.ts b/packages/w3c-issuer/src/did-web/wellKnown/generate.test.ts index 71bc3997..3703b086 100644 --- a/packages/w3c-issuer/src/did-web/wellKnown/generate.test.ts +++ b/packages/w3c-issuer/src/did-web/wellKnown/generate.test.ts @@ -217,6 +217,208 @@ describe('generate', () => { ).toThrowError('KeyPair already exists'); }); }); + + describe('generateWellKnownDid - BBS-2023', () => { + const keyPair = { + id: 'did:web:localhost.com#keys-3', + type: VerificationType.Multikey, + controller: 'did:web:localhost.com', + seedBase58: 'CxBwAH4ftdc9XkLhw7DkFAESxh3NEdetMyJXKrPiAKAX', + secretKeyMultibase: 'z42twTcNeSYcnqg1FLuSFs2bsGH3ZqbRHFmvS9XMsYhjxvHN', + publicKeyMultibase: + 'zUC724qx4TSVn1zuJAjbaPAzwMhNvjHXvJrg36gEtNjQoKSVqZpG7QfVgsUsV2WrNvTB2p41iF2ZtVruDtwjMtZnyHCFGQov', + }; + const verificationMethod = _.omit(keyPair, ['seedBase58', 'secretKeyMultibase']); + + it('should generateWellKnownDid with BBS-2023 keyPair', async () => { + const result = generateWellKnownDid({ + newKeyPair: keyPair, + }); + + expect(result).toBeTruthy(); + expect(result?.id).toBe(keyPair.controller); + expect(result).toHaveProperty('id'); + expect(result).toHaveProperty('verificationMethod'); + expect(result).toHaveProperty('@context'); + expect(result).toHaveProperty('assertionMethod'); + expect(result).toHaveProperty('authentication'); + expect(result).toHaveProperty('capabilityInvocation'); + expect(result).toHaveProperty('capabilityDelegation'); + expect(result?.verificationMethod?.[0]).toMatchObject(verificationMethod); + expect(result?.verificationMethod?.[0].type).toBe('Multikey'); + expect(result?.['@context']).toContain('https://www.w3.org/ns/did/v1'); + expect(result?.['@context']).toContain(VerificationContext[VerificationType.Multikey]); + }); + + it('should generateWellKnownDid with BBS-2023 keyPair and wellKnown', async () => { + const result = generateWellKnownDid({ + wellKnown: wellKnown, + newKeyPair: keyPair, + }); + + expect(result).toBeTruthy(); + expect(result?.id).toBe(keyPair.controller); + expect(result).toHaveProperty('id'); + expect(result).toHaveProperty('verificationMethod'); + expect(result).toHaveProperty('@context'); + expect(result).toHaveProperty('assertionMethod'); + expect(result).toHaveProperty('authentication'); + expect(result).toHaveProperty('capabilityInvocation'); + expect(result).toHaveProperty('capabilityDelegation'); + expect(result?.verificationMethod).toHaveLength(3); + expect(result?.verificationMethod?.[result?.verificationMethod?.length - 1]).toMatchObject( + verificationMethod, + ); + expect(result?.['@context']).toContain('https://www.w3.org/ns/did/v1'); + expect(result?.['@context']).toContain(VerificationContext[VerificationType.Multikey]); + }); + + it('should fail to generateWellKnownDid with same publicKeyMultibase as wellKnown - BBS-2023', async () => { + const existingMultikeyWellKnown = { + ...wellKnown, + verificationMethod: [ + ...(wellKnown.verificationMethod || []), + { + type: 'Multikey', + id: 'did:web:localhost.com#keys-existing', + controller: 'did:web:localhost.com', + publicKeyMultibase: keyPair.publicKeyMultibase, + }, + ], + }; + + const duplicatedKeyPair = { + ...keyPair, + id: 'did:web:localhost.com#keys-4', + }; + + expect(() => + generateWellKnownDid({ + wellKnown: existingMultikeyWellKnown, + newKeyPair: duplicatedKeyPair, + }), + ).toThrowError('KeyPair already exists'); + }); + }); + + describe('generateWellKnownDid - ECDSA-SD-2023', () => { + const keyPair = { + id: 'did:web:localhost.com#keys-3', + type: VerificationType.Multikey, + controller: 'did:web:localhost.com', + secretKeyMultibase: 'z42twTcNeSYcnqg1FLuSFs2bsGH3ZqbRHFmvS9XMsYhjxvHN', + publicKeyMultibase: 'zDnaekGZTbQBerwcehBSXLqAg6s55hVEBms1zFy89VHXtJSa9', + }; + const verificationMethod = _.omit(keyPair, ['secretKeyMultibase']); + + it('should generateWellKnownDid with ECDSA-SD-2023 keyPair', async () => { + const result = generateWellKnownDid({ + newKeyPair: keyPair, + }); + + expect(result).toBeTruthy(); + expect(result?.id).toBe(keyPair.controller); + expect(result).toHaveProperty('id'); + expect(result).toHaveProperty('verificationMethod'); + expect(result).toHaveProperty('@context'); + expect(result).toHaveProperty('assertionMethod'); + expect(result).toHaveProperty('authentication'); + expect(result).toHaveProperty('capabilityInvocation'); + expect(result).toHaveProperty('capabilityDelegation'); + expect(result?.verificationMethod?.[0]).toMatchObject(verificationMethod); + expect(result?.verificationMethod?.[0].type).toBe('Multikey'); + expect(result?.['@context']).toContain('https://www.w3.org/ns/did/v1'); + expect(result?.['@context']).toContain(VerificationContext[VerificationType.Multikey]); + }); + + it('should generateWellKnownDid with ECDSA-SD-2023 keyPair and wellKnown', async () => { + const result = generateWellKnownDid({ + wellKnown: wellKnown, + newKeyPair: keyPair, + }); + + expect(result).toBeTruthy(); + expect(result?.id).toBe(keyPair.controller); + expect(result).toHaveProperty('id'); + expect(result).toHaveProperty('verificationMethod'); + expect(result).toHaveProperty('@context'); + expect(result).toHaveProperty('assertionMethod'); + expect(result).toHaveProperty('authentication'); + expect(result).toHaveProperty('capabilityInvocation'); + expect(result).toHaveProperty('capabilityDelegation'); + expect(result?.verificationMethod).toHaveLength(3); + expect(result?.verificationMethod?.[result?.verificationMethod?.length - 1]).toMatchObject( + verificationMethod, + ); + expect(result?.['@context']).toContain('https://www.w3.org/ns/did/v1'); + expect(result?.['@context']).toContain(VerificationContext[VerificationType.Multikey]); + }); + + it('should fail to generateWellKnownDid with same publicKeyMultibase as wellKnown - ECDSA-SD-2023', async () => { + const existingMultikeyWellKnown = { + ...wellKnown, + verificationMethod: [ + ...(wellKnown.verificationMethod || []), + { + type: 'Multikey', + id: 'did:web:localhost.com#keys-existing', + controller: 'did:web:localhost.com', + publicKeyMultibase: keyPair.publicKeyMultibase, + }, + ], + }; + + const duplicatedKeyPair = { + ...keyPair, + id: 'did:web:localhost.com#keys-4', + }; + + expect(() => + generateWellKnownDid({ + wellKnown: existingMultikeyWellKnown, + newKeyPair: duplicatedKeyPair, + }), + ).toThrowError('KeyPair already exists'); + }); + }); + + describe('generateWellKnownDid - Mixed Cryptosuites', () => { + it('should handle mixed legacy and modern cryptosuites', async () => { + const bbsKeyPair = { + id: 'did:web:localhost.com#keys-3', + type: VerificationType.Multikey, + controller: 'did:web:localhost.com', + seedBase58: 'CxBwAH4ftdc9XkLhw7DkFAESxh3NEdetMyJXKrPiAKAX', + secretKeyMultibase: 'z42twTcNeSYcnqg1FLuSFs2bsGH3ZqbRHFmvS9XMsYhjxvHN', + publicKeyMultibase: + 'zUC724qx4TSVn1zuJAjbaPAzwMhNvjHXvJrg36gEtNjQoKSVqZpG7QfVgsUsV2WrNvTB2p41iF2ZtVruDtwjMtZnyHCFGQov', + }; + + const result = generateWellKnownDid({ + wellKnown: wellKnown, + newKeyPair: bbsKeyPair, + }); + + expect(result).toBeTruthy(); + expect(result?.verificationMethod).toHaveLength(3); + + // Check that all verification method types are present + const types = result?.verificationMethod?.map((vm) => vm.type); + expect(types).toContain('Bls12381G2Key2020'); + expect(types).toContain('EcdsaSecp256k1RecoveryMethod2020'); + expect(types).toContain('Multikey'); + + // Check that contexts include both legacy and modern contexts + expect(result?.['@context']).toContain('https://www.w3.org/ns/did/v1'); + expect(result?.['@context']).toContain( + VerificationContext[VerificationType.Bls12381G2Key2020], + ); + expect(result?.['@context']).toContain( + VerificationContext[VerificationType.EcdsaSecp256k1RecoveryMethod2020], + ); + expect(result?.['@context']).toContain(VerificationContext[VerificationType.Multikey]); + }); + }); }); describe('nextKeyId', () => { diff --git a/packages/w3c-issuer/src/did-web/wellKnown/generate.ts b/packages/w3c-issuer/src/did-web/wellKnown/generate.ts index 3da187aa..723c06cc 100644 --- a/packages/w3c-issuer/src/did-web/wellKnown/generate.ts +++ b/packages/w3c-issuer/src/did-web/wellKnown/generate.ts @@ -1,5 +1,5 @@ import { VerificationMethod } from 'did-resolver'; -import { VerificationContext, VerificationType } from '../../lib/types'; +import { VerificationType, VerificationContext } from '../../lib/types'; import { KeyPair, DidWellKnownDocument, @@ -7,6 +7,8 @@ import { WellKnownEnum, BBSKeyPair, ECDSAKeyPair, + Bbs2023KeyPair, + EcdsaSd2023KeyPair, } from './types'; /** @@ -36,7 +38,11 @@ export const generateWellKnownDid = ({ s?.publicKeyBase58 === (newKeyPair as BBSKeyPair)?.publicKeyBase58) || (newKeyPair.type === VerificationType.EcdsaSecp256k1RecoveryMethod2020 && s?.blockchainAccountId && - s?.blockchainAccountId === (newKeyPair as ECDSAKeyPair)?.blockchainAccountId) + s?.blockchainAccountId === (newKeyPair as ECDSAKeyPair)?.blockchainAccountId) || + (newKeyPair.type === VerificationType.Multikey && + s?.publicKeyMultibase && + s?.publicKeyMultibase === + (newKeyPair as Bbs2023KeyPair | EcdsaSd2023KeyPair)?.publicKeyMultibase) ); }) ) { @@ -88,6 +94,13 @@ export const generateWellKnownDid = ({ (newKeyPair as ECDSAKeyPair).blockchainAccountId ) { newVerificationMethod.blockchainAccountId = (newKeyPair as ECDSAKeyPair).blockchainAccountId; + } else if ( + newKeyPair.type === VerificationType.Multikey && + (newKeyPair as Bbs2023KeyPair | EcdsaSd2023KeyPair).publicKeyMultibase + ) { + newVerificationMethod.publicKeyMultibase = ( + newKeyPair as Bbs2023KeyPair | EcdsaSd2023KeyPair + ).publicKeyMultibase; } if (!wellKnown[WellKnownEnum.VERIFICATION_METHOD]) { diff --git a/packages/w3c-issuer/src/did-web/wellKnown/index.test.ts b/packages/w3c-issuer/src/did-web/wellKnown/index.test.ts index 91e211c3..3f0d0a99 100644 --- a/packages/w3c-issuer/src/did-web/wellKnown/index.test.ts +++ b/packages/w3c-issuer/src/did-web/wellKnown/index.test.ts @@ -1,9 +1,14 @@ import _ from 'lodash'; import { beforeEach, describe, expect, it, vi } from 'vitest'; import { issueDID } from '.'; -import { VerificationType } from '../../lib/types'; +import { CryptoSuite, VerificationType } from '../../lib/types'; import * as query from './query'; -import { BBSPrivateKeyPair, IssuedDID } from './types'; +import { + BBSPrivateKeyPair, + Bbs2023PrivateKeyPair, + EcdsaSd2023PrivateKeyPair, + IssuedDID, +} from './types'; const mockedQueryDidDocumentResult = { id: 'did:web:localhost.com', @@ -31,6 +36,13 @@ describe('wellKnown', () => { '23GznFBm8BZcPM2BX7tcPfmeCAfkKKLWUWYwAj1jnu8acYhaNB892YkCDCJ1LLhXRBDpXEigx2tQYaw6EP1e1Fia83AfRUnmSA35v96ZgU3PmEd2DGqhUAXZZa4rM1gVGB9v', }; + const bbs2023KeyPair = { + seedBase58: 'CxBwAH4ftdc9XkLhw7DkFAESxh3NEdetMyJXKrPiAKAX', + secretKeyMultibase: 'z42twTcNeSYcnqg1FLuSFs2bsGH3ZqbRHFmvS9XMsYhjxvHN', + publicKeyMultibase: + 'zUC7LTa4hWtaE9YKyDsMVGiRNqPMN3s4rjBdB3MFi6PcVWReNfR72y3oGW2NhNcaKNVhMobh7aHp8oZB3qdJCs7RebM2xsodrSm8MmePbN25NTGcpjkJMwKbcWfYDX7eHCJjPGM', + }; + describe('issueDID', () => { beforeEach(() => { vi.restoreAllMocks(); @@ -178,5 +190,175 @@ describe('wellKnown', () => { ); }); }); + + describe('issueDID - BBS-2023', () => { + it('should issueDID with valid domain and BBS-2023 type', async () => { + const result: IssuedDID = await issueDID({ + domain: 'https://www.google.com', + type: CryptoSuite.Bbs2023, + }); + + expect(result).toBeTruthy(); + expect(result.wellKnownDid).toHaveProperty('id'); + expect(result.wellKnownDid).toHaveProperty('verificationMethod'); + expect(result.wellKnownDid).toHaveProperty('@context'); + expect(result.wellKnownDid).toHaveProperty('assertionMethod'); + expect(result.wellKnownDid).toHaveProperty('authentication'); + expect(result.wellKnownDid).toHaveProperty('capabilityInvocation'); + expect(result.wellKnownDid).toHaveProperty('capabilityDelegation'); + + // Check that the verification method uses Multikey type + expect(result.wellKnownDid?.verificationMethod?.[0]?.type).toBe('Multikey'); + expect(result.wellKnownDid?.verificationMethod?.[0]).toHaveProperty('publicKeyMultibase'); + expect(result.wellKnownDid?.verificationMethod?.[0]).not.toHaveProperty('seedBase58'); + expect(result.wellKnownDid?.verificationMethod?.[0]).not.toHaveProperty( + 'secretKeyMultibase', + ); + expect(result.wellKnownDid?.verificationMethod?.[0]).not.toHaveProperty('cryptosuite'); + + // Check that the context includes Multikey v1 + expect(result.wellKnownDid?.['@context']).toContain( + 'https://w3id.org/security/multikey/v1', + ); + + // Check key pair properties + expect(result.didKeyPairs).toHaveProperty('type', VerificationType.Multikey); + expect(result.didKeyPairs).toHaveProperty('id'); + expect(result.didKeyPairs).toHaveProperty('controller'); + expect(result.didKeyPairs).toHaveProperty('secretKeyMultibase'); + expect(result.didKeyPairs).toHaveProperty('publicKeyMultibase'); + }); + + it('should issueDID with valid domain, BBS-2023 type and seed', async () => { + const result = await issueDID({ + domain: 'https://www.google.com', + type: CryptoSuite.Bbs2023, + seedBase58: bbs2023KeyPair.seedBase58, + }); + + expect(result).toBeTruthy(); + expect(result.wellKnownDid).toHaveProperty('id'); + expect(result.wellKnownDid?.verificationMethod?.[0]?.type).toBe('Multikey'); + expect(result.wellKnownDid?.verificationMethod?.[0]).toHaveProperty('publicKeyMultibase'); + expect(result.wellKnownDid?.['@context']).toContain( + 'https://w3id.org/security/multikey/v1', + ); + + expect(result.didKeyPairs).toHaveProperty('type', VerificationType.Multikey); + expect(result.didKeyPairs).toHaveProperty('seedBase58'); + expect(result.didKeyPairs).toHaveProperty('secretKeyMultibase'); + expect(result.didKeyPairs).toHaveProperty('publicKeyMultibase'); + expect((result.didKeyPairs as Bbs2023PrivateKeyPair)?.seedBase58).toBe( + bbs2023KeyPair.seedBase58, + ); + }); + }); + + describe('issueDID - ECDSA-SD-2023', () => { + it('should issueDID with valid domain and ECDSA-SD-2023 type', async () => { + const result: IssuedDID = await issueDID({ + domain: 'https://www.google.com', + type: CryptoSuite.EcdsaSd2023, + }); + + expect(result).toBeTruthy(); + expect(result.wellKnownDid).toHaveProperty('id'); + expect(result.wellKnownDid).toHaveProperty('verificationMethod'); + expect(result.wellKnownDid).toHaveProperty('@context'); + expect(result.wellKnownDid).toHaveProperty('assertionMethod'); + expect(result.wellKnownDid).toHaveProperty('authentication'); + expect(result.wellKnownDid).toHaveProperty('capabilityInvocation'); + expect(result.wellKnownDid).toHaveProperty('capabilityDelegation'); + + // Check that the verification method uses Multikey type + expect(result.wellKnownDid?.verificationMethod?.[0]?.type).toBe('Multikey'); + expect(result.wellKnownDid?.verificationMethod?.[0]).toHaveProperty('publicKeyMultibase'); + expect(result.wellKnownDid?.['@context']).toContain( + 'https://w3id.org/security/multikey/v1', + ); + + // Check key pair properties + expect(result.didKeyPairs).toHaveProperty('type', VerificationType.Multikey); + expect(result.didKeyPairs).toHaveProperty('id'); + expect(result.didKeyPairs).toHaveProperty('controller'); + expect(result.didKeyPairs).toHaveProperty('secretKeyMultibase'); + expect(result.didKeyPairs).toHaveProperty('publicKeyMultibase'); + expect(result.didKeyPairs).not.toHaveProperty('seedBase58'); // ECDSA-SD-2023 doesn't use seeds + }); + + it('should generate different keys on multiple calls', async () => { + const result1 = await issueDID({ + domain: 'https://www.google.com', + type: CryptoSuite.EcdsaSd2023, + }); + + const result2 = await issueDID({ + domain: 'https://www.google.com', + type: CryptoSuite.EcdsaSd2023, + }); + + expect(result1.didKeyPairs).toHaveProperty('publicKeyMultibase'); + expect(result2.didKeyPairs).toHaveProperty('publicKeyMultibase'); + + // Keys should be different since ECDSA-SD-2023 generates random keys + expect((result1.didKeyPairs as EcdsaSd2023PrivateKeyPair).publicKeyMultibase).not.toBe( + (result2.didKeyPairs as EcdsaSd2023PrivateKeyPair).publicKeyMultibase, + ); + }); + }); + + describe('issueDID - Mixed Cryptosuites', () => { + it('should handle existing DID with different cryptosuite types', async () => { + const mockExistingDid = { + id: 'did:web:localhost.com', + verificationMethod: [ + { + type: 'Bls12381G2Key2020', + id: 'did:web:localhost.com#keys-0', + controller: 'did:web:localhost.com', + publicKeyBase58: 'existing-bls-key', + }, + { + type: 'Multikey', + id: 'did:web:localhost.com#keys-1', + controller: 'did:web:localhost.com', + publicKeyMultibase: 'z6MkexistingBbs2023Key', + }, + ], + '@context': [ + 'https://www.w3.org/ns/did/v1', + 'https://w3id.org/security/suites/bls12381-2020/v1', + 'https://w3id.org/security/multikey/v1', + ], + assertionMethod: ['did:web:localhost.com#keys-0', 'did:web:localhost.com#keys-1'], + authentication: ['did:web:localhost.com#keys-0', 'did:web:localhost.com#keys-1'], + capabilityInvocation: ['did:web:localhost.com#keys-0', 'did:web:localhost.com#keys-1'], + capabilityDelegation: ['did:web:localhost.com#keys-0', 'did:web:localhost.com#keys-1'], + }; + + const spy = vi.spyOn(query, 'queryDidDocument').mockImplementation( + () => + new Promise((resolve, _rejects) => + resolve({ + did: mockExistingDid.id, + wellKnownDid: _.cloneDeep(mockExistingDid), + }), + ), + ); + + const result = await issueDID({ + domain: 'https://localhost.com', + type: CryptoSuite.EcdsaSd2023, + }); + + expect(spy).toHaveBeenCalledTimes(1); + expect(result).toBeTruthy(); + expect(result.wellKnownDid?.verificationMethod).toHaveLength(3); // Original 2 + new 1 + expect(result.wellKnownDid?.verificationMethod?.[2]?.type).toBe('Multikey'); + expect(result.wellKnownDid?.verificationMethod?.[2]?.id).toBe( + 'did:web:localhost.com#keys-2', + ); + }); + }); }); }); diff --git a/packages/w3c-issuer/src/did-web/wellKnown/index.ts b/packages/w3c-issuer/src/did-web/wellKnown/index.ts index 221fa159..2f1dedb1 100644 --- a/packages/w3c-issuer/src/did-web/wellKnown/index.ts +++ b/packages/w3c-issuer/src/did-web/wellKnown/index.ts @@ -1,4 +1,4 @@ -import { VerificationType } from '../../lib/types'; +import { VerificationType, VerificationContext } from '../../lib/types'; import { generateKeyPair } from './../keyPair'; import { generateWellKnownDid, nextKeyId } from './generate'; import { queryDidDocument } from './query'; @@ -9,11 +9,11 @@ import { PrivateKeyPair, IssuedDID, IssuedDIDOption } from './types'; * * @param {IssuedDIDOption} didInput * @param {string} didInput.domain - Domain name - * @param {string} didInput.type - Type of key pair to generate, supported types are Bls12381G2Key2020 + * @param {string} didInput.type - Type of key pair to generate, supported types are Bls12381G2Key2020, EcdsaSecp256k1RecoveryMethod2020, Bbs2023, EcdsaSd2023 * - * @param {string} didInput.seedBase58 - Seed in base58 format (optional) - * @param {string} didInput.privateKeyBase58 - Private key in base58 format (optional) - * @param {string} didInput.publicKeyBase58 - Public key in base58 format (optional) + * @param {string} didInput.seedBase58 - Seed in base58 format (optional, for BLS and BBS-2023) + * @param {string} didInput.privateKeyBase58 - Private key in base58 format (optional, for BLS) + * @param {string} didInput.publicKeyBase58 - Public key in base58 format (optional, for BLS) * * @param {string} didInput.mnemonics - Mnemonics for did:ethr [EcdsaSecp256k1RecoveryMethod2020] (optional) * @param {string} didInput.path - Path for HDWalletNode address for did:ethr [EcdsaSecp256k1RecoveryMethod2020], default "m/44'/60'/0'/0/0" (optional) @@ -32,19 +32,29 @@ export const issueDID = async (didInput: IssuedDIDOption): Promise => const generatedKeyPair = await generateKeyPair(didInput); - let keyPairs: PrivateKeyPair = { - id: `${did}#keys-${keyId}`, - type: generatedKeyPair.type, - controller: did, - }; + let keyPairs: PrivateKeyPair; if (generatedKeyPair.type === VerificationType.Bls12381G2Key2020) { + // Legacy BLS keyPairs = { - ...keyPairs, + id: `${did}#keys-${keyId}`, + type: VerificationType.Bls12381G2Key2020, + controller: did, seedBase58: generatedKeyPair?.seedBase58, privateKeyBase58: generatedKeyPair?.privateKeyBase58, publicKeyBase58: generatedKeyPair?.publicKeyBase58, }; + } else if (generatedKeyPair.type === VerificationType.Multikey) { + // Modern cryptosuites (BBS-2023, ECDSA-SD-2023) + keyPairs = { + '@context': VerificationContext[VerificationType.Multikey], + id: `${did}#keys-${keyId}`, + type: VerificationType.Multikey, + controller: did, + secretKeyMultibase: generatedKeyPair?.secretKeyMultibase, + publicKeyMultibase: generatedKeyPair?.publicKeyMultibase, + ...(generatedKeyPair?.seedBase58 && { seedBase58: generatedKeyPair.seedBase58 }), // Only for BBS-2023 + }; } const generatedWellKnownDid = generateWellKnownDid({ diff --git a/packages/w3c-issuer/src/did-web/wellKnown/types.ts b/packages/w3c-issuer/src/did-web/wellKnown/types.ts index c72a26b0..3701309f 100644 --- a/packages/w3c-issuer/src/did-web/wellKnown/types.ts +++ b/packages/w3c-issuer/src/did-web/wellKnown/types.ts @@ -32,7 +32,7 @@ export const WellKnownAttribute: readonly WellKnownAttributeType[] = [ WellKnownEnum.CAPABILITY_DELEGATION, ] as const; -export type KeyPair = BBSKeyPair | ECDSAKeyPair; +export type KeyPair = BBSKeyPair | ECDSAKeyPair | MultikeyKeyPair; export type BBSKeyPair = { id: string; type: VerificationType; @@ -47,8 +47,21 @@ export type ECDSAKeyPair = { publicKeyMultibase?: string; blockchainAccountId?: string; }; +export type MultikeyKeyPair = { + '@context'?: string; + id: string; + type: VerificationType.Multikey; + controller: string; + publicKeyMultibase?: string; +}; +export type Bbs2023KeyPair = MultikeyKeyPair; +export type EcdsaSd2023KeyPair = MultikeyKeyPair; -export type PrivateKeyPair = BBSPrivateKeyPair | ECDSAPrivateKeyPair; +export type PrivateKeyPair = + | BBSPrivateKeyPair + | ECDSAPrivateKeyPair + | Bbs2023PrivateKeyPair + | EcdsaSd2023PrivateKeyPair; export type BBSPrivateKeyPair = BBSKeyPair & { seedBase58?: string; privateKeyBase58?: string; @@ -59,6 +72,13 @@ export type ECDSAPrivateKeyPair = ECDSAKeyPair & { privateKeyMultibase?: string; mnemonics?: string; }; +export type Bbs2023PrivateKeyPair = Bbs2023KeyPair & { + seedBase58?: string; + secretKeyMultibase?: string; +}; +export type EcdsaSd2023PrivateKeyPair = EcdsaSd2023KeyPair & { + secretKeyMultibase?: string; +}; export type DidWellKnownDocument = DIDDocument & { [key in WellKnownAttributeType]?: string[]; diff --git a/packages/w3c-issuer/src/lib/types.ts b/packages/w3c-issuer/src/lib/types.ts index 23466f8a..470385db 100644 --- a/packages/w3c-issuer/src/lib/types.ts +++ b/packages/w3c-issuer/src/lib/types.ts @@ -1,5 +1,10 @@ import { DidWebGenerateKeyPairOptions, DidWebGeneratedKeyPair } from './../did-web/keyPair/types'; +export enum CryptoSuite { + Bbs2023 = 'bbs-2023', + EcdsaSd2023 = 'ecdsa-sd-2023', +} + /** * https://www.w3.org/TR/did-spec-registries/#verification-method-types */ @@ -10,6 +15,7 @@ export enum VerificationType { Bls12381G1Key2020 = 'Bls12381G1Key2020', Bls12381G2Key2020 = 'Bls12381G2Key2020', EcdsaSecp256k1RecoveryMethod2020 = 'EcdsaSecp256k1RecoveryMethod2020', + Multikey = 'Multikey', } export const VerificationContext: { [key in VerificationType]: string } = { @@ -23,10 +29,11 @@ export const VerificationContext: { [key in VerificationType]: string } = { [VerificationType.Bls12381G2Key2020]: 'https://w3id.org/security/suites/bls12381-2020/v1', [VerificationType.EcdsaSecp256k1RecoveryMethod2020]: 'https://w3id.org/security/suites/secp256k1recovery-2020/v2', + [VerificationType.Multikey]: 'https://w3id.org/security/multikey/v1', }; export type BaseKeyPair = { - type: VerificationType; + type: VerificationType | CryptoSuite; }; export type GenerateKeyPairOptions = Required & Partial; diff --git a/packages/w3c-issuer/tsconfig.build.json b/packages/w3c-issuer/tsconfig.build.json index d3c5227e..eb191e4c 100644 --- a/packages/w3c-issuer/tsconfig.build.json +++ b/packages/w3c-issuer/tsconfig.build.json @@ -7,6 +7,6 @@ "rootDir": ".", "baseUrl": "." }, - "include": ["src/**/*.ts"], + "include": ["src/**/*.ts", "../declaration.d.ts"], "exclude": ["node_modules", ".coverage", "src/**/*.spec.ts", "src/**/*.test.ts"] } diff --git a/packages/w3c-issuer/tsconfig.json b/packages/w3c-issuer/tsconfig.json index 3cf45e0d..1a4ebe25 100644 --- a/packages/w3c-issuer/tsconfig.json +++ b/packages/w3c-issuer/tsconfig.json @@ -3,5 +3,5 @@ "compilerOptions": { "declaration": false }, - "include": ["src/**/*"] + "include": ["src/**/*", "../declaration.d.ts"] } diff --git a/packages/w3c-vc/tsconfig.json b/packages/w3c-vc/tsconfig.json index 3cf45e0d..1a4ebe25 100644 --- a/packages/w3c-vc/tsconfig.json +++ b/packages/w3c-vc/tsconfig.json @@ -3,5 +3,5 @@ "compilerOptions": { "declaration": false }, - "include": ["src/**/*"] + "include": ["src/**/*", "../declaration.d.ts"] } diff --git a/packages/w3c/tsconfig.json b/packages/w3c/tsconfig.json index 3cf45e0d..1a4ebe25 100644 --- a/packages/w3c/tsconfig.json +++ b/packages/w3c/tsconfig.json @@ -3,5 +3,5 @@ "compilerOptions": { "declaration": false }, - "include": ["src/**/*"] + "include": ["src/**/*", "../declaration.d.ts"] } From de0be8a7bad75303fe8c9c8df2b3aea93bf8d90f Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Thu, 31 Jul 2025 02:44:39 +0000 Subject: [PATCH 020/122] chore(release): @trustvc/w3c-issuer@1.3.0-alpha.1 [skip ci] # [1.3.0-alpha.1](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-issuer@1.2.1...@trustvc/w3c-issuer@1.3.0-alpha.1) (2025-07-31) ### Features * add bbs-2023 and ecdsa-sd-2023 key generation and did support ([#67](https://github.com/TrustVC/w3c/issues/67)) ([1ad1690](https://github.com/TrustVC/w3c/commit/1ad1690d39a003434283df429ebb7c176d4da71a)) --- packages/w3c-issuer/CHANGELOG.md | 7 +++++++ packages/w3c-issuer/package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/w3c-issuer/CHANGELOG.md b/packages/w3c-issuer/CHANGELOG.md index 536a9047..8008c9fe 100644 --- a/packages/w3c-issuer/CHANGELOG.md +++ b/packages/w3c-issuer/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.1](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-issuer@1.2.1...@trustvc/w3c-issuer@1.3.0-alpha.1) (2025-07-31) + + +### Features + +* add bbs-2023 and ecdsa-sd-2023 key generation and did support ([#67](https://github.com/TrustVC/w3c/issues/67)) ([1ad1690](https://github.com/TrustVC/w3c/commit/1ad1690d39a003434283df429ebb7c176d4da71a)) + ## [1.2.4](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-issuer@1.2.3...@trustvc/w3c-issuer@1.2.4) (2025-06-13) diff --git a/packages/w3c-issuer/package.json b/packages/w3c-issuer/package.json index 148fbd2d..f885e5a8 100644 --- a/packages/w3c-issuer/package.json +++ b/packages/w3c-issuer/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c-issuer", - "version": "1.2.4", + "version": "1.3.0-alpha.1", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", From 67941f13b5cfecead476998ffd4e230e5ff41288 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Thu, 31 Jul 2025 02:45:15 +0000 Subject: [PATCH 021/122] chore(release): @trustvc/w3c-context@1.3.0-alpha.1 [skip ci] # [1.3.0-alpha.1](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-context@1.2.3-alpha.2...@trustvc/w3c-context@1.3.0-alpha.1) (2025-07-31) ### Features * add bbs-2023 and ecdsa-sd-2023 key generation and did support ([#67](https://github.com/TrustVC/w3c/issues/67)) ([1ad1690](https://github.com/TrustVC/w3c/commit/1ad1690d39a003434283df429ebb7c176d4da71a)) --- packages/w3c-context/CHANGELOG.md | 7 +++++++ packages/w3c-context/package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/w3c-context/CHANGELOG.md b/packages/w3c-context/CHANGELOG.md index 0fd9fa6f..04507bdf 100644 --- a/packages/w3c-context/CHANGELOG.md +++ b/packages/w3c-context/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.1](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-context@1.2.3-alpha.2...@trustvc/w3c-context@1.3.0-alpha.1) (2025-07-31) + + +### Features + +* add bbs-2023 and ecdsa-sd-2023 key generation and did support ([#67](https://github.com/TrustVC/w3c/issues/67)) ([1ad1690](https://github.com/TrustVC/w3c/commit/1ad1690d39a003434283df429ebb7c176d4da71a)) + ## [1.2.13](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-context@1.2.12...@trustvc/w3c-context@1.2.13) (2025-06-13) diff --git a/packages/w3c-context/package.json b/packages/w3c-context/package.json index 4ee7916d..dc9981ce 100644 --- a/packages/w3c-context/package.json +++ b/packages/w3c-context/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c-context", - "version": "1.2.13", + "version": "1.3.0-alpha.1", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", From 39b84aee2da100a43dfa111ff85d89dbfb789ceb Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Thu, 31 Jul 2025 02:45:52 +0000 Subject: [PATCH 022/122] chore(release): @trustvc/w3c-credential-status@1.3.0-alpha.1 [skip ci] # [1.3.0-alpha.1](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-credential-status@1.2.3-alpha.2...@trustvc/w3c-credential-status@1.3.0-alpha.1) (2025-07-31) ### Features * add bbs-2023 and ecdsa-sd-2023 key generation and did support ([#67](https://github.com/TrustVC/w3c/issues/67)) ([1ad1690](https://github.com/TrustVC/w3c/commit/1ad1690d39a003434283df429ebb7c176d4da71a)) --- packages/w3c-credential-status/CHANGELOG.md | 7 +++++++ packages/w3c-credential-status/package.json | 6 +++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/packages/w3c-credential-status/CHANGELOG.md b/packages/w3c-credential-status/CHANGELOG.md index 76f85104..400ece95 100644 --- a/packages/w3c-credential-status/CHANGELOG.md +++ b/packages/w3c-credential-status/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.1](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-credential-status@1.2.3-alpha.2...@trustvc/w3c-credential-status@1.3.0-alpha.1) (2025-07-31) + + +### Features + +* add bbs-2023 and ecdsa-sd-2023 key generation and did support ([#67](https://github.com/TrustVC/w3c/issues/67)) ([1ad1690](https://github.com/TrustVC/w3c/commit/1ad1690d39a003434283df429ebb7c176d4da71a)) + ## [1.2.13](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-credential-status@1.2.12...@trustvc/w3c-credential-status@1.2.13) (2025-06-13) diff --git a/packages/w3c-credential-status/package.json b/packages/w3c-credential-status/package.json index 29c7d8ef..060f2904 100644 --- a/packages/w3c-credential-status/package.json +++ b/packages/w3c-credential-status/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c-credential-status", - "version": "1.2.13", + "version": "1.3.0-alpha.1", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", @@ -29,8 +29,8 @@ } }, "dependencies": { - "@trustvc/w3c-context": "^1.2.13", - "@trustvc/w3c-issuer": "^1.2.4", + "@trustvc/w3c-context": "^1.3.0-alpha.1", + "@trustvc/w3c-issuer": "^1.3.0-alpha.1", "base64url-universal": "^2.0.0", "pako": "^2.1.0" }, From 9a6f647c02063434127f92fda38630ea072000c3 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Thu, 31 Jul 2025 02:46:30 +0000 Subject: [PATCH 023/122] chore(release): @trustvc/w3c-vc@1.3.0-alpha.1 [skip ci] # [1.3.0-alpha.1](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.2.7-alpha.3...@trustvc/w3c-vc@1.3.0-alpha.1) (2025-07-31) ### Features * add bbs-2023 and ecdsa-sd-2023 key generation and did support ([#67](https://github.com/TrustVC/w3c/issues/67)) ([1ad1690](https://github.com/TrustVC/w3c/commit/1ad1690d39a003434283df429ebb7c176d4da71a)) --- packages/w3c-vc/CHANGELOG.md | 7 +++++++ packages/w3c-vc/package.json | 6 +++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/packages/w3c-vc/CHANGELOG.md b/packages/w3c-vc/CHANGELOG.md index d68c34bf..3a060809 100644 --- a/packages/w3c-vc/CHANGELOG.md +++ b/packages/w3c-vc/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.1](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.2.7-alpha.3...@trustvc/w3c-vc@1.3.0-alpha.1) (2025-07-31) + + +### Features + +* add bbs-2023 and ecdsa-sd-2023 key generation and did support ([#67](https://github.com/TrustVC/w3c/issues/67)) ([1ad1690](https://github.com/TrustVC/w3c/commit/1ad1690d39a003434283df429ebb7c176d4da71a)) + ## [1.2.17](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.2.16...@trustvc/w3c-vc@1.2.17) (2025-06-13) diff --git a/packages/w3c-vc/package.json b/packages/w3c-vc/package.json index 3cb3de55..815e40eb 100644 --- a/packages/w3c-vc/package.json +++ b/packages/w3c-vc/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c-vc", - "version": "1.2.17", + "version": "1.3.0-alpha.1", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", @@ -32,8 +32,8 @@ }, "dependencies": { "@mattrglobal/jsonld-signatures-bbs": "^1.2.0", - "@trustvc/w3c-credential-status": "^1.2.13", - "@trustvc/w3c-issuer": "^1.2.4", + "@trustvc/w3c-credential-status": "^1.3.0-alpha.1", + "@trustvc/w3c-issuer": "^1.3.0-alpha.1", "did-resolver": "^4.1.0", "jsonld": "^6.0.0", "jsonld-signatures": "7.0.0", From 6335669d094e6bbf03fb5242147ddbcf493143aa Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Thu, 31 Jul 2025 02:47:05 +0000 Subject: [PATCH 024/122] chore(release): @trustvc/w3c-cli@1.3.0-alpha.1 [skip ci] # [1.3.0-alpha.1](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-cli@1.2.7-alpha.3...@trustvc/w3c-cli@1.3.0-alpha.1) (2025-07-31) ### Features * add bbs-2023 and ecdsa-sd-2023 key generation and did support ([#67](https://github.com/TrustVC/w3c/issues/67)) ([1ad1690](https://github.com/TrustVC/w3c/commit/1ad1690d39a003434283df429ebb7c176d4da71a)) --- apps/w3c-cli/CHANGELOG.md | 7 +++++++ apps/w3c-cli/package.json | 10 +++++----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/apps/w3c-cli/CHANGELOG.md b/apps/w3c-cli/CHANGELOG.md index 9ac083eb..75a7b8fe 100644 --- a/apps/w3c-cli/CHANGELOG.md +++ b/apps/w3c-cli/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.1](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-cli@1.2.7-alpha.3...@trustvc/w3c-cli@1.3.0-alpha.1) (2025-07-31) + + +### Features + +* add bbs-2023 and ecdsa-sd-2023 key generation and did support ([#67](https://github.com/TrustVC/w3c/issues/67)) ([1ad1690](https://github.com/TrustVC/w3c/commit/1ad1690d39a003434283df429ebb7c176d4da71a)) + ## [1.2.18](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-cli@1.2.17...@trustvc/w3c-cli@1.2.18) (2025-06-13) diff --git a/apps/w3c-cli/package.json b/apps/w3c-cli/package.json index c82b54e4..1daddbdc 100644 --- a/apps/w3c-cli/package.json +++ b/apps/w3c-cli/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c-cli", - "version": "1.2.18", + "version": "1.3.0-alpha.1", "description": "CLI for TrustVC W3C", "main": "dist/main.js", "types": "dist/main.d.ts", @@ -34,10 +34,10 @@ }, "dependencies": { "@inquirer/prompts": "^5.3.8", - "@trustvc/w3c-context": "^1.2.13", - "@trustvc/w3c-credential-status": "^1.2.13", - "@trustvc/w3c-vc": "^1.2.17", - "@trustvc/w3c-issuer": "^1.2.4", + "@trustvc/w3c-context": "^1.3.0-alpha.1", + "@trustvc/w3c-credential-status": "^1.3.0-alpha.1", + "@trustvc/w3c-vc": "^1.3.0-alpha.1", + "@trustvc/w3c-issuer": "^1.3.0-alpha.1", "@types/yargs": "^17.0.32", "chalk": "^4.1.2", "inquirer": "^10.0.1", From 2609c71d9d2971c21a36a01b79b089ca893f9520 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Thu, 31 Jul 2025 02:47:44 +0000 Subject: [PATCH 025/122] chore(release): @trustvc/w3c@1.3.0-alpha.1 [skip ci] # [1.3.0-alpha.1](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.2.7-alpha.3...@trustvc/w3c@1.3.0-alpha.1) (2025-07-31) ### Features * add bbs-2023 and ecdsa-sd-2023 key generation and did support ([#67](https://github.com/TrustVC/w3c/issues/67)) ([1ad1690](https://github.com/TrustVC/w3c/commit/1ad1690d39a003434283df429ebb7c176d4da71a)) --- packages/w3c/CHANGELOG.md | 7 +++++++ packages/w3c/package.json | 10 +++++----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/packages/w3c/CHANGELOG.md b/packages/w3c/CHANGELOG.md index f0136347..0e9ade8d 100644 --- a/packages/w3c/CHANGELOG.md +++ b/packages/w3c/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.1](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.2.7-alpha.3...@trustvc/w3c@1.3.0-alpha.1) (2025-07-31) + + +### Features + +* add bbs-2023 and ecdsa-sd-2023 key generation and did support ([#67](https://github.com/TrustVC/w3c/issues/67)) ([1ad1690](https://github.com/TrustVC/w3c/commit/1ad1690d39a003434283df429ebb7c176d4da71a)) + ## [1.2.17](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.2.16...@trustvc/w3c@1.2.17) (2025-06-13) diff --git a/packages/w3c/package.json b/packages/w3c/package.json index 391c2fb3..71b8ec81 100644 --- a/packages/w3c/package.json +++ b/packages/w3c/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c", - "version": "1.2.17", + "version": "1.3.0-alpha.1", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", @@ -32,10 +32,10 @@ } }, "dependencies": { - "@trustvc/w3c-context": "^1.2.13", - "@trustvc/w3c-credential-status": "^1.2.13", - "@trustvc/w3c-issuer": "^1.2.4", - "@trustvc/w3c-vc": "^1.2.17" + "@trustvc/w3c-context": "^1.3.0-alpha.1", + "@trustvc/w3c-credential-status": "^1.3.0-alpha.1", + "@trustvc/w3c-issuer": "^1.3.0-alpha.1", + "@trustvc/w3c-vc": "^1.3.0-alpha.1" }, "repository": { "type": "git", From 20d5e69328f60c34dd210c12734604b59f457030 Mon Sep 17 00:00:00 2001 From: rongquan1 <85145303+rongquan1@users.noreply.github.com> Date: Thu, 7 Aug 2025 11:26:15 +0800 Subject: [PATCH 026/122] feat: add ecdsa-sd-2023 support (#68) * feat: add ecdsa-sd-2023 support * fix: build issue * fix: update test * fix: naming * fix: refactor * fix: refactor --- package-lock.json | 266 ++++++++++++++++-- package.json | 1 - packages/declaration.d.ts | 5 + packages/w3c-context/package.json | 2 +- packages/w3c-context/src/lib/index.ts | 42 ++- packages/w3c-context/tsconfig.build.json | 3 +- packages/w3c-context/tsconfig.json | 3 +- .../src/did-web/wellKnown/query.test.ts | 11 + packages/w3c-vc/README.md | 228 +++++++++------ packages/w3c-vc/package.json | 6 +- packages/w3c-vc/src/lib/helper/index.ts | 30 +- .../src/lib/sign/credentialStatus/index.ts | 1 - packages/w3c-vc/src/lib/types.ts | 6 +- packages/w3c-vc/src/lib/w3c-vc.test.ts | 198 ++++++++++++- packages/w3c-vc/src/lib/w3c-vc.ts | 142 ++++++++-- packages/w3c-vc/tsconfig.build.json | 2 +- 16 files changed, 794 insertions(+), 152 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5eb86913..892b38fc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -30,7 +30,6 @@ "express": "^4.19.2", "inquirer": "^10.1.2", "jsonld": "^6.0.0", - "jsonld-signatures": "7.0.0", "multiformats": "^9.9.0", "pako": "^2.1.0", "tslib": "^2.3.0", @@ -116,14 +115,14 @@ }, "apps/w3c-cli": { "name": "@trustvc/w3c-cli", - "version": "1.2.18", + "version": "1.3.0-alpha.1", "license": "Apache-2.0", "dependencies": { "@inquirer/prompts": "^5.3.8", - "@trustvc/w3c-context": "^1.2.13", - "@trustvc/w3c-credential-status": "^1.2.13", - "@trustvc/w3c-issuer": "^1.2.4", - "@trustvc/w3c-vc": "^1.2.17", + "@trustvc/w3c-context": "^1.3.0-alpha.1", + "@trustvc/w3c-credential-status": "^1.3.0-alpha.1", + "@trustvc/w3c-issuer": "^1.3.0-alpha.1", + "@trustvc/w3c-vc": "^1.3.0-alpha.1", "@types/yargs": "^17.0.32", "chalk": "^4.1.2", "inquirer": "^10.0.1", @@ -2820,6 +2819,95 @@ "resolved": "https://registry.npmjs.org/@digitalbazaar/credentials-context/-/credentials-context-3.1.0.tgz", "integrity": "sha512-VKflyFbcid6xH3FJMrd8U9DeCjbYXa2aO3l8yy7MzP6O/0v0EZTV56hMfJT5fN6TSVtQmShv2R3oPCFqFbc2Tg==" }, + "node_modules/@digitalbazaar/data-integrity": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@digitalbazaar/data-integrity/-/data-integrity-2.5.0.tgz", + "integrity": "sha512-ohIieLfgtPQU9BYfj0eKNiz55/ZDOk5YSE9FN/Hn0eXzI8WQzLkzRvC8pvBnzuzXDgCsjPdSqYvzok5PoClMBQ==", + "dependencies": { + "base58-universal": "^2.0.0", + "base64url-universal": "^2.0.0", + "jsonld-signatures": "^11.3.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@digitalbazaar/data-integrity/node_modules/jsonld-signatures": { + "version": "11.5.0", + "resolved": "https://registry.npmjs.org/jsonld-signatures/-/jsonld-signatures-11.5.0.tgz", + "integrity": "sha512-Kdto+e8uvY/5u3HYkmAbpy52bplWX9uqS8fmqdCv6oxnCFwCTM0hMt6r4rWqlhw5/aHoCHJIRxwYb4QKGC69Jw==", + "dependencies": { + "@digitalbazaar/security-context": "^1.0.0", + "jsonld": "^8.0.0", + "rdf-canonize": "^4.0.1", + "serialize-error": "^8.1.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@digitalbazaar/data-integrity/node_modules/rdf-canonize": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/rdf-canonize/-/rdf-canonize-4.0.1.tgz", + "integrity": "sha512-B5ynHt4sasbUafzrvYI2GFARgeFcD8Sx9yXPbg7gEyT2EH76rlCv84kyO6tnxzVbxUN/uJDbK1S/MXh+DsnuTA==", + "dependencies": { + "setimmediate": "^1.0.5" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@digitalbazaar/data-integrity/node_modules/serialize-error": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-8.1.0.tgz", + "integrity": "sha512-3NnuWfM6vBYoy5gZFvHiYsVbafvI9vZv/+jlIigFn4oP4zjNPK3LhcY0xSCgeb1a5L8jO71Mit9LlNoi2UfDDQ==", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@digitalbazaar/data-integrity/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@digitalbazaar/di-sd-primitives": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@digitalbazaar/di-sd-primitives/-/di-sd-primitives-3.1.0.tgz", + "integrity": "sha512-qi8H5yz4R6UmNWC6t99MSxFexniWZHME39Q77ev03afkgLMRMQSVwNGybrgeIK1VOKn0uF4YQj8quhkNlg5baQ==", + "dependencies": { + "base64url-universal": "^2.0.0", + "jsonld": "^8.3.2", + "klona": "^2.0.6", + "rdf-canonize": "^4.0.1", + "uuid": "^10.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@digitalbazaar/di-sd-primitives/node_modules/rdf-canonize": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/rdf-canonize/-/rdf-canonize-4.0.1.tgz", + "integrity": "sha512-B5ynHt4sasbUafzrvYI2GFARgeFcD8Sx9yXPbg7gEyT2EH76rlCv84kyO6tnxzVbxUN/uJDbK1S/MXh+DsnuTA==", + "dependencies": { + "setimmediate": "^1.0.5" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/@digitalbazaar/ecdsa-multikey": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/@digitalbazaar/ecdsa-multikey/-/ecdsa-multikey-1.8.0.tgz", @@ -2832,6 +2920,22 @@ "node": ">=18" } }, + "node_modules/@digitalbazaar/ecdsa-sd-2023-cryptosuite": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/@digitalbazaar/ecdsa-sd-2023-cryptosuite/-/ecdsa-sd-2023-cryptosuite-3.4.1.tgz", + "integrity": "sha512-PzKQneakxUUS/kzDgUZ0ZcZKuHhMhAelW2Bp/rryHEV43VeI3meoJkuQ0s7sfMlD1OWkKWrNClMr1znwBaQiLQ==", + "dependencies": { + "@digitalbazaar/di-sd-primitives": "^3.0.4", + "@digitalbazaar/ecdsa-multikey": "^1.1.3", + "base58-universal": "^2.0.0", + "base64url-universal": "^2.0.0", + "cborg": "^4.0.5", + "klona": "^2.0.6" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/@digitalbazaar/http-client": { "version": "3.4.1", "resolved": "https://registry.npmjs.org/@digitalbazaar/http-client/-/http-client-3.4.1.tgz", @@ -19574,6 +19678,23 @@ "node": ">=10" } }, + "node_modules/jsonld-signatures-v7": { + "name": "jsonld-signatures", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/jsonld-signatures/-/jsonld-signatures-7.0.0.tgz", + "integrity": "sha512-J/nA+llcYYjErPHG9WFpXvR82TOg5fbHk/7rXbx4Ts854DPReaKAAd0hAZ+s5/P2WIIAZPIHCqA+iz1QrOqeiQ==", + "dependencies": { + "base64url": "^3.0.1", + "crypto-ld": "^3.7.0", + "jsonld": "^4.0.1", + "node-forge": "^0.10.0", + "security-context": "^4.0.0", + "serialize-error": "^5.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/jsonld/node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -19712,6 +19833,14 @@ "node": ">=6" } }, + "node_modules/klona": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz", + "integrity": "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==", + "engines": { + "node": ">= 8" + } + }, "node_modules/kolorist": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/kolorist/-/kolorist-1.8.0.tgz", @@ -32669,13 +32798,13 @@ }, "packages/w3c": { "name": "@trustvc/w3c", - "version": "1.2.17", + "version": "1.3.0-alpha.1", "license": "Apache-2.0", "dependencies": { - "@trustvc/w3c-context": "^1.2.13", - "@trustvc/w3c-credential-status": "^1.2.13", - "@trustvc/w3c-issuer": "^1.2.4", - "@trustvc/w3c-vc": "^1.2.17" + "@trustvc/w3c-context": "^1.3.0-alpha.1", + "@trustvc/w3c-credential-status": "^1.3.0-alpha.1", + "@trustvc/w3c-issuer": "^1.3.0-alpha.1", + "@trustvc/w3c-vc": "^1.3.0-alpha.1" }, "engines": { "node": ">=18.x" @@ -32683,11 +32812,11 @@ }, "packages/w3c-context": { "name": "@trustvc/w3c-context", - "version": "1.2.13", + "version": "1.3.0-alpha.1", "license": "Apache-2.0", "dependencies": { "did-resolver": "^4.1.0", - "jsonld-signatures": "^7.0.0" + "jsonld-signatures-v7": "npm:jsonld-signatures@7.0.0" }, "engines": { "node": ">=18.x" @@ -32695,11 +32824,11 @@ }, "packages/w3c-credential-status": { "name": "@trustvc/w3c-credential-status", - "version": "1.2.13", + "version": "1.3.0-alpha.1", "license": "Apache-2.0", "dependencies": { - "@trustvc/w3c-context": "^1.2.13", - "@trustvc/w3c-issuer": "^1.2.4", + "@trustvc/w3c-context": "^1.3.0-alpha.1", + "@trustvc/w3c-issuer": "^1.3.0-alpha.1", "base64url-universal": "^2.0.0", "pako": "^2.1.0" }, @@ -32709,7 +32838,7 @@ }, "packages/w3c-issuer": { "name": "@trustvc/w3c-issuer", - "version": "1.2.4", + "version": "1.3.0-alpha.1", "license": "Apache-2.0", "dependencies": { "@digitalbazaar/bls12-381-multikey": "^2.1.0", @@ -32726,15 +32855,19 @@ }, "packages/w3c-vc": { "name": "@trustvc/w3c-vc", - "version": "1.2.17", + "version": "1.3.0-alpha.1", "license": "Apache-2.0", "dependencies": { + "@digitalbazaar/data-integrity": "^2.5.0", + "@digitalbazaar/ecdsa-multikey": "^1.8.0", + "@digitalbazaar/ecdsa-sd-2023-cryptosuite": "^3.4.1", "@mattrglobal/jsonld-signatures-bbs": "^1.2.0", - "@trustvc/w3c-credential-status": "^1.2.13", - "@trustvc/w3c-issuer": "^1.2.4", + "@trustvc/w3c-credential-status": "^1.3.0-alpha.1", + "@trustvc/w3c-issuer": "^1.3.0-alpha.1", "did-resolver": "^4.1.0", "jsonld": "^6.0.0", - "jsonld-signatures": "7.0.0", + "jsonld-signatures": "^11.5.0", + "jsonld-signatures-v7": "npm:jsonld-signatures@7.0.0", "uuid": "^10.0.0" }, "devDependencies": { @@ -32746,6 +32879,97 @@ "peerDependencies": { "jsonld": "^6.0.0" } + }, + "packages/w3c-vc/node_modules/jsonld-signatures": { + "version": "11.5.0", + "resolved": "https://registry.npmjs.org/jsonld-signatures/-/jsonld-signatures-11.5.0.tgz", + "integrity": "sha512-Kdto+e8uvY/5u3HYkmAbpy52bplWX9uqS8fmqdCv6oxnCFwCTM0hMt6r4rWqlhw5/aHoCHJIRxwYb4QKGC69Jw==", + "dependencies": { + "@digitalbazaar/security-context": "^1.0.0", + "jsonld": "^8.0.0", + "rdf-canonize": "^4.0.1", + "serialize-error": "^8.1.0" + }, + "engines": { + "node": ">=18" + } + }, + "packages/w3c-vc/node_modules/jsonld-signatures/node_modules/jsonld": { + "version": "8.3.3", + "resolved": "https://registry.npmjs.org/jsonld/-/jsonld-8.3.3.tgz", + "integrity": "sha512-9YcilrF+dLfg9NTEof/mJLMtbdX1RJ8dbWtJgE00cMOIohb1lIyJl710vFiTaiHTl6ZYODJuBd32xFvUhmv3kg==", + "dependencies": { + "@digitalbazaar/http-client": "^3.4.1", + "canonicalize": "^1.0.1", + "lru-cache": "^6.0.0", + "rdf-canonize": "^3.4.0" + }, + "engines": { + "node": ">=14" + } + }, + "packages/w3c-vc/node_modules/jsonld-signatures/node_modules/jsonld/node_modules/rdf-canonize": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/rdf-canonize/-/rdf-canonize-3.4.0.tgz", + "integrity": "sha512-fUeWjrkOO0t1rg7B2fdyDTvngj+9RlUyL92vOdiB7c0FPguWVsniIMjEtHH+meLBO9rzkUlUzBVXgWrjI8P9LA==", + "dependencies": { + "setimmediate": "^1.0.5" + }, + "engines": { + "node": ">=12" + } + }, + "packages/w3c-vc/node_modules/jsonld-signatures/node_modules/rdf-canonize": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/rdf-canonize/-/rdf-canonize-4.0.1.tgz", + "integrity": "sha512-B5ynHt4sasbUafzrvYI2GFARgeFcD8Sx9yXPbg7gEyT2EH76rlCv84kyO6tnxzVbxUN/uJDbK1S/MXh+DsnuTA==", + "dependencies": { + "setimmediate": "^1.0.5" + }, + "engines": { + "node": ">=18" + } + }, + "packages/w3c-vc/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "packages/w3c-vc/node_modules/serialize-error": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-8.1.0.tgz", + "integrity": "sha512-3NnuWfM6vBYoy5gZFvHiYsVbafvI9vZv/+jlIigFn4oP4zjNPK3LhcY0xSCgeb1a5L8jO71Mit9LlNoi2UfDDQ==", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "packages/w3c-vc/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "packages/w3c-vc/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" } } } diff --git a/package.json b/package.json index ac5d3e51..b4fa99d3 100644 --- a/package.json +++ b/package.json @@ -114,7 +114,6 @@ "express": "^4.19.2", "inquirer": "^10.1.2", "jsonld": "^6.0.0", - "jsonld-signatures": "7.0.0", "multiformats": "^9.9.0", "pako": "^2.1.0", "tslib": "^2.3.0", diff --git a/packages/declaration.d.ts b/packages/declaration.d.ts index a0939395..eee0fba4 100644 --- a/packages/declaration.d.ts +++ b/packages/declaration.d.ts @@ -1,2 +1,7 @@ declare module '@digitalbazaar/bls12-381-multikey'; declare module '@digitalbazaar/ecdsa-multikey'; +declare module '@digitalbazaar/ecdsa-sd-2023-cryptosuite'; +declare module '@digitalbazaar/data-integrity'; +declare module 'jsonld'; +declare module 'jsonld-signatures'; +declare module 'jsonld-signatures-v7'; diff --git a/packages/w3c-context/package.json b/packages/w3c-context/package.json index dc9981ce..002a7241 100644 --- a/packages/w3c-context/package.json +++ b/packages/w3c-context/package.json @@ -34,7 +34,7 @@ }, "dependencies": { "did-resolver": "^4.1.0", - "jsonld-signatures": "^7.0.0" + "jsonld-signatures-v7": "npm:jsonld-signatures@7.0.0" }, "repository": { "type": "git", diff --git a/packages/w3c-context/src/lib/index.ts b/packages/w3c-context/src/lib/index.ts index ad36502d..d82875be 100644 --- a/packages/w3c-context/src/lib/index.ts +++ b/packages/w3c-context/src/lib/index.ts @@ -1,7 +1,6 @@ import { queryDidDocument } from '@trustvc/w3c-issuer'; import { DocumentLoader, DocumentLoaderObject } from './types'; -// @ts-ignore: No types available for jsonld-signatures -import jsonldSignatures from 'jsonld-signatures'; +import jsonldSignaturesV7 from 'jsonld-signatures-v7'; import attachmentsContext from '../context/attachments-context.json'; import bbsV1 from '../context/bbs-v1.json'; import bolContext from '../context/bill-of-lading.json'; @@ -121,15 +120,38 @@ export async function getDocumentLoader( const resolveDid = async (did: string) => { const { wellKnownDid } = await queryDidDocument({ did }); - const result: DocumentLoaderObject = { - contextUrl: null, - document: wellKnownDid, - documentUrl: did, - }; - resultMap.set(did, result); + // Check if the DID includes a fragment (verification method ID) + if (did.includes('#')) { + // This is a verification method ID, find the specific verification method + const verificationMethod = wellKnownDid.verificationMethod?.find((vm) => vm.id === did); + + if (!verificationMethod) { + throw new Error(`Verification method ${did} could not be found.`); + } - return result; + const result: DocumentLoaderObject = { + contextUrl: null, + document: { + '@context': wellKnownDid['@context'], + ...verificationMethod, + }, + documentUrl: did, + }; + + resultMap.set(did, result); + return result; + } else { + // This is a DID document request, return the full document + const result: DocumentLoaderObject = { + contextUrl: null, + document: wellKnownDid, + documentUrl: did, + }; + + resultMap.set(did, result); + return result; + } }; const customDocLoader = async (url: string) => { @@ -159,5 +181,5 @@ export async function getDocumentLoader( return resolveContext; }; - return jsonldSignatures.extendContextLoader(customDocLoader); + return jsonldSignaturesV7.extendContextLoader(customDocLoader); } diff --git a/packages/w3c-context/tsconfig.build.json b/packages/w3c-context/tsconfig.build.json index 0a3bc92c..1a33927b 100644 --- a/packages/w3c-context/tsconfig.build.json +++ b/packages/w3c-context/tsconfig.build.json @@ -10,7 +10,8 @@ }, "include": [ "src/**/*.ts", - "src/**/*.json" + "src/**/*.json", + "../declaration.d.ts" ], "exclude": ["node_modules", ".coverage", "src/**/*.spec.ts", "src/**/*.test.ts"] } diff --git a/packages/w3c-context/tsconfig.json b/packages/w3c-context/tsconfig.json index 20201530..bdbf97b8 100644 --- a/packages/w3c-context/tsconfig.json +++ b/packages/w3c-context/tsconfig.json @@ -3,6 +3,5 @@ "compilerOptions": { "module": "commonjs" }, - "files": [], - "include": [] + "include": ["src/**/*.ts", "../declaration.d.ts"] } diff --git a/packages/w3c-issuer/src/did-web/wellKnown/query.test.ts b/packages/w3c-issuer/src/did-web/wellKnown/query.test.ts index 055c122c..1aff72bb 100644 --- a/packages/w3c-issuer/src/did-web/wellKnown/query.test.ts +++ b/packages/w3c-issuer/src/did-web/wellKnown/query.test.ts @@ -28,18 +28,23 @@ describe('query', () => { "@context": [ "https://www.w3.org/ns/did/v1", "https://w3id.org/security/suites/bls12381-2020/v1", + "https://w3id.org/security/multikey/v1", ], "assertionMethod": [ "did:web:trustvc.github.io:did:1#keys-1", + "did:web:trustvc.github.io:did:1#multikey-1", ], "authentication": [ "did:web:trustvc.github.io:did:1#keys-1", + "did:web:trustvc.github.io:did:1#multikey-1", ], "capabilityDelegation": [ "did:web:trustvc.github.io:did:1#keys-1", + "did:web:trustvc.github.io:did:1#multikey-1", ], "capabilityInvocation": [ "did:web:trustvc.github.io:did:1#keys-1", + "did:web:trustvc.github.io:did:1#multikey-1", ], "id": "did:web:trustvc.github.io:did:1", "verificationMethod": [ @@ -49,6 +54,12 @@ describe('query', () => { "publicKeyBase58": "oRfEeWFresvhRtXCkihZbxyoi2JER7gHTJ5psXhHsdCoU1MttRMi3Yp9b9fpjmKh7bMgfWKLESiK2YovRd8KGzJsGuamoAXfqDDVhckxuc9nmsJ84skCSTijKeU4pfAcxeJ", "type": "Bls12381G2Key2020", }, + { + "controller": "did:web:trustvc.github.io:did:1", + "id": "did:web:trustvc.github.io:did:1#multikey-1", + "publicKeyMultibase": "zDnaemDNwi4G5eTzGfRooFFu5Kns3be6yfyVNtiaMhWkZbwtc", + "type": "Multikey", + }, ], } `); diff --git a/packages/w3c-vc/README.md b/packages/w3c-vc/README.md index 00ea3bce..dfe0a1a1 100644 --- a/packages/w3c-vc/README.md +++ b/packages/w3c-vc/README.md @@ -1,6 +1,6 @@ # TrustVC W3C VC -This repository provides utilities for signing and verifying Verifiable Credentials (VCs) using the BBS+ signature scheme. These functions can be used to ensure the authenticity and integrity of VCs within a W3C-compliant ecosystem. +This repository provides utilities for signing and verifying Verifiable Credentials (VCs) using multiple signature schemes including BBS+ and ECDSA-SD-2023. These functions can be used to ensure the authenticity and integrity of VCs within a W3C-compliant ecosystem. ## Installation To install the package, use: @@ -11,13 +11,17 @@ npm install @trustvc/w3c-vc ## Feature - Sign and Verify for BBS+ signature for W3C VC +- Sign and Verify for ECDSA-SD-2023 signature for W3C VC with selective disclosure - Derive a new VC with selective disclosure using BBS+ signature +- Derive a new VC with selective disclosure using ECDSA-SD-2023 signature - Checks if payload matches W3C VC schema ## Usage ### 1. Signing a Credential -The signCredential function allows you to sign a Verifiable Credential using the BBS+ signature scheme. +The signCredential function allows you to sign a Verifiable Credential using either BBS+ or ECDSA-SD-2023 signature schemes. + +#### BBS+ Signing (Default) ```ts import { signCredential } from '@trustvc/w3c-vc'; @@ -79,46 +83,52 @@ if (signedCredential.signed) { } ``` -
- signCredential Result - - ```js - Signed Credential: { - '@context': [ - 'https://www.w3.org/2018/credentials/v1', - 'https://w3c-ccg.github.io/citizenship-vocab/contexts/citizenship-v1.jsonld', - 'https://w3id.org/security/bbs/v1', - 'https://w3id.org/vc/status-list/2021/v1' - ], - credentialStatus: { - id: 'https://trustvc.github.io/did/credentials/statuslist/1#1', - statusListCredential: 'https://trustvc.github.io/did/credentials/statuslist/1', - statusListIndex: '1', - statusPurpose: 'revocation', - type: 'StatusList2021Entry' - }, - issuanceDate: '2024-04-01T12:19:52Z', - credentialSubject: { - id: 'did:example:b34ca6cd37bbf23', - type: [ 'Person' ], - name: 'TrustVC' - }, - expirationDate: '2029-12-03T12:19:52Z', - issuer: 'did:web:trustvc.github.io:did:1', - type: [ 'VerifiableCredential' ], - proof: { - type: 'BbsBlsSignature2020', - created: '2024-10-02T09:04:07Z', - proofPurpose: 'assertionMethod', - proofValue: 'tissP5pJF1q4txCMWNZI5LgwhXMWrLI8675ops8FwlQE/zBUQnVO9Iey505MjkNDD5GdmQmnb6+RUKkLVGEJLIJrKQXlU3Xr4DlMW7ShH/sIpuvZoobGs/0hw/B5agXz8cVWfnDGWtDYciVh0rwQvg==', - verificationMethod: 'did:web:trustvc.github.io:did:1#keys-1' - } - } - ``` -
+#### ECDSA-SD-2023 Signing + +```ts +import { signCredential } from '@trustvc/w3c-vc'; + +const ecdsaKeyPair = { + "id": "did:web:trustvc.github.io:did:1#multikey-1", + "type": "Multikey", + "controller": "did:web:trustvc.github.io:did:1", + "secretKeyMultibase": "", + "publicKeyMultibase": "zDnaekGZTbQBerwcehBSXLqAg6s55hVEBms1zFy89VHXtJSa9" +}; + +const credential = { + "@context": [ + "https://www.w3.org/2018/credentials/v1", + "https://w3id.org/security/data-integrity/v2" + ], + "issuanceDate": "2024-04-01T12:19:52Z", + "credentialSubject": { + "id": "did:example:b34ca6cd37bbf23", + "type": ["Person"], + "name": "TrustVC", + "billOfLadingName": "Acme Corp" + }, + "expirationDate": "2029-12-03T12:19:52Z", + "issuer": "did:web:trustvc.github.io:did:1", + "type": ["VerifiableCredential"] +}; + +// Sign with mandatory pointers (always included in derived credentials) +const signedCredential = await signCredential(credential, ecdsaKeyPair, 'ecdsa-sd-2023', { + mandatoryPointers: ['/credentialSubject/id', '/credentialSubject/type'] +}); + +if (signedCredential.signed) { + console.log('Signed Credential:', signedCredential.signed); +} else { + console.error('Error:', signedCredential.error); +} +``` ### 2. Verifying a Credential -The verifyCredential function allows you to verify a signed Verifiable Credential using the BBS+ signature scheme. +The verifyCredential function allows you to verify a signed Verifiable Credential using BBS+ or ECDSA-SD-2023 signature schemes. + +#### BBS+ Verification ```ts import { verifyCredential } from '@trustvc/w3c-vc'; @@ -174,17 +184,52 @@ if (verificationResult.verified) { } ``` -
- verifyCredential Result +#### ECDSA-SD-2023 Verification + +> **Note**: For ECDSA-SD-2023 credentials with selective disclosure, you typically need to derive the credential first using `deriveCredential()` before verification. The example below shows verification of a base credential. + +```ts +import { verifyCredential } from '@trustvc/w3c-vc'; + +const ecdsaCredential = { + '@context': [ + 'https://www.w3.org/2018/credentials/v1', + 'https://w3id.org/security/data-integrity/v2' + ], + issuanceDate: '2024-04-01T12:19:52Z', + credentialSubject: { + id: 'did:example:b34ca6cd37bbf23', + type: ['Person'], + name: 'TrustVC', + billOfLadingName: 'Acme Corp' + }, + expirationDate: '2029-12-03T12:19:52Z', + issuer: 'did:web:trustvc.github.io:did:1', + type: ['VerifiableCredential'], + proof: { + type: 'DataIntegrityProof', + cryptosuite: 'ecdsa-sd-2023', + created: '2024-10-02T09:04:07Z', + proofPurpose: 'assertionMethod', + proofValue: 'z...', + verificationMethod: 'did:web:trustvc.github.io:did:1#multikey-1' + } +}; + +const verificationResult = await verifyCredential(ecdsaCredential); - ```js - Credential verified successfully. - ``` -
+if (verificationResult.verified) { + console.log('ECDSA-SD-2023 Credential verified successfully.'); +} else { + console.error('Verification failed:', verificationResult.error); +} +``` ### 3. Deriving a Credential -The deriveCredential function allows you to derive a new credential with selective disclosure using the BBS+ signature proof. +The deriveCredential function allows you to derive a new credential with selective disclosure using either BBS+ or ECDSA-SD-2023 signature schemes. + +#### BBS+ Selective Disclosure ```ts import { deriveCredential } from '@trustvc/w3c-vc'; @@ -255,44 +300,58 @@ if (derivedResult.derived) { } ``` -
- deriveCredential Result - - ```js - Derived Credential: { - '@context': [ - 'https://www.w3.org/2018/credentials/v1', - 'https://w3c-ccg.github.io/citizenship-vocab/contexts/citizenship-v1.jsonld', - 'https://w3id.org/security/bbs/v1', - 'https://w3id.org/vc/status-list/2021/v1' - ], - credentialStatus: { - id: 'https://trustvc.github.io/did/credentials/statuslist/1#1', - statusListCredential: 'https://trustvc.github.io/did/credentials/statuslist/1', - statusListIndex: '1', - statusPurpose: 'revocation', - type: 'StatusList2021Entry' - }, - issuanceDate: '2024-04-01T12:19:52Z', - credentialSubject: { - id: 'did:example:b34ca6cd37bbf23', - type: [ 'Person' ] - }, - expirationDate: '2029-12-03T12:19:52Z', - issuer: 'did:web:trustvc.github.io:did:1', - id: 'urn:bnid:_:c14n0', - type: [ 'VerifiableCredential' ], - proof: { - type: 'BbsBlsSignatureProof2020', - created: '2024-10-02T09:04:07Z', - nonce: 'YsFIiujnENBLMsuuXhyctszyGC72SLqiOvlT8OcvSOD6eDcehcGJgbTx5k+tfK00K5M=', - proofPurpose: 'assertionMethod', - proofValue: 'ABAA/++QJhxxPdA340RTSEwPfgmB1Z3kUnhOCE4ReITG6nSNhHvZxdP24jsvBUzyecIArsS2FZdgscCNVP2K2LvEXJteLh/pDjOVsTMOyuVuDaOPYclXxOJR4D3UQtL0DFhu4wC0NaZ+NXV8j1xG/zyJ+lzn4jrKaPhHyuySKFjCZnlQNVx01Cm3pKzgL94GdKsXsEsAAAB0p7aO6wVq4hcyOKmEK4UALxZHTIMet/QMoVlHI017QSQi8hHu+hnGEmmmpuyluTgrAAAAAnIbawi/noqB4Fb+Q3C8ck73LxWVeqBrisWfadhCfep0FVRp/l2McLCsr9mfcDwhFpDoPfh8jza82Mk0s15Q9J+LwH39CGtwjatgL22bM4Ulnwe+GsyYoOgcN6vbtkmYdw7TNJ+H76mRq1K82vDJ6sQAAAADDUVU/P0Exnz7Dvs5V0rSHEur/ySddDgjU7cZZVRjTARzCr7xpcs/yd9W6FGzvxDSIqwTjBgnah9I6v4QDOAdvVyjoZ+Joppjt1rIER9AYXxIN++wCqQtWqaC/X7jPtPb', - verificationMethod: 'did:web:trustvc.github.io:did:1#keys-1' - } +#### ECDSA-SD-2023 Selective Disclosure + +```ts +import { deriveCredential } from '@trustvc/w3c-vc'; + +/** + * Parameters: + * - credential (SignedVerifiableCredential): The verifiable credential to be selectively disclosed. + * - revealedAttributes (string[]): Array of JSON pointers specifying which fields to reveal. + * + * Returns: + * - A Promise that resolves to: + * - derived (DerivedProof): The selectively disclosed credential with the derived proof. + * - error (string): The error message in case of failure. + */ + +const ecdsaCredential = { + '@context': [ + 'https://www.w3.org/2018/credentials/v1', + 'https://w3id.org/security/data-integrity/v2' + ], + issuanceDate: '2024-04-01T12:19:52Z', + credentialSubject: { + id: 'did:example:b34ca6cd37bbf23', + type: ['Person'], + name: 'TrustVC', + billOfLadingName: 'Acme Corp' + }, + expirationDate: '2029-12-03T12:19:52Z', + issuer: 'did:web:trustvc.github.io:did:1', + type: ['VerifiableCredential'], + proof: { + type: 'DataIntegrityProof', + cryptosuite: 'ecdsa-sd-2023', + created: '2024-10-02T09:04:07Z', + proofPurpose: 'assertionMethod', + proofValue: 'z...', + verificationMethod: 'did:web:trustvc.github.io:did:1#multikey-1' } - ``` -
+}; + +// Reveal only the billOfLadingName field (mandatory pointers are always included) +const selectivePointers = ['/credentialSubject/billOfLadingName']; + +const derivedResult = await deriveCredential(ecdsaCredential, selectivePointers); + +if (derivedResult.derived) { + console.log('Derived ECDSA-SD-2023 Credential:', derivedResult.derived); +} else { + console.error('Error:', derivedResult.error); +} +``` ### 4. Validate if payload meets the schema @@ -316,4 +375,3 @@ console.log('isRawDocument', result1); const result2 = isSignedDocument(document); console.log('isSignedDocument', result2); -``` diff --git a/packages/w3c-vc/package.json b/packages/w3c-vc/package.json index 815e40eb..d4dd3993 100644 --- a/packages/w3c-vc/package.json +++ b/packages/w3c-vc/package.json @@ -31,12 +31,16 @@ } }, "dependencies": { + "@digitalbazaar/data-integrity": "^2.5.0", + "@digitalbazaar/ecdsa-multikey": "^1.8.0", + "@digitalbazaar/ecdsa-sd-2023-cryptosuite": "^3.4.1", "@mattrglobal/jsonld-signatures-bbs": "^1.2.0", "@trustvc/w3c-credential-status": "^1.3.0-alpha.1", "@trustvc/w3c-issuer": "^1.3.0-alpha.1", "did-resolver": "^4.1.0", "jsonld": "^6.0.0", - "jsonld-signatures": "7.0.0", + "jsonld-signatures": "^11.5.0", + "jsonld-signatures-v7": "npm:jsonld-signatures@7.0.0", "uuid": "^10.0.0" }, "overrides": { diff --git a/packages/w3c-vc/src/lib/helper/index.ts b/packages/w3c-vc/src/lib/helper/index.ts index cdfb58da..29f456bf 100644 --- a/packages/w3c-vc/src/lib/helper/index.ts +++ b/packages/w3c-vc/src/lib/helper/index.ts @@ -6,9 +6,14 @@ import { BitstringStatusListCredentialStatus, TransferableRecordsCredentialStatus, } from '@trustvc/w3c-credential-status'; -import { BBSPrivateKeyPair, PrivateKeyPair, VerificationType } from '@trustvc/w3c-issuer'; +import { + Bbs2023PrivateKeyPair, + BBSPrivateKeyPair, + EcdsaSd2023PrivateKeyPair, + PrivateKeyPair, + VerificationType, +} from '@trustvc/w3c-issuer'; import { createHash } from 'crypto'; -// @ts-ignore: No types available for jsonld import * as jsonld from 'jsonld'; import { v7 as uuidv7 } from 'uuid'; import { assertCredentialStatuses } from '../sign/credentialStatus'; @@ -35,6 +40,7 @@ export function _checkKeyPair(keyPair: PrivateKeyPair) { if (!keyPair.id) { throw new Error('"id" property in keyPair is required.'); } + if (keyPair.type === VerificationType.Bls12381G2Key2020) { if (!(keyPair as BBSPrivateKeyPair).privateKeyBase58) { throw new Error('"privateKeyBase58" property in keyPair is required.'); @@ -42,6 +48,15 @@ export function _checkKeyPair(keyPair: PrivateKeyPair) { if (!(keyPair as BBSPrivateKeyPair).publicKeyBase58) { throw new Error('"publicKeyBase58" property in keyPair is required.'); } + } else if (keyPair.type === VerificationType.Multikey) { + // For Multikey types (BBS-2023 and ECDSA-SD-2023), check for multibase keys + const multikeyPair = keyPair as Bbs2023PrivateKeyPair | EcdsaSd2023PrivateKeyPair; + if (!multikeyPair.secretKeyMultibase) { + throw new Error('"secretKeyMultibase" property in keyPair is required.'); + } + if (!multikeyPair.publicKeyMultibase) { + throw new Error('"publicKeyMultibase" property in keyPair is required.'); + } } } @@ -384,15 +399,24 @@ export const _checkCredentialStatus = ( /** * Prefills the credential ID with a UUIDv7. + * Uses blank node format for BBS+ compatibility and proper URI format for ECDSA-SD-2023. * If the credentialStatus is present with type TransferableRecords, set the tokenId. * * @param {RawVerifiableCredential} credential + * @param {string} cryptoSuite - The cryptosuite being used for signing * @returns {RawVerifiableCredential} */ export const prefilCredentialId = ( credential: RawVerifiableCredential, + cryptoSuite?: string, ): RawVerifiableCredential => { - credential.id = `urn:bnid:_:${uuidv7()}`; + // Use proper URI format for ECDSA-SD-2023 + // Use blank node format for BBS+ (maintains backward compatibility) + if (cryptoSuite === 'ecdsa-sd-2023') { + credential.id = `urn:uuid:${uuidv7()}`; + } else { + credential.id = `urn:bnid:_:${uuidv7()}`; + } if (credential?.credentialStatus?.type === 'TransferableRecords') { credential.credentialStatus = { diff --git a/packages/w3c-vc/src/lib/sign/credentialStatus/index.ts b/packages/w3c-vc/src/lib/sign/credentialStatus/index.ts index 2a27bf95..753ab013 100644 --- a/packages/w3c-vc/src/lib/sign/credentialStatus/index.ts +++ b/packages/w3c-vc/src/lib/sign/credentialStatus/index.ts @@ -1,4 +1,3 @@ -// @ts-ignore: No types available for jsonld import * as jsonld from 'jsonld'; import { _checkCredentialStatus, _validateUriId } from '../../helper'; import { CredentialStatus, VerifiableCredential } from '../../types'; diff --git a/packages/w3c-vc/src/lib/types.ts b/packages/w3c-vc/src/lib/types.ts index 8439b906..890592fc 100644 --- a/packages/w3c-vc/src/lib/types.ts +++ b/packages/w3c-vc/src/lib/types.ts @@ -1,4 +1,5 @@ import { BbsBlsSignature2020, BbsBlsSignatureProof2020 } from '@mattrglobal/jsonld-signatures-bbs'; +import { DataIntegrityProof } from '@digitalbazaar/data-integrity'; // Define the type for the signing result export interface SigningResult { @@ -56,12 +57,13 @@ export type SignedVerifiableCredential = { export type RawVerifiableCredential = Omit; -export type ProofType = 'BbsBlsSignature2020' | 'BbsBlsSignatureProof2020'; +export type ProofType = 'BbsBlsSignature2020' | 'BbsBlsSignatureProof2020' | 'DataIntegrityProof'; export const proofTypeMapping: Record< ProofType, - typeof BbsBlsSignature2020 | typeof BbsBlsSignatureProof2020 + typeof BbsBlsSignature2020 | typeof BbsBlsSignatureProof2020 | typeof DataIntegrityProof > = { BbsBlsSignature2020: BbsBlsSignature2020, BbsBlsSignatureProof2020: BbsBlsSignatureProof2020, + DataIntegrityProof: DataIntegrityProof, }; diff --git a/packages/w3c-vc/src/lib/w3c-vc.test.ts b/packages/w3c-vc/src/lib/w3c-vc.test.ts index b903aee0..6e701183 100644 --- a/packages/w3c-vc/src/lib/w3c-vc.test.ts +++ b/packages/w3c-vc/src/lib/w3c-vc.test.ts @@ -1,6 +1,7 @@ -import { VerificationType } from '@trustvc/w3c-issuer'; +import { EcdsaSd2023PrivateKeyPair, VerificationType } from '@trustvc/w3c-issuer'; import { describe, expect, it } from 'vitest'; import { deriveCredential, signCredential, verifyCredential } from './w3c-vc'; +import { VerifiableCredential } from './types'; const modifiedCredential: any = { '@context': [ @@ -95,6 +96,79 @@ const modifiedKeyPair: any = { 'oRfEeWFresvhRtXCkihZbxyoi2JER7gHTJ5psXhHsdCoU1MttRMi3Yp9b9fpjmKh7bMgfWKLESiK2YovRd8KGzJsGuamoAXfqDDVhckxuc9nmsJ84skCSTijKeU4pfAcxeJ', }; +// ECDSA-SD-2023 key pair for testing +const ecdsaKeyPair: EcdsaSd2023PrivateKeyPair = { + '@context': 'https://w3id.org/security/multikey/v1', + id: 'did:web:trustvc.github.io:did:1#multikey-1', + type: VerificationType.Multikey, + controller: 'did:web:trustvc.github.io:did:1', + publicKeyMultibase: 'zDnaemDNwi4G5eTzGfRooFFu5Kns3be6yfyVNtiaMhWkZbwtc', + secretKeyMultibase: 'z42tmUXTVn3n9BihE6NhdMpvVBTnFTgmb6fw18o5Ud6puhRW', +}; + +// Modified credential for ECDSA-SD-2023 testing +const ecdsaCredential: VerifiableCredential = { + '@context': [ + 'https://www.w3.org/2018/credentials/v1', + 'https://w3id.org/security/data-integrity/v2', + 'https://w3id.org/vc/status-list/2021/v1', + 'https://trustvc.io/context/transferable-records-context.json', + 'https://trustvc.io/context/render-method-context.json', + 'https://trustvc.io/context/attachments-context.json', + 'https://trustvc.io/context/qrcode-context.json', + 'https://trustvc.io/context/bill-of-lading.json', + ], + qrCode: { + type: 'TrustVCQRCode', + uri: 'https://localhost:3000/qrcode', + }, + credentialStatus: { + type: 'TransferableRecords', + tokenNetwork: { + chain: 'MATIC', + chainId: '80001', + }, + tokenRegistry: '0xE0a94770B8e969B5D9179d6dA8730B01e19279e2', + }, + credentialSubject: { + billOfLadingName: 'TrustVC Bill of Lading', + scac: 'SGPU', + blNumber: 'SGCNM21566325', + vessel: 'vessel', + voyageNo: 'voyageNo', + portOfLoading: 'Singapore', + portOfDischarge: 'Paris', + carrierName: 'A.P. Moller', + placeOfReceipt: 'Beijing', + placeOfDelivery: 'Singapore', + packages: [ + { packagesDescription: 'package 1', packagesWeight: '10', packagesMeasurement: '20' }, + { packagesDescription: 'package 2', packagesWeight: '10', packagesMeasurement: '20' }, + ], + shipperName: 'Shipper Name', + shipperAddressStreet: '101 ORCHARD ROAD', + shipperAddressCountry: 'SINGAPORE', + consigneeName: 'Consignee name', + notifyPartyName: 'Notify Party Name', + links: 'https://localhost:3000/url', + attachments: [ + { data: 'BASE64_ENCODED_FILE', filename: 'sample1.pdf', mimeType: 'application/pdf' }, + { data: 'BASE64_ENCODED_FILE', filename: 'sample2.pdf', mimeType: 'application/pdf' }, + ], + type: ['BillOfLading'], + }, + renderMethod: [ + { + id: 'https://localhost:3000/renderer', + type: 'EMBEDDED_RENDERER', + templateName: 'BILL_OF_LADING', + }, + ], + expirationDate: '2029-12-03T12:19:52Z', + issuer: 'did:web:trustvc.github.io:did:1', + type: ['VerifiableCredential'], +}; + describe('Credential Signing and Verification', () => { it('should successfully sign, derive and verify a credential', async () => { let signingKeyPair = modifiedKeyPair; @@ -235,6 +309,126 @@ describe('Credential Signing and Verification', () => { const verificationResult = await verifyCredential(signedCredential); expect(verificationResult.verified).toBe(false); - expect(verificationResult.error).equals('Verification method could not be found.'); + expect(verificationResult.error).equals( + 'Verification method did:web:trustvc.github.io:did:1#keys-2 could not be found.', + ); + }); +}); + +describe('ECDSA-SD-2023 Credential Signing and Verification', () => { + it('should successfully sign, derive, and verify a credential with ECDSA-SD-2023', async () => { + let credential = ecdsaCredential; + credential = { ...credential, issuanceDate: '2024-04-01T12:19:52Z' }; + + // Sign the credential + const signedCredential = await signCredential(credential, ecdsaKeyPair, 'ecdsa-sd-2023'); + expect(signedCredential.signed).toBeDefined(); + expect(signedCredential.error).toBeUndefined(); + expect(signedCredential.signed?.proof?.type).toBe('DataIntegrityProof'); + + // Derive the credential with selective disclosure + const selectivePointers = ['/credentialSubject/billOfLadingName', '/issuer', '/issuanceDate']; + const derivedCredential = await deriveCredential(signedCredential.signed, selectivePointers); + expect(derivedCredential.derived).toBeDefined(); + expect(derivedCredential.error).toBeUndefined(); + + // Verify that all selective pointers are included in the derived credential + expect(derivedCredential.derived?.issuer).toBeDefined(); + expect(derivedCredential.derived?.issuanceDate).toBeDefined(); + const credentialSubject = Array.isArray(derivedCredential.derived?.credentialSubject) + ? derivedCredential.derived?.credentialSubject[0] + : derivedCredential.derived?.credentialSubject; + expect(credentialSubject?.billOfLadingName).toBeDefined(); + + // Verify the derived credential + const verificationResult = await verifyCredential(derivedCredential.derived); + expect(verificationResult.verified).toBe(true); + expect(verificationResult.error).toBeUndefined(); + }); + + it('should successfully sign with custom mandatory pointers, derive, and verify', async () => { + let credential = ecdsaCredential; + credential = { ...credential, issuanceDate: '2024-04-01T12:19:52Z' }; + + const customMandatoryPointers = [ + '/issuer', + '/issuanceDate', + '/credentialSubject/billOfLadingName', + ]; + + // Sign with custom mandatory pointers + const signedCredential = await signCredential(credential, ecdsaKeyPair, 'ecdsa-sd-2023', { + mandatoryPointers: customMandatoryPointers, + }); + expect(signedCredential.signed).toBeDefined(); + expect(signedCredential.error).toBeUndefined(); + expect(signedCredential.signed?.proof?.type).toBe('DataIntegrityProof'); + + // Derive with selective disclosure (only reveal specific fields) + const selectivePointers = ['/credentialSubject/blNumber']; + const derivedCredential = await deriveCredential(signedCredential.signed, selectivePointers); + expect(derivedCredential.derived).toBeDefined(); + expect(derivedCredential.error).toBeUndefined(); + + // Verify that mandatory pointers are always included (even though not in selectivePointers) + expect(derivedCredential.derived?.issuer).toBeDefined(); + expect(derivedCredential.derived?.issuanceDate).toBeDefined(); + const credentialSubject = Array.isArray(derivedCredential.derived?.credentialSubject) + ? derivedCredential.derived?.credentialSubject[0] + : derivedCredential.derived?.credentialSubject; + expect(credentialSubject?.billOfLadingName).toBeDefined(); + + // Verify that selective pointers are included + expect(credentialSubject?.blNumber).toBeDefined(); + + // Verify the derived credential + const verificationResult = await verifyCredential(derivedCredential.derived); + expect(verificationResult.verified).toBe(true); + expect(verificationResult.error).toBeUndefined(); + }); + + it('should require derivation before verification for ECDSA-SD-2023 credentials', async () => { + let credential = ecdsaCredential; + credential = { ...credential, issuanceDate: '2024-04-01T12:19:52Z' }; + + // Sign the credential + const signedCredential = await signCredential(credential, ecdsaKeyPair, 'ecdsa-sd-2023'); + expect(signedCredential.signed).toBeDefined(); + expect(signedCredential.error).toBeUndefined(); + + // Verify the original signed credential directly (without derivation) - should fail + // ECDSA-SD-2023 credentials require derivation before verification + const verificationResult = await verifyCredential(signedCredential.signed); + expect(verificationResult.verified).toBe(false); + expect(verificationResult.error).toBeDefined(); + expect(verificationResult.error).toContain('proofValue'); + }); + + it('should fail to sign with ECDSA-SD-2023 if key pair is missing required properties', async () => { + let credential = ecdsaCredential; + credential = { ...credential, issuanceDate: '2024-04-01T12:19:52Z' }; + + const invalidKeyPair: any = { + id: 'did:web:trustvc.github.io:did:1#multikey-1', + type: 'Multikey', + controller: 'did:web:trustvc.github.io:did:1', + publicKeyMultibase: 'zDnaemDNwi4G5eTzGfRooFFu5Kns3be6yfyVNtiaMhWkZbwtc', + // Missing secretKeyMultibase + }; + + const signedCredential = await signCredential(credential, invalidKeyPair, 'ecdsa-sd-2023'); + expect(signedCredential.signed).toBeUndefined(); + expect(signedCredential.error).toBeDefined(); + expect(signedCredential.error).toBe('"secretKeyMultibase" property in keyPair is required.'); + }); + + it('should fail to sign with unsupported cryptosuite', async () => { + let credential = ecdsaCredential; + credential = { ...credential, issuanceDate: '2024-04-01T12:19:52Z' }; + + const signedCredential = await signCredential(credential, ecdsaKeyPair, 'unsupported-suite'); + expect(signedCredential.signed).toBeUndefined(); + expect(signedCredential.error).toBeDefined(); + expect(signedCredential.error).toBe('"unsupported-suite" is not supported.'); }); }); diff --git a/packages/w3c-vc/src/lib/w3c-vc.ts b/packages/w3c-vc/src/lib/w3c-vc.ts index bf45d80c..b2b104dc 100644 --- a/packages/w3c-vc/src/lib/w3c-vc.ts +++ b/packages/w3c-vc/src/lib/w3c-vc.ts @@ -5,11 +5,13 @@ import { Bls12381G2KeyPair, deriveProof, } from '@mattrglobal/jsonld-signatures-bbs'; +import * as EcdsaMultikey from '@digitalbazaar/ecdsa-multikey'; +import * as ecdsaSd2023Cryptosuite from '@digitalbazaar/ecdsa-sd-2023-cryptosuite'; +import { DataIntegrityProof } from '@digitalbazaar/data-integrity'; import { ContextDocument, DocumentLoader, getDocumentLoader } from '@trustvc/w3c-context'; import { PrivateKeyPair } from '@trustvc/w3c-issuer'; -// @ts-ignore: No types available for jsonld-signatures import jsonldSignatures from 'jsonld-signatures'; -// @ts-ignore: No types available for jsonld +import jsonldSignaturesV7 from 'jsonld-signatures-v7'; import * as jsonld from 'jsonld'; import { _checkCredential, _checkKeyPair, prefilCredentialId } from './helper'; import { @@ -22,6 +24,15 @@ import { VerificationResult, } from './types'; +const { createSignCryptosuite, createDiscloseCryptosuite, createVerifyCryptosuite } = + ecdsaSd2023Cryptosuite; +const { + purposes: { AssertionProofPurpose }, +} = jsonldSignatures; +const { + purposes: { AssertionProofPurpose: AssertionProofPurposeV7 }, +} = jsonldSignaturesV7; + /** * Checks if the input document is a raw credential. * @param {RawVerifiableCredential | unknown} document - The raw credential to be checked. @@ -57,6 +68,7 @@ export const isSignedDocument = ( * @param {object} credential - The credential to be signed. * @param {object} keyPair - The key pair options for signing. * @param {string} cryptoSuite - The cryptosuite to be used for signing. Defaults to 'BbsBlsSignature2020'. + * @param {object} options - Optional parameters including documentLoader and mandatoryPointers for ECDSA-SD-2023. * @returns {Promise} The signed credential or an error message in case of failure. */ export const signCredential = async ( @@ -65,25 +77,54 @@ export const signCredential = async ( cryptoSuite = 'BbsBlsSignature2020', options?: { documentLoader?: DocumentLoader; + mandatoryPointers?: string[]; }, ): Promise => { try { + const documentLoader = options?.documentLoader ?? (await getDocumentLoader()); + if (cryptoSuite === 'BbsBlsSignature2020') { _checkKeyPair(keyPair); _checkCredential(credential, undefined, 'sign'); - const documentLoader = options?.documentLoader ?? (await getDocumentLoader()); const key = new Bls12381G2KeyPair(keyPair as KeyPairOptions); // This ensures each credential has a distinct, system-generated ID in the UUIDv7 format - credential = prefilCredentialId(credential); + credential = prefilCredentialId(credential, cryptoSuite); - const signed = await jsonldSignatures.sign(credential, { + const signed = await jsonldSignaturesV7.sign(credential, { suite: new BbsBlsSignature2020({ key }), - purpose: new jsonldSignatures.purposes.AssertionProofPurpose(), + purpose: new AssertionProofPurposeV7(), documentLoader, }); + return { signed: signed }; + } else if (cryptoSuite === 'ecdsa-sd-2023') { + _checkKeyPair(keyPair); + _checkCredential(credential, undefined, 'sign'); + + // Import the key pair object into a usable signer instance + const ecdsaKeyPair = await EcdsaMultikey.from({ ...keyPair }); + + // Default mandatory pointers for selective disclosure + const mandatoryPointers = options?.mandatoryPointers || []; + + // Create the DataIntegrityProof suite using the ECDSA-SD cryptosuite + const suite = new DataIntegrityProof({ + signer: ecdsaKeyPair.signer(), + cryptosuite: createSignCryptosuite({ + mandatoryPointers: mandatoryPointers, + }), + }); + + // This ensures each credential has a distinct, system-generated ID in the UUIDv7 format + credential = prefilCredentialId(credential, cryptoSuite); + + const signed = await jsonldSignatures.sign(credential, { + suite, + purpose: new AssertionProofPurpose(), + documentLoader, + }); return { signed: signed }; } else { return { error: `"${cryptoSuite}" is not supported.` }; @@ -108,7 +149,7 @@ export const signCredential = async ( }; /** - * Verifies a credential using the BBS+ signature scheme. + * Verifies a credential using the BBS+ signature scheme or ECDSA-SD-2023. * @param {object} credential - The credential to be verified. * @returns {Promise} The verification result indicating success * or failure, along with an error message if applicable. @@ -127,12 +168,30 @@ export const verifyCredential = async ( const proofType = jsonld.getValues(credential, 'proof')[0].type as ProofType; const SuiteClass = proofTypeMapping[proofType]; - if (SuiteClass) - verificationResult = await jsonldSignatures.verify(credential, { - suite: new SuiteClass(), - purpose: new jsonldSignatures.purposes.AssertionProofPurpose(), - documentLoader, - }); + if (SuiteClass) { + if (proofType === 'DataIntegrityProof') { + // Check the cryptosuite to determine the specific verification approach + const proof = jsonld.getValues(credential, 'proof')[0]; + const cryptosuite = proof.cryptosuite; + + if (cryptosuite === 'ecdsa-sd-2023') { + verificationResult = await jsonldSignatures.verify(credential, { + suite: new DataIntegrityProof({ + cryptosuite: createVerifyCryptosuite(), + }), + purpose: new AssertionProofPurpose(), + documentLoader, + }); + } + } else { + // For BBS+ proofs, create the suite normally + verificationResult = await jsonldSignaturesV7.verify(credential, { + suite: new SuiteClass(), + purpose: new AssertionProofPurposeV7(), + documentLoader, + }); + } + } if (verificationResult.verified) { return { verified: true }; @@ -173,12 +232,13 @@ export const verifyCredential = async ( /** * Derives a credential with selective disclosure based on revealed attributes. * @param {object} credential - The verifiable credential to be selectively disclosed. - * @param {object} revealedAttributes - The attributes from the credential that should be revealed in the derived proof. + * @param {object|string[]} revealedAttributes - For BBS+: The attributes from the credential that should be revealed. For ECDSA-SD-2023: Array of selective pointers. + * @param {object} options - Optional parameters including documentLoader. * @returns {Promise} A DerivedResult containing the derived proof or an error message. */ export const deriveCredential = async ( credential: SignedVerifiableCredential, - revealedAttributes: ContextDocument, + revealedAttributes: ContextDocument | string[], options?: { documentLoader?: DocumentLoader; }, @@ -187,13 +247,53 @@ export const deriveCredential = async ( _checkCredential(credential); const documentLoader = options?.documentLoader ?? (await getDocumentLoader()); - // Generate a derived proof with selective disclosure using the BbsBlsSignatureProof2020 suite - const derivedProof = await deriveProof(credential, revealedAttributes, { - suite: new BbsBlsSignatureProof2020(), - documentLoader, - }); + const proofType = jsonld.getValues(credential, 'proof')[0].type as ProofType; + + if (proofType === 'BbsBlsSignature2020') { + // For BBS+, use the existing deriveProof function with revealedAttributes + const derivedProof = await deriveProof(credential, revealedAttributes as ContextDocument, { + suite: new BbsBlsSignatureProof2020(), + documentLoader, + }); + return { derived: derivedProof }; + } else if (proofType === 'DataIntegrityProof') { + // Check the cryptosuite to determine the specific proof type + const proof = jsonld.getValues(credential, 'proof')[0]; + const cryptosuite = proof.cryptosuite; + + if (cryptosuite === 'ecdsa-sd-2023') { + // For ECDSA-SD-2023, use selective pointers (can be empty array for mandatory-only disclosure) + if (!Array.isArray(revealedAttributes)) { + return { + error: `${cryptosuite} requires revealedAttributes to be an array of JSON pointers (string[]).`, + }; + } - return { derived: derivedProof }; + const selectivePointers = revealedAttributes; + + // Create the DataIntegrityProof suite for disclosure + const suite = new DataIntegrityProof({ + cryptosuite: createDiscloseCryptosuite({ + selectivePointers, + }), + }); + + // Derive the selectively disclosed credential + const derivedProof = await jsonldSignatures.derive(credential, { + suite, + purpose: new AssertionProofPurpose(), + documentLoader, + }); + + return { derived: derivedProof }; + } else { + return { + error: `DataIntegrityProof with cryptosuite "${cryptosuite}" is not supported for derivation.`, + }; + } + } else { + return { error: `Proof type "${proofType}" is not supported for derivation.` }; + } } catch (err: unknown) { // Handle any errors that occur during the proof derivation process if (!(err instanceof Error)) { diff --git a/packages/w3c-vc/tsconfig.build.json b/packages/w3c-vc/tsconfig.build.json index 1f1061f9..22b520bc 100644 --- a/packages/w3c-vc/tsconfig.build.json +++ b/packages/w3c-vc/tsconfig.build.json @@ -8,6 +8,6 @@ "rootDir": ".", "baseUrl": "." }, - "include": ["src/**/*.ts", "src/**/*.json"], + "include": ["src/**/*.ts", "src/**/*.json", "../declaration.d.ts"], "exclude": ["node_modules", ".coverage", "src/**/*.spec.ts", "src/**/*.test.ts"] } From 77b1898e89e930b53e04fdf646d7f99708ddab27 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Thu, 7 Aug 2025 03:29:04 +0000 Subject: [PATCH 027/122] chore(release): @trustvc/w3c-issuer@1.3.0-alpha.2 [skip ci] # [1.3.0-alpha.2](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-issuer@1.3.0-alpha.1...@trustvc/w3c-issuer@1.3.0-alpha.2) (2025-08-07) ### Features * add ecdsa-sd-2023 support ([#68](https://github.com/TrustVC/w3c/issues/68)) ([20d5e69](https://github.com/TrustVC/w3c/commit/20d5e69328f60c34dd210c12734604b59f457030)) --- packages/w3c-issuer/CHANGELOG.md | 7 +++++++ packages/w3c-issuer/package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/w3c-issuer/CHANGELOG.md b/packages/w3c-issuer/CHANGELOG.md index 8008c9fe..2fcddad8 100644 --- a/packages/w3c-issuer/CHANGELOG.md +++ b/packages/w3c-issuer/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.2](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-issuer@1.3.0-alpha.1...@trustvc/w3c-issuer@1.3.0-alpha.2) (2025-08-07) + + +### Features + +* add ecdsa-sd-2023 support ([#68](https://github.com/TrustVC/w3c/issues/68)) ([20d5e69](https://github.com/TrustVC/w3c/commit/20d5e69328f60c34dd210c12734604b59f457030)) + # [1.3.0-alpha.1](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-issuer@1.2.1...@trustvc/w3c-issuer@1.3.0-alpha.1) (2025-07-31) diff --git a/packages/w3c-issuer/package.json b/packages/w3c-issuer/package.json index f885e5a8..3330e045 100644 --- a/packages/w3c-issuer/package.json +++ b/packages/w3c-issuer/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c-issuer", - "version": "1.3.0-alpha.1", + "version": "1.3.0-alpha.2", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", From 7fca3d0e938649eafe3bfe947f6d16a31f2fd876 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Thu, 7 Aug 2025 03:29:42 +0000 Subject: [PATCH 028/122] chore(release): @trustvc/w3c-context@1.3.0-alpha.2 [skip ci] # [1.3.0-alpha.2](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-context@1.3.0-alpha.1...@trustvc/w3c-context@1.3.0-alpha.2) (2025-08-07) ### Features * add ecdsa-sd-2023 support ([#68](https://github.com/TrustVC/w3c/issues/68)) ([20d5e69](https://github.com/TrustVC/w3c/commit/20d5e69328f60c34dd210c12734604b59f457030)) --- packages/w3c-context/CHANGELOG.md | 7 +++++++ packages/w3c-context/package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/w3c-context/CHANGELOG.md b/packages/w3c-context/CHANGELOG.md index 04507bdf..1bb1861b 100644 --- a/packages/w3c-context/CHANGELOG.md +++ b/packages/w3c-context/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.2](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-context@1.3.0-alpha.1...@trustvc/w3c-context@1.3.0-alpha.2) (2025-08-07) + + +### Features + +* add ecdsa-sd-2023 support ([#68](https://github.com/TrustVC/w3c/issues/68)) ([20d5e69](https://github.com/TrustVC/w3c/commit/20d5e69328f60c34dd210c12734604b59f457030)) + # [1.3.0-alpha.1](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-context@1.2.3-alpha.2...@trustvc/w3c-context@1.3.0-alpha.1) (2025-07-31) diff --git a/packages/w3c-context/package.json b/packages/w3c-context/package.json index 002a7241..896173d9 100644 --- a/packages/w3c-context/package.json +++ b/packages/w3c-context/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c-context", - "version": "1.3.0-alpha.1", + "version": "1.3.0-alpha.2", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", From d348a8b6f1b39e91b216b6cd7a04ca4f04e222a9 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Thu, 7 Aug 2025 03:30:22 +0000 Subject: [PATCH 029/122] chore(release): @trustvc/w3c-credential-status@1.3.0-alpha.2 [skip ci] # [1.3.0-alpha.2](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-credential-status@1.3.0-alpha.1...@trustvc/w3c-credential-status@1.3.0-alpha.2) (2025-08-07) ### Features * add ecdsa-sd-2023 support ([#68](https://github.com/TrustVC/w3c/issues/68)) ([20d5e69](https://github.com/TrustVC/w3c/commit/20d5e69328f60c34dd210c12734604b59f457030)) --- packages/w3c-credential-status/CHANGELOG.md | 7 +++++++ packages/w3c-credential-status/package.json | 6 +++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/packages/w3c-credential-status/CHANGELOG.md b/packages/w3c-credential-status/CHANGELOG.md index 400ece95..affce16c 100644 --- a/packages/w3c-credential-status/CHANGELOG.md +++ b/packages/w3c-credential-status/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.2](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-credential-status@1.3.0-alpha.1...@trustvc/w3c-credential-status@1.3.0-alpha.2) (2025-08-07) + + +### Features + +* add ecdsa-sd-2023 support ([#68](https://github.com/TrustVC/w3c/issues/68)) ([20d5e69](https://github.com/TrustVC/w3c/commit/20d5e69328f60c34dd210c12734604b59f457030)) + # [1.3.0-alpha.1](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-credential-status@1.2.3-alpha.2...@trustvc/w3c-credential-status@1.3.0-alpha.1) (2025-07-31) diff --git a/packages/w3c-credential-status/package.json b/packages/w3c-credential-status/package.json index 060f2904..5e7fcdb8 100644 --- a/packages/w3c-credential-status/package.json +++ b/packages/w3c-credential-status/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c-credential-status", - "version": "1.3.0-alpha.1", + "version": "1.3.0-alpha.2", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", @@ -29,8 +29,8 @@ } }, "dependencies": { - "@trustvc/w3c-context": "^1.3.0-alpha.1", - "@trustvc/w3c-issuer": "^1.3.0-alpha.1", + "@trustvc/w3c-context": "^1.3.0-alpha.2", + "@trustvc/w3c-issuer": "^1.3.0-alpha.2", "base64url-universal": "^2.0.0", "pako": "^2.1.0" }, From e1ecbf1b4066f8486bc5f888e0d0e7129ae58689 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Thu, 7 Aug 2025 03:31:02 +0000 Subject: [PATCH 030/122] chore(release): @trustvc/w3c-vc@1.3.0-alpha.2 [skip ci] # [1.3.0-alpha.2](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.3.0-alpha.1...@trustvc/w3c-vc@1.3.0-alpha.2) (2025-08-07) ### Features * add ecdsa-sd-2023 support ([#68](https://github.com/TrustVC/w3c/issues/68)) ([20d5e69](https://github.com/TrustVC/w3c/commit/20d5e69328f60c34dd210c12734604b59f457030)) --- packages/w3c-vc/CHANGELOG.md | 7 +++++++ packages/w3c-vc/package.json | 6 +++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/packages/w3c-vc/CHANGELOG.md b/packages/w3c-vc/CHANGELOG.md index 3a060809..f1da1588 100644 --- a/packages/w3c-vc/CHANGELOG.md +++ b/packages/w3c-vc/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.2](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.3.0-alpha.1...@trustvc/w3c-vc@1.3.0-alpha.2) (2025-08-07) + + +### Features + +* add ecdsa-sd-2023 support ([#68](https://github.com/TrustVC/w3c/issues/68)) ([20d5e69](https://github.com/TrustVC/w3c/commit/20d5e69328f60c34dd210c12734604b59f457030)) + # [1.3.0-alpha.1](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.2.7-alpha.3...@trustvc/w3c-vc@1.3.0-alpha.1) (2025-07-31) diff --git a/packages/w3c-vc/package.json b/packages/w3c-vc/package.json index d4dd3993..3ec0edeb 100644 --- a/packages/w3c-vc/package.json +++ b/packages/w3c-vc/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c-vc", - "version": "1.3.0-alpha.1", + "version": "1.3.0-alpha.2", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", @@ -35,8 +35,8 @@ "@digitalbazaar/ecdsa-multikey": "^1.8.0", "@digitalbazaar/ecdsa-sd-2023-cryptosuite": "^3.4.1", "@mattrglobal/jsonld-signatures-bbs": "^1.2.0", - "@trustvc/w3c-credential-status": "^1.3.0-alpha.1", - "@trustvc/w3c-issuer": "^1.3.0-alpha.1", + "@trustvc/w3c-credential-status": "^1.3.0-alpha.2", + "@trustvc/w3c-issuer": "^1.3.0-alpha.2", "did-resolver": "^4.1.0", "jsonld": "^6.0.0", "jsonld-signatures": "^11.5.0", From c4d2265975f1281afe23a60c9893d1ed936a7a4b Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Thu, 7 Aug 2025 03:31:40 +0000 Subject: [PATCH 031/122] chore(release): @trustvc/w3c-cli@1.3.0-alpha.2 [skip ci] # [1.3.0-alpha.2](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-cli@1.3.0-alpha.1...@trustvc/w3c-cli@1.3.0-alpha.2) (2025-08-07) ### Features * add ecdsa-sd-2023 support ([#68](https://github.com/TrustVC/w3c/issues/68)) ([20d5e69](https://github.com/TrustVC/w3c/commit/20d5e69328f60c34dd210c12734604b59f457030)) --- apps/w3c-cli/CHANGELOG.md | 7 +++++++ apps/w3c-cli/package.json | 10 +++++----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/apps/w3c-cli/CHANGELOG.md b/apps/w3c-cli/CHANGELOG.md index 75a7b8fe..3a622d38 100644 --- a/apps/w3c-cli/CHANGELOG.md +++ b/apps/w3c-cli/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.2](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-cli@1.3.0-alpha.1...@trustvc/w3c-cli@1.3.0-alpha.2) (2025-08-07) + + +### Features + +* add ecdsa-sd-2023 support ([#68](https://github.com/TrustVC/w3c/issues/68)) ([20d5e69](https://github.com/TrustVC/w3c/commit/20d5e69328f60c34dd210c12734604b59f457030)) + # [1.3.0-alpha.1](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-cli@1.2.7-alpha.3...@trustvc/w3c-cli@1.3.0-alpha.1) (2025-07-31) diff --git a/apps/w3c-cli/package.json b/apps/w3c-cli/package.json index 1daddbdc..641a4859 100644 --- a/apps/w3c-cli/package.json +++ b/apps/w3c-cli/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c-cli", - "version": "1.3.0-alpha.1", + "version": "1.3.0-alpha.2", "description": "CLI for TrustVC W3C", "main": "dist/main.js", "types": "dist/main.d.ts", @@ -34,10 +34,10 @@ }, "dependencies": { "@inquirer/prompts": "^5.3.8", - "@trustvc/w3c-context": "^1.3.0-alpha.1", - "@trustvc/w3c-credential-status": "^1.3.0-alpha.1", - "@trustvc/w3c-vc": "^1.3.0-alpha.1", - "@trustvc/w3c-issuer": "^1.3.0-alpha.1", + "@trustvc/w3c-context": "^1.3.0-alpha.2", + "@trustvc/w3c-credential-status": "^1.3.0-alpha.2", + "@trustvc/w3c-vc": "^1.3.0-alpha.2", + "@trustvc/w3c-issuer": "^1.3.0-alpha.2", "@types/yargs": "^17.0.32", "chalk": "^4.1.2", "inquirer": "^10.0.1", From b63352fa1b5895756d7d039f22da417885d032e2 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Thu, 7 Aug 2025 03:32:18 +0000 Subject: [PATCH 032/122] chore(release): @trustvc/w3c@1.3.0-alpha.2 [skip ci] # [1.3.0-alpha.2](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.3.0-alpha.1...@trustvc/w3c@1.3.0-alpha.2) (2025-08-07) ### Features * add ecdsa-sd-2023 support ([#68](https://github.com/TrustVC/w3c/issues/68)) ([20d5e69](https://github.com/TrustVC/w3c/commit/20d5e69328f60c34dd210c12734604b59f457030)) --- packages/w3c/CHANGELOG.md | 7 +++++++ packages/w3c/package.json | 10 +++++----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/packages/w3c/CHANGELOG.md b/packages/w3c/CHANGELOG.md index 0e9ade8d..3f2c941e 100644 --- a/packages/w3c/CHANGELOG.md +++ b/packages/w3c/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.2](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.3.0-alpha.1...@trustvc/w3c@1.3.0-alpha.2) (2025-08-07) + + +### Features + +* add ecdsa-sd-2023 support ([#68](https://github.com/TrustVC/w3c/issues/68)) ([20d5e69](https://github.com/TrustVC/w3c/commit/20d5e69328f60c34dd210c12734604b59f457030)) + # [1.3.0-alpha.1](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.2.7-alpha.3...@trustvc/w3c@1.3.0-alpha.1) (2025-07-31) diff --git a/packages/w3c/package.json b/packages/w3c/package.json index 71b8ec81..b3656c39 100644 --- a/packages/w3c/package.json +++ b/packages/w3c/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c", - "version": "1.3.0-alpha.1", + "version": "1.3.0-alpha.2", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", @@ -32,10 +32,10 @@ } }, "dependencies": { - "@trustvc/w3c-context": "^1.3.0-alpha.1", - "@trustvc/w3c-credential-status": "^1.3.0-alpha.1", - "@trustvc/w3c-issuer": "^1.3.0-alpha.1", - "@trustvc/w3c-vc": "^1.3.0-alpha.1" + "@trustvc/w3c-context": "^1.3.0-alpha.2", + "@trustvc/w3c-credential-status": "^1.3.0-alpha.2", + "@trustvc/w3c-issuer": "^1.3.0-alpha.2", + "@trustvc/w3c-vc": "^1.3.0-alpha.2" }, "repository": { "type": "git", From e4219eefbc79fbc7ae7a495f1b989be9b4205e3c Mon Sep 17 00:00:00 2001 From: rongquan1 <85145303+rongquan1@users.noreply.github.com> Date: Wed, 13 Aug 2025 10:37:18 +0800 Subject: [PATCH 033/122] feat: add support for w3c vc data model v2 (#69) * feat: add support for w3c vc data model v2 * fix: refactor * fix: add version specific credential validation helper --- package-lock.json | 82 ++++- packages/w3c-context/package.json | 2 +- packages/w3c-context/src/lib/index.ts | 4 +- packages/w3c-vc/README.md | 18 +- packages/w3c-vc/src/lib/helper/index.ts | 112 +++++-- packages/w3c-vc/src/lib/types.ts | 2 + packages/w3c-vc/src/lib/w3c-vc.test.ts | 402 +++++++++++++++++------- packages/w3c-vc/src/lib/w3c-vc.ts | 124 +++++++- 8 files changed, 588 insertions(+), 158 deletions(-) diff --git a/package-lock.json b/package-lock.json index 892b38fc..66a5bd43 100644 --- a/package-lock.json +++ b/package-lock.json @@ -32816,12 +32816,92 @@ "license": "Apache-2.0", "dependencies": { "did-resolver": "^4.1.0", - "jsonld-signatures-v7": "npm:jsonld-signatures@7.0.0" + "jsonld-signatures": "^11.5.0" }, "engines": { "node": ">=18.x" } }, + "packages/w3c-context/node_modules/jsonld": { + "version": "8.3.3", + "resolved": "https://registry.npmjs.org/jsonld/-/jsonld-8.3.3.tgz", + "integrity": "sha512-9YcilrF+dLfg9NTEof/mJLMtbdX1RJ8dbWtJgE00cMOIohb1lIyJl710vFiTaiHTl6ZYODJuBd32xFvUhmv3kg==", + "dependencies": { + "@digitalbazaar/http-client": "^3.4.1", + "canonicalize": "^1.0.1", + "lru-cache": "^6.0.0", + "rdf-canonize": "^3.4.0" + }, + "engines": { + "node": ">=14" + } + }, + "packages/w3c-context/node_modules/jsonld-signatures": { + "version": "11.5.0", + "resolved": "https://registry.npmjs.org/jsonld-signatures/-/jsonld-signatures-11.5.0.tgz", + "integrity": "sha512-Kdto+e8uvY/5u3HYkmAbpy52bplWX9uqS8fmqdCv6oxnCFwCTM0hMt6r4rWqlhw5/aHoCHJIRxwYb4QKGC69Jw==", + "dependencies": { + "@digitalbazaar/security-context": "^1.0.0", + "jsonld": "^8.0.0", + "rdf-canonize": "^4.0.1", + "serialize-error": "^8.1.0" + }, + "engines": { + "node": ">=18" + } + }, + "packages/w3c-context/node_modules/jsonld-signatures/node_modules/rdf-canonize": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/rdf-canonize/-/rdf-canonize-4.0.1.tgz", + "integrity": "sha512-B5ynHt4sasbUafzrvYI2GFARgeFcD8Sx9yXPbg7gEyT2EH76rlCv84kyO6tnxzVbxUN/uJDbK1S/MXh+DsnuTA==", + "dependencies": { + "setimmediate": "^1.0.5" + }, + "engines": { + "node": ">=18" + } + }, + "packages/w3c-context/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "packages/w3c-context/node_modules/serialize-error": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-8.1.0.tgz", + "integrity": "sha512-3NnuWfM6vBYoy5gZFvHiYsVbafvI9vZv/+jlIigFn4oP4zjNPK3LhcY0xSCgeb1a5L8jO71Mit9LlNoi2UfDDQ==", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "packages/w3c-context/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "packages/w3c-context/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, "packages/w3c-credential-status": { "name": "@trustvc/w3c-credential-status", "version": "1.3.0-alpha.1", diff --git a/packages/w3c-context/package.json b/packages/w3c-context/package.json index 896173d9..e750637e 100644 --- a/packages/w3c-context/package.json +++ b/packages/w3c-context/package.json @@ -34,7 +34,7 @@ }, "dependencies": { "did-resolver": "^4.1.0", - "jsonld-signatures-v7": "npm:jsonld-signatures@7.0.0" + "jsonld-signatures": "^11.5.0" }, "repository": { "type": "git", diff --git a/packages/w3c-context/src/lib/index.ts b/packages/w3c-context/src/lib/index.ts index d82875be..77a187fe 100644 --- a/packages/w3c-context/src/lib/index.ts +++ b/packages/w3c-context/src/lib/index.ts @@ -1,6 +1,6 @@ import { queryDidDocument } from '@trustvc/w3c-issuer'; import { DocumentLoader, DocumentLoaderObject } from './types'; -import jsonldSignaturesV7 from 'jsonld-signatures-v7'; +import jsonldSignatures from 'jsonld-signatures'; import attachmentsContext from '../context/attachments-context.json'; import bbsV1 from '../context/bbs-v1.json'; import bolContext from '../context/bill-of-lading.json'; @@ -181,5 +181,5 @@ export async function getDocumentLoader( return resolveContext; }; - return jsonldSignaturesV7.extendContextLoader(customDocLoader); + return jsonldSignatures.extendContextLoader(customDocLoader); } diff --git a/packages/w3c-vc/README.md b/packages/w3c-vc/README.md index dfe0a1a1..9a10c7ca 100644 --- a/packages/w3c-vc/README.md +++ b/packages/w3c-vc/README.md @@ -98,17 +98,17 @@ const ecdsaKeyPair = { const credential = { "@context": [ - "https://www.w3.org/2018/credentials/v1", + "https://www.w3.org/ns/credentials/v2", "https://w3id.org/security/data-integrity/v2" ], - "issuanceDate": "2024-04-01T12:19:52Z", + "validFrom": "2024-04-01T12:19:52Z", "credentialSubject": { "id": "did:example:b34ca6cd37bbf23", "type": ["Person"], "name": "TrustVC", "billOfLadingName": "Acme Corp" }, - "expirationDate": "2029-12-03T12:19:52Z", + "validUntil": "2029-12-03T12:19:52Z", "issuer": "did:web:trustvc.github.io:did:1", "type": ["VerifiableCredential"] }; @@ -193,17 +193,17 @@ import { verifyCredential } from '@trustvc/w3c-vc'; const ecdsaCredential = { '@context': [ - 'https://www.w3.org/2018/credentials/v1', + 'https://www.w3.org/ns/credentials/v2', 'https://w3id.org/security/data-integrity/v2' ], - issuanceDate: '2024-04-01T12:19:52Z', + validFrom: '2024-04-01T12:19:52Z', credentialSubject: { id: 'did:example:b34ca6cd37bbf23', type: ['Person'], name: 'TrustVC', billOfLadingName: 'Acme Corp' }, - expirationDate: '2029-12-03T12:19:52Z', + validUntil: '2029-12-03T12:19:52Z', issuer: 'did:web:trustvc.github.io:did:1', type: ['VerifiableCredential'], proof: { @@ -318,17 +318,17 @@ import { deriveCredential } from '@trustvc/w3c-vc'; const ecdsaCredential = { '@context': [ - 'https://www.w3.org/2018/credentials/v1', + 'https://www.w3.org/ns/credentials/v2', 'https://w3id.org/security/data-integrity/v2' ], - issuanceDate: '2024-04-01T12:19:52Z', + validFrom: '2024-04-01T12:19:52Z', credentialSubject: { id: 'did:example:b34ca6cd37bbf23', type: ['Person'], name: 'TrustVC', billOfLadingName: 'Acme Corp' }, - expirationDate: '2029-12-03T12:19:52Z', + validUntil: '2029-12-03T12:19:52Z', issuer: 'did:web:trustvc.github.io:did:1', type: ['VerifiableCredential'], proof: { diff --git a/packages/w3c-vc/src/lib/helper/index.ts b/packages/w3c-vc/src/lib/helper/index.ts index 29f456bf..7b990466 100644 --- a/packages/w3c-vc/src/lib/helper/index.ts +++ b/packages/w3c-vc/src/lib/helper/index.ts @@ -116,6 +116,17 @@ function assertDateString({ } } +/** + * Retrieves the first value from the `@context` property of a Verifiable Credential. + * + * @param {object} credential - The Verifiable Credential object from which to extract the context. + * @returns {string} The first context value as a string. + */ +export function getFirstContext(credential: VerifiableCredential): string { + const v = jsonld.getValues(credential, '@context'); + return (Array.isArray(v) && v.length ? v[0] : credential['@context']) as string; +} + /** * Checks if the first element of the '@context' field in the credential is the expected value. * Returns true if the context is valid, otherwise false. @@ -124,8 +135,14 @@ function assertDateString({ * @throws {Error} If the context is invalid. */ function assertCredentialContext(credential: VerifiableCredential): void { - if (credential['@context'][0] !== CredentialContextVersion.v1) { - throw new Error(`The first element of '@context' must be '${CredentialContextVersion.v1}'`); + const firstContext = getFirstContext(credential); + if ( + firstContext !== CredentialContextVersion.v1 && + firstContext !== CredentialContextVersion.v2 + ) { + throw new Error( + `The first element of '@context' must be either '${CredentialContextVersion.v1}' (v1.1) or '${CredentialContextVersion.v2}' (v2.0).`, + ); } } @@ -179,39 +196,80 @@ export function _checkCredential( _validateUriId({ id: issuer, propertyName: 'issuer' }); } - // Validate issuanceDate field - if (!credential.issuanceDate) { - throw new Error('"issuanceDate" property is required.'); - } - assertDateString({ credential, prop: 'issuanceDate' }); + // Validate date fields - support both v1.1 and v2.0 formats + const firstContext = getFirstContext(credential); + const isV2 = firstContext === CredentialContextVersion.v2; - // Ensure issuanceDate has only one value - if (jsonld.getValues(credential, 'issuanceDate').length > 1) { - throw new Error('"issuanceDate" property can only have one value.'); - } + if (isV2) { + // v2.0 format: validFrom is optional, validUntil is optional + if ('validFrom' in credential) { + assertDateString({ credential, prop: 'validFrom' }); + if (jsonld.getValues(credential, 'validFrom').length > 1) { + throw new Error('"validFrom" property can only have one value.'); + } + } - // Optionally validate expirationDate field if it exists - if ('expirationDate' in credential) { - assertDateString({ credential, prop: 'expirationDate' }); + if ('validUntil' in credential) { + assertDateString({ credential, prop: 'validUntil' }); + if (jsonld.getValues(credential, 'validUntil').length > 1) { + throw new Error('"validUntil" property can only have one value.'); + } + + if (mode === 'verify') { + if (now > new Date(credential.validUntil)) { + console.warn('Credential has expired.'); + // throw new Error('Credential has expired.'); + } + } + } + + // Check if the current date is before the validFrom date during verification + if (mode === 'verify' && credential.validFrom) { + const validFromDate = new Date(credential.validFrom); + if (now < validFromDate) { + throw new Error( + `The current date time (${now.toISOString()}) is before the ` + + `"validFrom" (${credential.validFrom}).`, + ); + } + } + } else { + // v1.1 format: issuanceDate is required + if (!credential.issuanceDate) { + throw new Error('"issuanceDate" property is required.'); + } + assertDateString({ credential, prop: 'issuanceDate' }); + + // Ensure issuanceDate has only one value + if (jsonld.getValues(credential, 'issuanceDate').length > 1) { + throw new Error('"issuanceDate" property can only have one value.'); + } + + // Optionally validate expirationDate field if it exists + if ('expirationDate' in credential) { + assertDateString({ credential, prop: 'expirationDate' }); + if (mode === 'verify') { + if (now > new Date(credential.expirationDate)) { + console.warn('Credential has expired.'); + // throw new Error('Credential has expired.'); + } + } + } + + // Check if the current date is before the issuance date during verification if (mode === 'verify') { - if (now > new Date(credential.expirationDate)) { - console.warn('Credential has expired.'); - // throw new Error('Credential has expired.'); + const issuanceDate = new Date(credential.issuanceDate); + if (now < issuanceDate) { + throw new Error( + `The current date time (${now.toISOString()}) is before the ` + + `"issuanceDate" (${credential.issuanceDate}).`, + ); } } } - // Check if the current date is before the issuance date during verification + // Validate proof field for presence and type during verification if (mode === 'verify') { - const issuanceDate = new Date(credential.issuanceDate); - if (now < issuanceDate) { - throw new Error( - `The current date time (${now.toISOString()}) is before the ` + - `"issuanceDate" (${credential.issuanceDate}).`, - ); - } - - // Validate proof field for presence and type during verification if (!credential.proof) { throw new Error('"proof" property is required.'); } diff --git a/packages/w3c-vc/src/lib/types.ts b/packages/w3c-vc/src/lib/types.ts index 890592fc..9945838e 100644 --- a/packages/w3c-vc/src/lib/types.ts +++ b/packages/w3c-vc/src/lib/types.ts @@ -57,6 +57,8 @@ export type SignedVerifiableCredential = { export type RawVerifiableCredential = Omit; +export type CryptoSuiteName = 'BbsBlsSignature2020' | 'bbs-2023' | 'ecdsa-sd-2023'; + export type ProofType = 'BbsBlsSignature2020' | 'BbsBlsSignatureProof2020' | 'DataIntegrityProof'; export const proofTypeMapping: Record< diff --git a/packages/w3c-vc/src/lib/w3c-vc.test.ts b/packages/w3c-vc/src/lib/w3c-vc.test.ts index 6e701183..de5c3167 100644 --- a/packages/w3c-vc/src/lib/w3c-vc.test.ts +++ b/packages/w3c-vc/src/lib/w3c-vc.test.ts @@ -106,8 +106,8 @@ const ecdsaKeyPair: EcdsaSd2023PrivateKeyPair = { secretKeyMultibase: 'z42tmUXTVn3n9BihE6NhdMpvVBTnFTgmb6fw18o5Ud6puhRW', }; -// Modified credential for ECDSA-SD-2023 testing -const ecdsaCredential: VerifiableCredential = { +// Modified ECDSA-SD-2023 credential for v1.1 testing +const ecdsaCredentialV1_1: VerifiableCredential = { '@context': [ 'https://www.w3.org/2018/credentials/v1', 'https://w3id.org/security/data-integrity/v2', @@ -169,7 +169,85 @@ const ecdsaCredential: VerifiableCredential = { type: ['VerifiableCredential'], }; -describe('Credential Signing and Verification', () => { +// Modified ECDSA-SD-2023 credential for v2.0 testing +const ecdsaCredentialV2_0: VerifiableCredential = { + '@context': [ + 'https://www.w3.org/ns/credentials/v2', + 'https://w3id.org/security/data-integrity/v2', + 'https://w3id.org/vc/status-list/2021/v1', + 'https://trustvc.io/context/transferable-records-context.json', + 'https://trustvc.io/context/attachments-context.json', + 'https://trustvc.io/context/qrcode-context.json', + 'https://trustvc.io/context/bill-of-lading.json', + ], + qrCode: { + type: 'TrustVCQRCode', + uri: 'https://localhost:3000/qrcode', + }, + credentialStatus: { + type: 'TransferableRecords', + tokenNetwork: { + chain: 'MATIC', + chainId: '80001', + }, + tokenRegistry: '0xE0a94770B8e969B5D9179d6dA8730B01e19279e2', + }, + credentialSubject: { + billOfLadingName: 'TrustVC Bill of Lading', + scac: 'SGPU', + blNumber: 'SGCNM21566325', + vessel: 'vessel', + voyageNo: 'voyageNo', + portOfLoading: 'Singapore', + portOfDischarge: 'Paris', + carrierName: 'A.P. Moller', + placeOfReceipt: 'Beijing', + placeOfDelivery: 'Singapore', + packages: [ + { packagesDescription: 'package 1', packagesWeight: '10', packagesMeasurement: '20' }, + { packagesDescription: 'package 2', packagesWeight: '10', packagesMeasurement: '20' }, + ], + shipperName: 'Shipper Name', + shipperAddressStreet: '101 ORCHARD ROAD', + shipperAddressCountry: 'SINGAPORE', + consigneeName: 'Consignee name', + notifyPartyName: 'Notify Party Name', + links: 'https://localhost:3000/url', + attachments: [ + { data: 'BASE64_ENCODED_FILE', filename: 'sample1.pdf', mimeType: 'application/pdf' }, + { data: 'BASE64_ENCODED_FILE', filename: 'sample2.pdf', mimeType: 'application/pdf' }, + ], + type: ['BillOfLading'], + }, + renderMethod: [ + { + id: 'https://localhost:3000/renderer', + type: 'EMBEDDED_RENDERER', + templateName: 'BILL_OF_LADING', + }, + ], + validUntil: '2029-12-03T12:19:52Z', + issuer: 'did:web:trustvc.github.io:did:1', + type: ['VerifiableCredential'], +}; + +// Parameterized test data for ECDSA-SD-2023 tests +const ecdsaTestScenarios = [ + { + version: 'v1.1', + credential: ecdsaCredentialV1_1, + dateField: 'issuanceDate', + dateValue: '2024-04-01T12:19:52Z', + }, + { + version: 'v2.0', + credential: ecdsaCredentialV2_0, + dateField: 'validFrom', + dateValue: '2024-04-01T12:19:52Z', + }, +]; + +describe('BBS+ v1.1 Credential Signing and Verification', () => { it('should successfully sign, derive and verify a credential', async () => { let signingKeyPair = modifiedKeyPair; signingKeyPair = { @@ -315,120 +393,220 @@ describe('Credential Signing and Verification', () => { }); }); -describe('ECDSA-SD-2023 Credential Signing and Verification', () => { - it('should successfully sign, derive, and verify a credential with ECDSA-SD-2023', async () => { - let credential = ecdsaCredential; - credential = { ...credential, issuanceDate: '2024-04-01T12:19:52Z' }; - - // Sign the credential - const signedCredential = await signCredential(credential, ecdsaKeyPair, 'ecdsa-sd-2023'); - expect(signedCredential.signed).toBeDefined(); - expect(signedCredential.error).toBeUndefined(); - expect(signedCredential.signed?.proof?.type).toBe('DataIntegrityProof'); - - // Derive the credential with selective disclosure - const selectivePointers = ['/credentialSubject/billOfLadingName', '/issuer', '/issuanceDate']; - const derivedCredential = await deriveCredential(signedCredential.signed, selectivePointers); - expect(derivedCredential.derived).toBeDefined(); - expect(derivedCredential.error).toBeUndefined(); - - // Verify that all selective pointers are included in the derived credential - expect(derivedCredential.derived?.issuer).toBeDefined(); - expect(derivedCredential.derived?.issuanceDate).toBeDefined(); - const credentialSubject = Array.isArray(derivedCredential.derived?.credentialSubject) - ? derivedCredential.derived?.credentialSubject[0] - : derivedCredential.derived?.credentialSubject; - expect(credentialSubject?.billOfLadingName).toBeDefined(); - - // Verify the derived credential - const verificationResult = await verifyCredential(derivedCredential.derived); - expect(verificationResult.verified).toBe(true); - expect(verificationResult.error).toBeUndefined(); - }); - - it('should successfully sign with custom mandatory pointers, derive, and verify', async () => { - let credential = ecdsaCredential; - credential = { ...credential, issuanceDate: '2024-04-01T12:19:52Z' }; - - const customMandatoryPointers = [ - '/issuer', - '/issuanceDate', - '/credentialSubject/billOfLadingName', - ]; - - // Sign with custom mandatory pointers - const signedCredential = await signCredential(credential, ecdsaKeyPair, 'ecdsa-sd-2023', { - mandatoryPointers: customMandatoryPointers, +describe.each(ecdsaTestScenarios)( + 'ECDSA-SD-2023 $version Credential Signing and Verification', + ({ version, credential, dateField, dateValue }) => { + it(`should successfully sign, derive, and verify a ${version} credential with ECDSA-SD-2023`, async () => { + const testCredential = { ...credential, [dateField]: dateValue }; + + // Sign the credential + const signedCredential = await signCredential(testCredential, ecdsaKeyPair, 'ecdsa-sd-2023'); + expect(signedCredential.signed).toBeDefined(); + expect(signedCredential.error).toBeUndefined(); + expect(signedCredential.signed?.proof?.type).toBe('DataIntegrityProof'); + + // Derive the credential with selective disclosure + const selectivePointers = ['/credentialSubject/billOfLadingName']; + const derivedCredential = await deriveCredential(signedCredential.signed, selectivePointers); + expect(derivedCredential.derived).toBeDefined(); + expect(derivedCredential.error).toBeUndefined(); + + // Verify that mandatory core pointers are always included + expect(derivedCredential.derived?.issuer).toBeDefined(); // Core mandatory: /issuer + expect(derivedCredential.derived?.[dateField]).toBeDefined(); // Core mandatory: date field + + // Verify that selective disclosure works within credentialSubject + const credentialSubject = Array.isArray(derivedCredential.derived?.credentialSubject) + ? derivedCredential.derived?.credentialSubject[0] + : derivedCredential.derived?.credentialSubject; + expect(credentialSubject?.billOfLadingName).toBeDefined(); // Selected field + expect(credentialSubject?.blNumber).toBeUndefined(); // Not selected, should be hidden + + // Verify the derived credential + const verificationResult = await verifyCredential(derivedCredential.derived); + expect(verificationResult.verified).toBe(true); + expect(verificationResult.error).toBeUndefined(); }); - expect(signedCredential.signed).toBeDefined(); - expect(signedCredential.error).toBeUndefined(); - expect(signedCredential.signed?.proof?.type).toBe('DataIntegrityProof'); - - // Derive with selective disclosure (only reveal specific fields) - const selectivePointers = ['/credentialSubject/blNumber']; - const derivedCredential = await deriveCredential(signedCredential.signed, selectivePointers); - expect(derivedCredential.derived).toBeDefined(); - expect(derivedCredential.error).toBeUndefined(); - - // Verify that mandatory pointers are always included (even though not in selectivePointers) - expect(derivedCredential.derived?.issuer).toBeDefined(); - expect(derivedCredential.derived?.issuanceDate).toBeDefined(); - const credentialSubject = Array.isArray(derivedCredential.derived?.credentialSubject) - ? derivedCredential.derived?.credentialSubject[0] - : derivedCredential.derived?.credentialSubject; - expect(credentialSubject?.billOfLadingName).toBeDefined(); - - // Verify that selective pointers are included - expect(credentialSubject?.blNumber).toBeDefined(); - // Verify the derived credential - const verificationResult = await verifyCredential(derivedCredential.derived); - expect(verificationResult.verified).toBe(true); - expect(verificationResult.error).toBeUndefined(); - }); - - it('should require derivation before verification for ECDSA-SD-2023 credentials', async () => { - let credential = ecdsaCredential; - credential = { ...credential, issuanceDate: '2024-04-01T12:19:52Z' }; - - // Sign the credential - const signedCredential = await signCredential(credential, ecdsaKeyPair, 'ecdsa-sd-2023'); - expect(signedCredential.signed).toBeDefined(); - expect(signedCredential.error).toBeUndefined(); + it(`should successfully sign ${version} credential with custom mandatory pointers, derive, and verify`, async () => { + const testCredential = { ...credential, [dateField]: dateValue }; + + // Sign with mandatory pointers (core pointers will be added automatically) + const customMandatoryPointers = ['/credentialSubject/billOfLadingName']; + const signedCredential = await signCredential(testCredential, ecdsaKeyPair, 'ecdsa-sd-2023', { + mandatoryPointers: customMandatoryPointers, + }); + expect(signedCredential.signed).toBeDefined(); + expect(signedCredential.error).toBeUndefined(); + expect(signedCredential.signed?.proof?.type).toBe('DataIntegrityProof'); + + // Derive with selective disclosure (only reveal specific fields) + const selectivePointers = ['/credentialSubject/blNumber']; + const derivedCredential = await deriveCredential(signedCredential.signed, selectivePointers); + expect(derivedCredential.derived).toBeDefined(); + expect(derivedCredential.error).toBeUndefined(); + + // Verify that mandatory core pointers are always included (automatically added) + expect(derivedCredential.derived?.issuer).toBeDefined(); // Core mandatory: /issuer + expect(derivedCredential.derived?.[dateField]).toBeDefined(); // Core mandatory: date field + + // Verify that mandatory pointers are always included + const credentialSubject = Array.isArray(derivedCredential.derived?.credentialSubject) + ? derivedCredential.derived?.credentialSubject[0] + : derivedCredential.derived?.credentialSubject; + expect(credentialSubject?.billOfLadingName).toBeDefined(); // Custom mandatory + + // Verify that selective pointers are included + expect(credentialSubject?.blNumber).toBeDefined(); // Selected field + expect(credentialSubject?.scac).toBeUndefined(); // Not selected, should be hidden + + // Verify the derived credential + const verificationResult = await verifyCredential(derivedCredential.derived); + expect(verificationResult.verified).toBe(true); + expect(verificationResult.error).toBeUndefined(); + }); - // Verify the original signed credential directly (without derivation) - should fail - // ECDSA-SD-2023 credentials require derivation before verification - const verificationResult = await verifyCredential(signedCredential.signed); - expect(verificationResult.verified).toBe(false); - expect(verificationResult.error).toBeDefined(); - expect(verificationResult.error).toContain('proofValue'); - }); + it(`should automatically include entire credentialSubject when no credentialSubject properties are selected (${version})`, async () => { + const testCredential = { ...credential, [dateField]: dateValue }; + + // Sign the credential + const signedCredential = await signCredential(testCredential, ecdsaKeyPair, 'ecdsa-sd-2023'); + expect(signedCredential.signed).toBeDefined(); + expect(signedCredential.error).toBeUndefined(); + expect(signedCredential.signed?.proof?.type).toBe('DataIntegrityProof'); + + // Derive with no credentialSubject pointers - should automatically include entire credentialSubject + const selectivePointers: string[] = []; + const derivedCredential = await deriveCredential(signedCredential.signed, selectivePointers); + expect(derivedCredential.derived).toBeDefined(); + expect(derivedCredential.error).toBeUndefined(); + + // Verify that core mandatory pointers are automatically included + expect(derivedCredential.derived?.issuer).toBeDefined(); // Core mandatory: /issuer (auto-added) + expect(derivedCredential.derived?.[dateField]).toBeDefined(); // Core mandatory: date field (auto-added) + + // Verify that entire credentialSubject is included (since no credentialSubject properties were selected) + const credentialSubject = Array.isArray(derivedCredential.derived?.credentialSubject) + ? derivedCredential.derived?.credentialSubject[0] + : derivedCredential.derived?.credentialSubject; + expect(credentialSubject?.scac).toBeDefined(); // All properties should be present + expect(credentialSubject?.vessel).toBeDefined(); // All properties should be present + expect(credentialSubject?.billOfLadingName).toBeDefined(); // All properties should be present + expect(credentialSubject?.blNumber).toBeDefined(); // All properties should be present + + // Verify the derived credential + const verificationResult = await verifyCredential(derivedCredential.derived); + expect(verificationResult.verified).toBe(true); + expect(verificationResult.error).toBeUndefined(); + }); - it('should fail to sign with ECDSA-SD-2023 if key pair is missing required properties', async () => { - let credential = ecdsaCredential; - credential = { ...credential, issuanceDate: '2024-04-01T12:19:52Z' }; + it(`should require derivation before verification for ECDSA-SD-2023 ${version} credentials`, async () => { + const testCredential = { ...credential, [dateField]: dateValue }; + + // Sign the credential + const signedCredential = await signCredential(testCredential, ecdsaKeyPair, 'ecdsa-sd-2023'); + expect(signedCredential.signed).toBeDefined(); + expect(signedCredential.error).toBeUndefined(); + + // Verify the original signed credential directly (without derivation) - should fail + // ECDSA-SD-2023 credentials require derivation before verification + const verificationResult = await verifyCredential(signedCredential.signed); + expect(verificationResult.verified).toBe(false); + expect(verificationResult.error).toBeDefined(); + expect(verificationResult.error).toBe( + 'ecdsa-sd-2023 base credentials must be derived before verification. Use deriveCredential() first.', + ); + }); - const invalidKeyPair: any = { - id: 'did:web:trustvc.github.io:did:1#multikey-1', - type: 'Multikey', - controller: 'did:web:trustvc.github.io:did:1', - publicKeyMultibase: 'zDnaemDNwi4G5eTzGfRooFFu5Kns3be6yfyVNtiaMhWkZbwtc', - // Missing secretKeyMultibase - }; + it(`should fail when attempting to derive from an already derived ECDSA-SD-2023 ${version} credential`, async () => { + const testCredential = { ...credential, [dateField]: dateValue }; + + // Sign the credential + const signedCredential = await signCredential(testCredential, ecdsaKeyPair, 'ecdsa-sd-2023'); + expect(signedCredential.signed).toBeDefined(); + expect(signedCredential.error).toBeUndefined(); + + // First derivation - should succeed + const selectivePointers = ['/credentialSubject/blNumber']; + const firstDerivedCredential = await deriveCredential( + signedCredential.signed, + selectivePointers, + ); + expect(firstDerivedCredential.derived).toBeDefined(); + expect(firstDerivedCredential.error).toBeUndefined(); + + // Attempt second derivation from the already derived credential - should fail + const secondSelectivePointers = ['/credentialSubject/billOfLadingName']; + const secondDerivedCredential = await deriveCredential( + firstDerivedCredential.derived, + secondSelectivePointers, + ); + expect(secondDerivedCredential.derived).toBeUndefined(); + expect(secondDerivedCredential.error).toBeDefined(); + expect(secondDerivedCredential.error).toBe( + 'ecdsa-sd-2023 derived credentials cannot be further derived. Multiple rounds of derivation are not supported by this cryptosuite.', + ); + }); - const signedCredential = await signCredential(credential, invalidKeyPair, 'ecdsa-sd-2023'); - expect(signedCredential.signed).toBeUndefined(); - expect(signedCredential.error).toBeDefined(); - expect(signedCredential.error).toBe('"secretKeyMultibase" property in keyPair is required.'); - }); + it(`should fail verification if the ${version} credential is tampered with`, async () => { + const testCredential = { ...credential, [dateField]: dateValue }; + + // Sign the credential + const signedCredential = await signCredential(testCredential, ecdsaKeyPair, 'ecdsa-sd-2023'); + expect(signedCredential.signed).toBeDefined(); + expect(signedCredential.error).toBeUndefined(); + + // Derive the credential with selective disclosure + const selectivePointers = ['/credentialSubject/billOfLadingName']; + const derivedCredential = await deriveCredential(signedCredential.signed, selectivePointers); + expect(derivedCredential.derived).toBeDefined(); + expect(derivedCredential.error).toBeUndefined(); + + const tamperedCredential = { + ...derivedCredential.derived, + [dateField]: new Date().toISOString(), + }; + + // Verify the derived credential - should fail + const verificationResult = await verifyCredential(tamperedCredential); + expect(verificationResult.verified).toBe(false); + expect(verificationResult.error).equals('Invalid signature.'); + }); - it('should fail to sign with unsupported cryptosuite', async () => { - let credential = ecdsaCredential; - credential = { ...credential, issuanceDate: '2024-04-01T12:19:52Z' }; + it(`should fail to sign with ECDSA-SD-2023 if key pair is missing required properties (${version})`, async () => { + const testCredential = { ...credential, [dateField]: dateValue }; + + const invalidKeyPair: any = { + id: 'did:web:trustvc.github.io:did:1#multikey-1', + type: 'Multikey', + controller: 'did:web:trustvc.github.io:did:1', + publicKeyMultibase: 'zDnaemDNwi4G5eTzGfRooFFu5Kns3be6yfyVNtiaMhWkZbwtc', + // Missing secretKeyMultibase + }; + + // Sign the credential + const signedCredential = await signCredential( + testCredential, + invalidKeyPair, + 'ecdsa-sd-2023', + ); + expect(signedCredential.signed).toBeUndefined(); + expect(signedCredential.error).toBeDefined(); + expect(signedCredential.error).toBe('"secretKeyMultibase" property in keyPair is required.'); + }); - const signedCredential = await signCredential(credential, ecdsaKeyPair, 'unsupported-suite'); - expect(signedCredential.signed).toBeUndefined(); - expect(signedCredential.error).toBeDefined(); - expect(signedCredential.error).toBe('"unsupported-suite" is not supported.'); - }); -}); + it(`should fail to sign with unsupported cryptosuite (${version})`, async () => { + const testCredential = { ...credential, [dateField]: dateValue }; + + // Sign the credential + const signedCredential = await signCredential( + testCredential, + ecdsaKeyPair, + 'unsupported-suite' as any, + ); + expect(signedCredential.signed).toBeUndefined(); + expect(signedCredential.error).toBeDefined(); + expect(signedCredential.error).toBe('"unsupported-suite" is not supported.'); + }); + }, +); diff --git a/packages/w3c-vc/src/lib/w3c-vc.ts b/packages/w3c-vc/src/lib/w3c-vc.ts index b2b104dc..f3c6f39d 100644 --- a/packages/w3c-vc/src/lib/w3c-vc.ts +++ b/packages/w3c-vc/src/lib/w3c-vc.ts @@ -8,13 +8,19 @@ import { import * as EcdsaMultikey from '@digitalbazaar/ecdsa-multikey'; import * as ecdsaSd2023Cryptosuite from '@digitalbazaar/ecdsa-sd-2023-cryptosuite'; import { DataIntegrityProof } from '@digitalbazaar/data-integrity'; -import { ContextDocument, DocumentLoader, getDocumentLoader } from '@trustvc/w3c-context'; +import { + ContextDocument, + CredentialContextVersion, + DocumentLoader, + getDocumentLoader, +} from '@trustvc/w3c-context'; import { PrivateKeyPair } from '@trustvc/w3c-issuer'; import jsonldSignatures from 'jsonld-signatures'; import jsonldSignaturesV7 from 'jsonld-signatures-v7'; import * as jsonld from 'jsonld'; -import { _checkCredential, _checkKeyPair, prefilCredentialId } from './helper'; +import { _checkCredential, _checkKeyPair, getFirstContext, prefilCredentialId } from './helper'; import { + CryptoSuiteName, DerivedResult, ProofType, proofTypeMapping, @@ -47,6 +53,22 @@ export const isRawDocument = (document: RawVerifiableCredential | unknown): bool return typeof document === 'object'; }; +/** + * Checks if the input document is a valid raw credential with context version 1.1. + * @param {RawVerifiableCredential | unknown} document - The document to check. + * @returns {boolean} - True if the document is a valid raw credential and uses v1.1 context, otherwise false. + */ +export const isRawDocumentV1_1 = (document: RawVerifiableCredential | unknown): boolean => + isRawDocument(document) && getFirstContext(document) === CredentialContextVersion.v1; + +/** + * Checks if the input document is a valid raw credential with context version 2.0. + * @param {RawVerifiableCredential | unknown} document - The document to check. + * @returns {boolean} - True if the document is a valid raw credential and uses v2.0 context, otherwise false. + */ +export const isRawDocumentV2_0 = (document: RawVerifiableCredential | unknown): boolean => + isRawDocument(document) && getFirstContext(document) === CredentialContextVersion.v2; + /** * Checks if the input document is a signed credential. * @param {SignedVerifiableCredential | unknown} document - The signed credential to be checked. @@ -63,6 +85,45 @@ export const isSignedDocument = ( return typeof document === 'object' && 'proof' in document; }; +/** + * Checks if the input document is a valid signed credential with context version 1.1. + * @param {SignedVerifiableCredential | unknown} document - The document to check. + * @returns {boolean} - True if the document is a valid signed credential and uses v1.1 context, otherwise false. + */ +export const isSignedDocumentV1_1 = ( + document: SignedVerifiableCredential | unknown, +): document is SignedVerifiableCredential => + isSignedDocument(document) && getFirstContext(document) === CredentialContextVersion.v1; + +/** + * Checks if the input document is a valid signed credential with context version 2.0. + * @param {SignedVerifiableCredential | unknown} document - The document to check. + * @returns {boolean} - True if the document is a valid signed credential and uses v2.0 context, otherwise false. + */ +export const isSignedDocumentV2_0 = ( + document: SignedVerifiableCredential | unknown, +): document is SignedVerifiableCredential => + isSignedDocument(document) && getFirstContext(document) === CredentialContextVersion.v2; + +/** + * Checks if a proof value represents a base (non-derived) ECDSA-SD-2023 credential + * @param {string} proofValue - The proof value string to check + * @returns {boolean} - true if this is a base proof, false otherwise + */ +const isEcdsaSdBaseProof = (proofValue: string): boolean => { + try { + if (!proofValue || !proofValue.startsWith('u')) { + return false; + } + // Decode to check the structure + const decoded = Buffer.from(proofValue.slice(1), 'base64url'); + // Check if it has the base proof header (0xd9, 0x5d, 0x00) + return decoded.length >= 3 && decoded[0] === 0xd9 && decoded[1] === 0x5d && decoded[2] === 0x00; + } catch { + return false; + } +}; + /** * Signs a credential using the specified cryptosuite. Defaults to 'BbsBlsSignature2020'. * @param {object} credential - The credential to be signed. @@ -74,7 +135,7 @@ export const isSignedDocument = ( export const signCredential = async ( credential: RawVerifiableCredential, keyPair: PrivateKeyPair, - cryptoSuite = 'BbsBlsSignature2020', + cryptoSuite: CryptoSuiteName = 'BbsBlsSignature2020', options?: { documentLoader?: DocumentLoader; mandatoryPointers?: string[]; @@ -106,8 +167,30 @@ export const signCredential = async ( // Import the key pair object into a usable signer instance const ecdsaKeyPair = await EcdsaMultikey.from({ ...keyPair }); - // Default mandatory pointers for selective disclosure - const mandatoryPointers = options?.mandatoryPointers || []; + // Determine required mandatory pointers based on credential format + const firstContext = credential['@context'][0]; + const isV2 = firstContext === CredentialContextVersion.v2; + + // Core mandatory pointers for fields required for credential validity + const coreMandatoryPointers = ['/issuer']; + + // Add date field pointer based on credential version + if (isV2) { + // For v2.0, validFrom is optional but if present should be mandatory for consistency + if (credential.validFrom) { + coreMandatoryPointers.push('/validFrom'); + } + } else { + // For v1.1, issuanceDate is required + coreMandatoryPointers.push('/issuanceDate'); + } + + // Combine core mandatory pointers with user-provided ones, ensuring core fields are always included + const userMandatoryPointers = options?.mandatoryPointers || []; + const mandatoryPointers = [ + ...coreMandatoryPointers, + ...userMandatoryPointers.filter((pointer) => !coreMandatoryPointers.includes(pointer)), + ]; // Create the DataIntegrityProof suite using the ECDSA-SD cryptosuite const suite = new DataIntegrityProof({ @@ -175,6 +258,15 @@ export const verifyCredential = async ( const cryptosuite = proof.cryptosuite; if (cryptosuite === 'ecdsa-sd-2023') { + // Check if this is a base credential (non-derived) by examining the proofValue structure + if (isEcdsaSdBaseProof(proof.proofValue as string)) { + // This is a base proof - ECDSA-SD-2023 base credentials require derivation before verification + return { + verified: false, + error: `${cryptosuite} base credentials must be derived before verification. Use deriveCredential() first.`, + }; + } + verificationResult = await jsonldSignatures.verify(credential, { suite: new DataIntegrityProof({ cryptosuite: createVerifyCryptosuite(), @@ -262,6 +354,13 @@ export const deriveCredential = async ( const cryptosuite = proof.cryptosuite; if (cryptosuite === 'ecdsa-sd-2023') { + // Check if this is already a derived credential by examining the proofValue structure + if (!isEcdsaSdBaseProof(proof.proofValue as string)) { + return { + error: `${cryptosuite} derived credentials cannot be further derived. Multiple rounds of derivation are not supported by this cryptosuite.`, + }; + } + // For ECDSA-SD-2023, use selective pointers (can be empty array for mandatory-only disclosure) if (!Array.isArray(revealedAttributes)) { return { @@ -271,10 +370,23 @@ export const deriveCredential = async ( const selectivePointers = revealedAttributes; + // Ensure credentialSubject is included if no credentialSubject properties are selected + // This maintains credential validity while allowing selective disclosure within credentialSubject + const hasCredentialSubjectPointers = selectivePointers.some((pointer) => + pointer.startsWith('/credentialSubject'), + ); + + let finalSelectivePointers = selectivePointers; + if (!hasCredentialSubjectPointers) { + // If no credentialSubject properties are selected, include the entire credentialSubject + // This ensures the derived credential remains valid per W3C VC specification + finalSelectivePointers = [...selectivePointers, '/credentialSubject']; + } + // Create the DataIntegrityProof suite for disclosure const suite = new DataIntegrityProof({ cryptosuite: createDiscloseCryptosuite({ - selectivePointers, + selectivePointers: finalSelectivePointers, }), }); From c4f8e65eae031237e403aa0dee645942fddec5ee Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 13 Aug 2025 02:39:52 +0000 Subject: [PATCH 034/122] chore(release): @trustvc/w3c-issuer@1.3.0-alpha.3 [skip ci] # [1.3.0-alpha.3](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-issuer@1.3.0-alpha.2...@trustvc/w3c-issuer@1.3.0-alpha.3) (2025-08-13) ### Features * add support for w3c vc data model v2 ([#69](https://github.com/TrustVC/w3c/issues/69)) ([e4219ee](https://github.com/TrustVC/w3c/commit/e4219eefbc79fbc7ae7a495f1b989be9b4205e3c)) --- packages/w3c-issuer/CHANGELOG.md | 7 +++++++ packages/w3c-issuer/package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/w3c-issuer/CHANGELOG.md b/packages/w3c-issuer/CHANGELOG.md index 2fcddad8..f8333f31 100644 --- a/packages/w3c-issuer/CHANGELOG.md +++ b/packages/w3c-issuer/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.3](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-issuer@1.3.0-alpha.2...@trustvc/w3c-issuer@1.3.0-alpha.3) (2025-08-13) + + +### Features + +* add support for w3c vc data model v2 ([#69](https://github.com/TrustVC/w3c/issues/69)) ([e4219ee](https://github.com/TrustVC/w3c/commit/e4219eefbc79fbc7ae7a495f1b989be9b4205e3c)) + # [1.3.0-alpha.2](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-issuer@1.3.0-alpha.1...@trustvc/w3c-issuer@1.3.0-alpha.2) (2025-08-07) diff --git a/packages/w3c-issuer/package.json b/packages/w3c-issuer/package.json index 3330e045..5fe9a02a 100644 --- a/packages/w3c-issuer/package.json +++ b/packages/w3c-issuer/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c-issuer", - "version": "1.3.0-alpha.2", + "version": "1.3.0-alpha.3", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", From d5290d3fcf18fe9e054ab9bf582f4e41075b83e8 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 13 Aug 2025 02:40:22 +0000 Subject: [PATCH 035/122] chore(release): @trustvc/w3c-context@1.3.0-alpha.3 [skip ci] # [1.3.0-alpha.3](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-context@1.3.0-alpha.2...@trustvc/w3c-context@1.3.0-alpha.3) (2025-08-13) ### Features * add support for w3c vc data model v2 ([#69](https://github.com/TrustVC/w3c/issues/69)) ([e4219ee](https://github.com/TrustVC/w3c/commit/e4219eefbc79fbc7ae7a495f1b989be9b4205e3c)) --- packages/w3c-context/CHANGELOG.md | 7 +++++++ packages/w3c-context/package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/w3c-context/CHANGELOG.md b/packages/w3c-context/CHANGELOG.md index 1bb1861b..8d20c03f 100644 --- a/packages/w3c-context/CHANGELOG.md +++ b/packages/w3c-context/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.3](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-context@1.3.0-alpha.2...@trustvc/w3c-context@1.3.0-alpha.3) (2025-08-13) + + +### Features + +* add support for w3c vc data model v2 ([#69](https://github.com/TrustVC/w3c/issues/69)) ([e4219ee](https://github.com/TrustVC/w3c/commit/e4219eefbc79fbc7ae7a495f1b989be9b4205e3c)) + # [1.3.0-alpha.2](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-context@1.3.0-alpha.1...@trustvc/w3c-context@1.3.0-alpha.2) (2025-08-07) diff --git a/packages/w3c-context/package.json b/packages/w3c-context/package.json index e750637e..5682f8e7 100644 --- a/packages/w3c-context/package.json +++ b/packages/w3c-context/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c-context", - "version": "1.3.0-alpha.2", + "version": "1.3.0-alpha.3", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", From 1f56fb32cdae117d4dba2db64f4dfcf5a9f0c0ae Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 13 Aug 2025 02:40:55 +0000 Subject: [PATCH 036/122] chore(release): @trustvc/w3c-credential-status@1.3.0-alpha.3 [skip ci] # [1.3.0-alpha.3](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-credential-status@1.3.0-alpha.2...@trustvc/w3c-credential-status@1.3.0-alpha.3) (2025-08-13) ### Features * add support for w3c vc data model v2 ([#69](https://github.com/TrustVC/w3c/issues/69)) ([e4219ee](https://github.com/TrustVC/w3c/commit/e4219eefbc79fbc7ae7a495f1b989be9b4205e3c)) --- packages/w3c-credential-status/CHANGELOG.md | 7 +++++++ packages/w3c-credential-status/package.json | 6 +++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/packages/w3c-credential-status/CHANGELOG.md b/packages/w3c-credential-status/CHANGELOG.md index affce16c..27dca536 100644 --- a/packages/w3c-credential-status/CHANGELOG.md +++ b/packages/w3c-credential-status/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.3](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-credential-status@1.3.0-alpha.2...@trustvc/w3c-credential-status@1.3.0-alpha.3) (2025-08-13) + + +### Features + +* add support for w3c vc data model v2 ([#69](https://github.com/TrustVC/w3c/issues/69)) ([e4219ee](https://github.com/TrustVC/w3c/commit/e4219eefbc79fbc7ae7a495f1b989be9b4205e3c)) + # [1.3.0-alpha.2](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-credential-status@1.3.0-alpha.1...@trustvc/w3c-credential-status@1.3.0-alpha.2) (2025-08-07) diff --git a/packages/w3c-credential-status/package.json b/packages/w3c-credential-status/package.json index 5e7fcdb8..f5187771 100644 --- a/packages/w3c-credential-status/package.json +++ b/packages/w3c-credential-status/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c-credential-status", - "version": "1.3.0-alpha.2", + "version": "1.3.0-alpha.3", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", @@ -29,8 +29,8 @@ } }, "dependencies": { - "@trustvc/w3c-context": "^1.3.0-alpha.2", - "@trustvc/w3c-issuer": "^1.3.0-alpha.2", + "@trustvc/w3c-context": "^1.3.0-alpha.3", + "@trustvc/w3c-issuer": "^1.3.0-alpha.3", "base64url-universal": "^2.0.0", "pako": "^2.1.0" }, From b9e05a9d95d6a6bf4b81567efaa526ddb2418a90 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 13 Aug 2025 02:41:28 +0000 Subject: [PATCH 037/122] chore(release): @trustvc/w3c-vc@1.3.0-alpha.3 [skip ci] # [1.3.0-alpha.3](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.3.0-alpha.2...@trustvc/w3c-vc@1.3.0-alpha.3) (2025-08-13) ### Features * add support for w3c vc data model v2 ([#69](https://github.com/TrustVC/w3c/issues/69)) ([e4219ee](https://github.com/TrustVC/w3c/commit/e4219eefbc79fbc7ae7a495f1b989be9b4205e3c)) --- packages/w3c-vc/CHANGELOG.md | 7 +++++++ packages/w3c-vc/package.json | 6 +++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/packages/w3c-vc/CHANGELOG.md b/packages/w3c-vc/CHANGELOG.md index f1da1588..550073f3 100644 --- a/packages/w3c-vc/CHANGELOG.md +++ b/packages/w3c-vc/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.3](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.3.0-alpha.2...@trustvc/w3c-vc@1.3.0-alpha.3) (2025-08-13) + + +### Features + +* add support for w3c vc data model v2 ([#69](https://github.com/TrustVC/w3c/issues/69)) ([e4219ee](https://github.com/TrustVC/w3c/commit/e4219eefbc79fbc7ae7a495f1b989be9b4205e3c)) + # [1.3.0-alpha.2](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.3.0-alpha.1...@trustvc/w3c-vc@1.3.0-alpha.2) (2025-08-07) diff --git a/packages/w3c-vc/package.json b/packages/w3c-vc/package.json index 3ec0edeb..836398cd 100644 --- a/packages/w3c-vc/package.json +++ b/packages/w3c-vc/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c-vc", - "version": "1.3.0-alpha.2", + "version": "1.3.0-alpha.3", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", @@ -35,8 +35,8 @@ "@digitalbazaar/ecdsa-multikey": "^1.8.0", "@digitalbazaar/ecdsa-sd-2023-cryptosuite": "^3.4.1", "@mattrglobal/jsonld-signatures-bbs": "^1.2.0", - "@trustvc/w3c-credential-status": "^1.3.0-alpha.2", - "@trustvc/w3c-issuer": "^1.3.0-alpha.2", + "@trustvc/w3c-credential-status": "^1.3.0-alpha.3", + "@trustvc/w3c-issuer": "^1.3.0-alpha.3", "did-resolver": "^4.1.0", "jsonld": "^6.0.0", "jsonld-signatures": "^11.5.0", From 9ebdf3bdd1c8fec80308fe2faa66580fc572aab0 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 13 Aug 2025 02:41:58 +0000 Subject: [PATCH 038/122] chore(release): @trustvc/w3c-cli@1.3.0-alpha.3 [skip ci] # [1.3.0-alpha.3](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-cli@1.3.0-alpha.2...@trustvc/w3c-cli@1.3.0-alpha.3) (2025-08-13) ### Features * add support for w3c vc data model v2 ([#69](https://github.com/TrustVC/w3c/issues/69)) ([e4219ee](https://github.com/TrustVC/w3c/commit/e4219eefbc79fbc7ae7a495f1b989be9b4205e3c)) --- apps/w3c-cli/CHANGELOG.md | 7 +++++++ apps/w3c-cli/package.json | 10 +++++----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/apps/w3c-cli/CHANGELOG.md b/apps/w3c-cli/CHANGELOG.md index 3a622d38..a35fb7cf 100644 --- a/apps/w3c-cli/CHANGELOG.md +++ b/apps/w3c-cli/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.3](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-cli@1.3.0-alpha.2...@trustvc/w3c-cli@1.3.0-alpha.3) (2025-08-13) + + +### Features + +* add support for w3c vc data model v2 ([#69](https://github.com/TrustVC/w3c/issues/69)) ([e4219ee](https://github.com/TrustVC/w3c/commit/e4219eefbc79fbc7ae7a495f1b989be9b4205e3c)) + # [1.3.0-alpha.2](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-cli@1.3.0-alpha.1...@trustvc/w3c-cli@1.3.0-alpha.2) (2025-08-07) diff --git a/apps/w3c-cli/package.json b/apps/w3c-cli/package.json index 641a4859..9470f098 100644 --- a/apps/w3c-cli/package.json +++ b/apps/w3c-cli/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c-cli", - "version": "1.3.0-alpha.2", + "version": "1.3.0-alpha.3", "description": "CLI for TrustVC W3C", "main": "dist/main.js", "types": "dist/main.d.ts", @@ -34,10 +34,10 @@ }, "dependencies": { "@inquirer/prompts": "^5.3.8", - "@trustvc/w3c-context": "^1.3.0-alpha.2", - "@trustvc/w3c-credential-status": "^1.3.0-alpha.2", - "@trustvc/w3c-vc": "^1.3.0-alpha.2", - "@trustvc/w3c-issuer": "^1.3.0-alpha.2", + "@trustvc/w3c-context": "^1.3.0-alpha.3", + "@trustvc/w3c-credential-status": "^1.3.0-alpha.3", + "@trustvc/w3c-vc": "^1.3.0-alpha.3", + "@trustvc/w3c-issuer": "^1.3.0-alpha.3", "@types/yargs": "^17.0.32", "chalk": "^4.1.2", "inquirer": "^10.0.1", From 7b1671872e6b85dea5f2e170accce321f8190f1c Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 13 Aug 2025 02:42:29 +0000 Subject: [PATCH 039/122] chore(release): @trustvc/w3c@1.3.0-alpha.3 [skip ci] # [1.3.0-alpha.3](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.3.0-alpha.2...@trustvc/w3c@1.3.0-alpha.3) (2025-08-13) ### Features * add support for w3c vc data model v2 ([#69](https://github.com/TrustVC/w3c/issues/69)) ([e4219ee](https://github.com/TrustVC/w3c/commit/e4219eefbc79fbc7ae7a495f1b989be9b4205e3c)) --- packages/w3c/CHANGELOG.md | 7 +++++++ packages/w3c/package.json | 10 +++++----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/packages/w3c/CHANGELOG.md b/packages/w3c/CHANGELOG.md index 3f2c941e..a564d0c3 100644 --- a/packages/w3c/CHANGELOG.md +++ b/packages/w3c/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.3](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.3.0-alpha.2...@trustvc/w3c@1.3.0-alpha.3) (2025-08-13) + + +### Features + +* add support for w3c vc data model v2 ([#69](https://github.com/TrustVC/w3c/issues/69)) ([e4219ee](https://github.com/TrustVC/w3c/commit/e4219eefbc79fbc7ae7a495f1b989be9b4205e3c)) + # [1.3.0-alpha.2](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.3.0-alpha.1...@trustvc/w3c@1.3.0-alpha.2) (2025-08-07) diff --git a/packages/w3c/package.json b/packages/w3c/package.json index b3656c39..352960f0 100644 --- a/packages/w3c/package.json +++ b/packages/w3c/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c", - "version": "1.3.0-alpha.2", + "version": "1.3.0-alpha.3", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", @@ -32,10 +32,10 @@ } }, "dependencies": { - "@trustvc/w3c-context": "^1.3.0-alpha.2", - "@trustvc/w3c-credential-status": "^1.3.0-alpha.2", - "@trustvc/w3c-issuer": "^1.3.0-alpha.2", - "@trustvc/w3c-vc": "^1.3.0-alpha.2" + "@trustvc/w3c-context": "^1.3.0-alpha.3", + "@trustvc/w3c-credential-status": "^1.3.0-alpha.3", + "@trustvc/w3c-issuer": "^1.3.0-alpha.3", + "@trustvc/w3c-vc": "^1.3.0-alpha.3" }, "repository": { "type": "git", From c31c59b6c49c3bc142e28902327a3ef2153d8c86 Mon Sep 17 00:00:00 2001 From: Moiz Shaikh <58319530+Moiz47@users.noreply.github.com> Date: Mon, 18 Aug 2025 11:26:34 +0530 Subject: [PATCH 040/122] chore: package lock update (#70) Co-authored-by: moiz-sgtradex --- package-lock.json | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/package-lock.json b/package-lock.json index 66a5bd43..fd472b0f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -115,14 +115,14 @@ }, "apps/w3c-cli": { "name": "@trustvc/w3c-cli", - "version": "1.3.0-alpha.1", + "version": "1.3.0-alpha.3", "license": "Apache-2.0", "dependencies": { "@inquirer/prompts": "^5.3.8", - "@trustvc/w3c-context": "^1.3.0-alpha.1", - "@trustvc/w3c-credential-status": "^1.3.0-alpha.1", - "@trustvc/w3c-issuer": "^1.3.0-alpha.1", - "@trustvc/w3c-vc": "^1.3.0-alpha.1", + "@trustvc/w3c-context": "^1.3.0-alpha.3", + "@trustvc/w3c-credential-status": "^1.3.0-alpha.3", + "@trustvc/w3c-issuer": "^1.3.0-alpha.3", + "@trustvc/w3c-vc": "^1.3.0-alpha.3", "@types/yargs": "^17.0.32", "chalk": "^4.1.2", "inquirer": "^10.0.1", @@ -32798,13 +32798,13 @@ }, "packages/w3c": { "name": "@trustvc/w3c", - "version": "1.3.0-alpha.1", + "version": "1.3.0-alpha.3", "license": "Apache-2.0", "dependencies": { - "@trustvc/w3c-context": "^1.3.0-alpha.1", - "@trustvc/w3c-credential-status": "^1.3.0-alpha.1", - "@trustvc/w3c-issuer": "^1.3.0-alpha.1", - "@trustvc/w3c-vc": "^1.3.0-alpha.1" + "@trustvc/w3c-context": "^1.3.0-alpha.3", + "@trustvc/w3c-credential-status": "^1.3.0-alpha.3", + "@trustvc/w3c-issuer": "^1.3.0-alpha.3", + "@trustvc/w3c-vc": "^1.3.0-alpha.3" }, "engines": { "node": ">=18.x" @@ -32812,7 +32812,7 @@ }, "packages/w3c-context": { "name": "@trustvc/w3c-context", - "version": "1.3.0-alpha.1", + "version": "1.3.0-alpha.3", "license": "Apache-2.0", "dependencies": { "did-resolver": "^4.1.0", @@ -32904,11 +32904,11 @@ }, "packages/w3c-credential-status": { "name": "@trustvc/w3c-credential-status", - "version": "1.3.0-alpha.1", + "version": "1.3.0-alpha.3", "license": "Apache-2.0", "dependencies": { - "@trustvc/w3c-context": "^1.3.0-alpha.1", - "@trustvc/w3c-issuer": "^1.3.0-alpha.1", + "@trustvc/w3c-context": "^1.3.0-alpha.3", + "@trustvc/w3c-issuer": "^1.3.0-alpha.3", "base64url-universal": "^2.0.0", "pako": "^2.1.0" }, @@ -32918,7 +32918,7 @@ }, "packages/w3c-issuer": { "name": "@trustvc/w3c-issuer", - "version": "1.3.0-alpha.1", + "version": "1.3.0-alpha.3", "license": "Apache-2.0", "dependencies": { "@digitalbazaar/bls12-381-multikey": "^2.1.0", @@ -32935,15 +32935,15 @@ }, "packages/w3c-vc": { "name": "@trustvc/w3c-vc", - "version": "1.3.0-alpha.1", + "version": "1.3.0-alpha.3", "license": "Apache-2.0", "dependencies": { "@digitalbazaar/data-integrity": "^2.5.0", "@digitalbazaar/ecdsa-multikey": "^1.8.0", "@digitalbazaar/ecdsa-sd-2023-cryptosuite": "^3.4.1", "@mattrglobal/jsonld-signatures-bbs": "^1.2.0", - "@trustvc/w3c-credential-status": "^1.3.0-alpha.1", - "@trustvc/w3c-issuer": "^1.3.0-alpha.1", + "@trustvc/w3c-credential-status": "^1.3.0-alpha.3", + "@trustvc/w3c-issuer": "^1.3.0-alpha.3", "did-resolver": "^4.1.0", "jsonld": "^6.0.0", "jsonld-signatures": "^11.5.0", From aa958c4423877bda9ec170cfb98b27a24df541cb Mon Sep 17 00:00:00 2001 From: Moiz Shaikh <58319530+Moiz47@users.noreply.github.com> Date: Mon, 18 Aug 2025 12:18:31 +0530 Subject: [PATCH 041/122] fix: trigger release (#71) Co-authored-by: moiz-sgtradex From 3fbc3a332dfe33e56b5d077ff67d6b219e0a3d00 Mon Sep 17 00:00:00 2001 From: rongquan1 <85145303+rongquan1@users.noreply.github.com> Date: Mon, 18 Aug 2025 16:43:01 +0800 Subject: [PATCH 042/122] fix: rendermethod v2 (#72) --- .../src/context/render-method-context-v2.json | 24 +++++++++++++++++++ packages/w3c-context/src/lib/index.ts | 7 ++++++ packages/w3c-vc/src/lib/w3c-vc.test.ts | 1 + 3 files changed, 32 insertions(+) create mode 100644 packages/w3c-context/src/context/render-method-context-v2.json diff --git a/packages/w3c-context/src/context/render-method-context-v2.json b/packages/w3c-context/src/context/render-method-context-v2.json new file mode 100644 index 00000000..664d140b --- /dev/null +++ b/packages/w3c-context/src/context/render-method-context-v2.json @@ -0,0 +1,24 @@ +{ + "@context": { + "@version": 1.1, + "xsd": "http://www.w3.org/2001/XMLSchema#", + "renderMethod": { + "@id": "https://example.org/terms#renderMethod", + "@container": "@set", + "@context": { + "@protected": true, + "id": { + "@id": "https://example.org/terms#id", + "@type": "xsd:anyURI" + }, + "type": { + "@id": "https://example.org/terms#type" + }, + "templateName": { + "@id": "https://example.org/terms#templateName" + } + } + } + } + } + \ No newline at end of file diff --git a/packages/w3c-context/src/lib/index.ts b/packages/w3c-context/src/lib/index.ts index 77a187fe..8d1e8473 100644 --- a/packages/w3c-context/src/lib/index.ts +++ b/packages/w3c-context/src/lib/index.ts @@ -16,6 +16,7 @@ import multikeyV1 from '../context/multikey-v1.json'; import promissoryNoteContext from '../context/promissory-note.json'; import qrCodeContext from '../context/qrcode-context.json'; import renderContext from '../context/render-method-context.json'; +import renderContextV2 from '../context/render-method-context-v2.json'; import statusList2021V1 from '../context/status-list-2021-v1.json'; import trContext from '../context/transferable-records-context.json'; import warehouseReceiptContext from '../context/warehouse-receipt.json'; @@ -33,6 +34,7 @@ export const STATUS_LIST_2021_CREDENTIAL_URL = 'https://w3id.org/vc/status-list/ export const TR_CONTEXT_URL = 'https://trustvc.io/context/transferable-records-context.json'; export const RENDER_CONTEXT_URL = 'https://trustvc.io/context/render-method-context.json'; +export const RENDER_CONTEXT_V2_URL = 'https://trustvc.io/context/render-method-context-v2.json'; export const ATTACHMENTS_CONTEXT_URL = 'https://trustvc.io/context/attachments-context.json'; export const QRCODE_CONTEXT_URL = 'https://trustvc.io/context/qrcode-context.json'; @@ -63,6 +65,10 @@ export const renderContexts: { [key: string]: Document } = { [RENDER_CONTEXT_URL]: renderContext, }; +export const renderContextsV2: { [key: string]: Document } = { + [RENDER_CONTEXT_V2_URL]: renderContextV2, +}; + export const attachmentsContexts: { [key: string]: Document } = { [ATTACHMENTS_CONTEXT_URL]: attachmentsContext, }; @@ -103,6 +109,7 @@ export async function getDocumentLoader( contexts, trContexts, renderContexts, + renderContextsV2, attachmentsContexts, qrCodeContexts, templateContexts, diff --git a/packages/w3c-vc/src/lib/w3c-vc.test.ts b/packages/w3c-vc/src/lib/w3c-vc.test.ts index de5c3167..c232ba08 100644 --- a/packages/w3c-vc/src/lib/w3c-vc.test.ts +++ b/packages/w3c-vc/src/lib/w3c-vc.test.ts @@ -176,6 +176,7 @@ const ecdsaCredentialV2_0: VerifiableCredential = { 'https://w3id.org/security/data-integrity/v2', 'https://w3id.org/vc/status-list/2021/v1', 'https://trustvc.io/context/transferable-records-context.json', + 'https://trustvc.io/context/render-method-context-v2.json', 'https://trustvc.io/context/attachments-context.json', 'https://trustvc.io/context/qrcode-context.json', 'https://trustvc.io/context/bill-of-lading.json', From 0b252f7b24096299e99e8e1f2c6e1078ebfb58b7 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Mon, 18 Aug 2025 08:45:55 +0000 Subject: [PATCH 043/122] chore(release): @trustvc/w3c-context@1.3.0-alpha.4 [skip ci] # [1.3.0-alpha.4](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-context@1.3.0-alpha.3...@trustvc/w3c-context@1.3.0-alpha.4) (2025-08-18) ### Bug Fixes * rendermethod v2 ([#72](https://github.com/TrustVC/w3c/issues/72)) ([3fbc3a3](https://github.com/TrustVC/w3c/commit/3fbc3a332dfe33e56b5d077ff67d6b219e0a3d00)) --- packages/w3c-context/CHANGELOG.md | 7 +++++++ packages/w3c-context/package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/w3c-context/CHANGELOG.md b/packages/w3c-context/CHANGELOG.md index 8d20c03f..7475a5b2 100644 --- a/packages/w3c-context/CHANGELOG.md +++ b/packages/w3c-context/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.4](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-context@1.3.0-alpha.3...@trustvc/w3c-context@1.3.0-alpha.4) (2025-08-18) + + +### Bug Fixes + +* rendermethod v2 ([#72](https://github.com/TrustVC/w3c/issues/72)) ([3fbc3a3](https://github.com/TrustVC/w3c/commit/3fbc3a332dfe33e56b5d077ff67d6b219e0a3d00)) + # [1.3.0-alpha.3](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-context@1.3.0-alpha.2...@trustvc/w3c-context@1.3.0-alpha.3) (2025-08-13) diff --git a/packages/w3c-context/package.json b/packages/w3c-context/package.json index 5682f8e7..9adc4da3 100644 --- a/packages/w3c-context/package.json +++ b/packages/w3c-context/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c-context", - "version": "1.3.0-alpha.3", + "version": "1.3.0-alpha.4", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", From bd63fb5a7984dd31c5fd3488ecf31bcaede16b71 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Mon, 18 Aug 2025 08:46:38 +0000 Subject: [PATCH 044/122] chore(release): @trustvc/w3c-credential-status@1.3.0-alpha.4 [skip ci] # [1.3.0-alpha.4](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-credential-status@1.3.0-alpha.3...@trustvc/w3c-credential-status@1.3.0-alpha.4) (2025-08-18) ### Bug Fixes * rendermethod v2 ([#72](https://github.com/TrustVC/w3c/issues/72)) ([3fbc3a3](https://github.com/TrustVC/w3c/commit/3fbc3a332dfe33e56b5d077ff67d6b219e0a3d00)) --- packages/w3c-credential-status/CHANGELOG.md | 7 +++++++ packages/w3c-credential-status/package.json | 4 ++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/packages/w3c-credential-status/CHANGELOG.md b/packages/w3c-credential-status/CHANGELOG.md index 27dca536..25503136 100644 --- a/packages/w3c-credential-status/CHANGELOG.md +++ b/packages/w3c-credential-status/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.4](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-credential-status@1.3.0-alpha.3...@trustvc/w3c-credential-status@1.3.0-alpha.4) (2025-08-18) + + +### Bug Fixes + +* rendermethod v2 ([#72](https://github.com/TrustVC/w3c/issues/72)) ([3fbc3a3](https://github.com/TrustVC/w3c/commit/3fbc3a332dfe33e56b5d077ff67d6b219e0a3d00)) + # [1.3.0-alpha.3](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-credential-status@1.3.0-alpha.2...@trustvc/w3c-credential-status@1.3.0-alpha.3) (2025-08-13) diff --git a/packages/w3c-credential-status/package.json b/packages/w3c-credential-status/package.json index f5187771..1e32dd86 100644 --- a/packages/w3c-credential-status/package.json +++ b/packages/w3c-credential-status/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c-credential-status", - "version": "1.3.0-alpha.3", + "version": "1.3.0-alpha.4", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", @@ -29,7 +29,7 @@ } }, "dependencies": { - "@trustvc/w3c-context": "^1.3.0-alpha.3", + "@trustvc/w3c-context": "^1.3.0-alpha.4", "@trustvc/w3c-issuer": "^1.3.0-alpha.3", "base64url-universal": "^2.0.0", "pako": "^2.1.0" From 6a8fae978e0f78d538da211977e703f3a79dd2ff Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Mon, 18 Aug 2025 08:47:19 +0000 Subject: [PATCH 045/122] chore(release): @trustvc/w3c-vc@1.3.0-alpha.4 [skip ci] # [1.3.0-alpha.4](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.3.0-alpha.3...@trustvc/w3c-vc@1.3.0-alpha.4) (2025-08-18) ### Bug Fixes * rendermethod v2 ([#72](https://github.com/TrustVC/w3c/issues/72)) ([3fbc3a3](https://github.com/TrustVC/w3c/commit/3fbc3a332dfe33e56b5d077ff67d6b219e0a3d00)) --- packages/w3c-vc/CHANGELOG.md | 7 +++++++ packages/w3c-vc/package.json | 4 ++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/packages/w3c-vc/CHANGELOG.md b/packages/w3c-vc/CHANGELOG.md index 550073f3..708f7108 100644 --- a/packages/w3c-vc/CHANGELOG.md +++ b/packages/w3c-vc/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.4](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.3.0-alpha.3...@trustvc/w3c-vc@1.3.0-alpha.4) (2025-08-18) + + +### Bug Fixes + +* rendermethod v2 ([#72](https://github.com/TrustVC/w3c/issues/72)) ([3fbc3a3](https://github.com/TrustVC/w3c/commit/3fbc3a332dfe33e56b5d077ff67d6b219e0a3d00)) + # [1.3.0-alpha.3](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.3.0-alpha.2...@trustvc/w3c-vc@1.3.0-alpha.3) (2025-08-13) diff --git a/packages/w3c-vc/package.json b/packages/w3c-vc/package.json index 836398cd..90625153 100644 --- a/packages/w3c-vc/package.json +++ b/packages/w3c-vc/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c-vc", - "version": "1.3.0-alpha.3", + "version": "1.3.0-alpha.4", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", @@ -35,7 +35,7 @@ "@digitalbazaar/ecdsa-multikey": "^1.8.0", "@digitalbazaar/ecdsa-sd-2023-cryptosuite": "^3.4.1", "@mattrglobal/jsonld-signatures-bbs": "^1.2.0", - "@trustvc/w3c-credential-status": "^1.3.0-alpha.3", + "@trustvc/w3c-credential-status": "^1.3.0-alpha.4", "@trustvc/w3c-issuer": "^1.3.0-alpha.3", "did-resolver": "^4.1.0", "jsonld": "^6.0.0", From d1822cb1c8ca4947d48801900566592b4c4af983 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Mon, 18 Aug 2025 08:47:58 +0000 Subject: [PATCH 046/122] chore(release): @trustvc/w3c-cli@1.3.0-alpha.4 [skip ci] # [1.3.0-alpha.4](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-cli@1.3.0-alpha.3...@trustvc/w3c-cli@1.3.0-alpha.4) (2025-08-18) ### Bug Fixes * rendermethod v2 ([#72](https://github.com/TrustVC/w3c/issues/72)) ([3fbc3a3](https://github.com/TrustVC/w3c/commit/3fbc3a332dfe33e56b5d077ff67d6b219e0a3d00)) --- apps/w3c-cli/CHANGELOG.md | 7 +++++++ apps/w3c-cli/package.json | 8 ++++---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/apps/w3c-cli/CHANGELOG.md b/apps/w3c-cli/CHANGELOG.md index a35fb7cf..32e4dec4 100644 --- a/apps/w3c-cli/CHANGELOG.md +++ b/apps/w3c-cli/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.4](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-cli@1.3.0-alpha.3...@trustvc/w3c-cli@1.3.0-alpha.4) (2025-08-18) + + +### Bug Fixes + +* rendermethod v2 ([#72](https://github.com/TrustVC/w3c/issues/72)) ([3fbc3a3](https://github.com/TrustVC/w3c/commit/3fbc3a332dfe33e56b5d077ff67d6b219e0a3d00)) + # [1.3.0-alpha.3](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-cli@1.3.0-alpha.2...@trustvc/w3c-cli@1.3.0-alpha.3) (2025-08-13) diff --git a/apps/w3c-cli/package.json b/apps/w3c-cli/package.json index 9470f098..0585a908 100644 --- a/apps/w3c-cli/package.json +++ b/apps/w3c-cli/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c-cli", - "version": "1.3.0-alpha.3", + "version": "1.3.0-alpha.4", "description": "CLI for TrustVC W3C", "main": "dist/main.js", "types": "dist/main.d.ts", @@ -34,9 +34,9 @@ }, "dependencies": { "@inquirer/prompts": "^5.3.8", - "@trustvc/w3c-context": "^1.3.0-alpha.3", - "@trustvc/w3c-credential-status": "^1.3.0-alpha.3", - "@trustvc/w3c-vc": "^1.3.0-alpha.3", + "@trustvc/w3c-context": "^1.3.0-alpha.4", + "@trustvc/w3c-credential-status": "^1.3.0-alpha.4", + "@trustvc/w3c-vc": "^1.3.0-alpha.4", "@trustvc/w3c-issuer": "^1.3.0-alpha.3", "@types/yargs": "^17.0.32", "chalk": "^4.1.2", From 6de9d47e62d820fc81f9428fdaf1b9f15daa74f2 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Mon, 18 Aug 2025 08:48:37 +0000 Subject: [PATCH 047/122] chore(release): @trustvc/w3c@1.3.0-alpha.4 [skip ci] # [1.3.0-alpha.4](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.3.0-alpha.3...@trustvc/w3c@1.3.0-alpha.4) (2025-08-18) ### Bug Fixes * rendermethod v2 ([#72](https://github.com/TrustVC/w3c/issues/72)) ([3fbc3a3](https://github.com/TrustVC/w3c/commit/3fbc3a332dfe33e56b5d077ff67d6b219e0a3d00)) --- packages/w3c/CHANGELOG.md | 7 +++++++ packages/w3c/package.json | 8 ++++---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/packages/w3c/CHANGELOG.md b/packages/w3c/CHANGELOG.md index a564d0c3..e1ea3cbf 100644 --- a/packages/w3c/CHANGELOG.md +++ b/packages/w3c/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.4](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.3.0-alpha.3...@trustvc/w3c@1.3.0-alpha.4) (2025-08-18) + + +### Bug Fixes + +* rendermethod v2 ([#72](https://github.com/TrustVC/w3c/issues/72)) ([3fbc3a3](https://github.com/TrustVC/w3c/commit/3fbc3a332dfe33e56b5d077ff67d6b219e0a3d00)) + # [1.3.0-alpha.3](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.3.0-alpha.2...@trustvc/w3c@1.3.0-alpha.3) (2025-08-13) diff --git a/packages/w3c/package.json b/packages/w3c/package.json index 352960f0..fa84ca1b 100644 --- a/packages/w3c/package.json +++ b/packages/w3c/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c", - "version": "1.3.0-alpha.3", + "version": "1.3.0-alpha.4", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", @@ -32,10 +32,10 @@ } }, "dependencies": { - "@trustvc/w3c-context": "^1.3.0-alpha.3", - "@trustvc/w3c-credential-status": "^1.3.0-alpha.3", + "@trustvc/w3c-context": "^1.3.0-alpha.4", + "@trustvc/w3c-credential-status": "^1.3.0-alpha.4", "@trustvc/w3c-issuer": "^1.3.0-alpha.3", - "@trustvc/w3c-vc": "^1.3.0-alpha.3" + "@trustvc/w3c-vc": "^1.3.0-alpha.4" }, "repository": { "type": "git", From 6e1a06772e23278bd2de6beaaee5ca9adb5608aa Mon Sep 17 00:00:00 2001 From: rongquan1 <85145303+rongquan1@users.noreply.github.com> Date: Mon, 18 Aug 2025 17:07:53 +0800 Subject: [PATCH 048/122] fix: rendermethod v2 (#73) * fix: rendermethod v2 * fix: rendermethod v2 --- .../src/context/render-method-context-v2.json | 29 ++++++------------- 1 file changed, 9 insertions(+), 20 deletions(-) diff --git a/packages/w3c-context/src/context/render-method-context-v2.json b/packages/w3c-context/src/context/render-method-context-v2.json index 664d140b..af1e2670 100644 --- a/packages/w3c-context/src/context/render-method-context-v2.json +++ b/packages/w3c-context/src/context/render-method-context-v2.json @@ -1,24 +1,13 @@ { - "@context": { - "@version": 1.1, - "xsd": "http://www.w3.org/2001/XMLSchema#", - "renderMethod": { - "@id": "https://example.org/terms#renderMethod", - "@container": "@set", - "@context": { - "@protected": true, - "id": { - "@id": "https://example.org/terms#id", - "@type": "xsd:anyURI" - }, - "type": { - "@id": "https://example.org/terms#type" - }, - "templateName": { - "@id": "https://example.org/terms#templateName" - } - } + "@context": { + "@version": 1.1, + "@protected": true, + "xsd": "http://www.w3.org/2001/XMLSchema#", + "EMBEDDED_RENDERER": { + "@id": "https://example.org/terms#EmbeddedRenderer", + "@context": { + "templateName": "https://example.org/terms#templateName" } } } - \ No newline at end of file +} From e26a068a1e0c139829c57abe888ecac5f5167849 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Mon, 18 Aug 2025 09:10:51 +0000 Subject: [PATCH 049/122] chore(release): @trustvc/w3c-context@1.3.0-alpha.5 [skip ci] # [1.3.0-alpha.5](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-context@1.3.0-alpha.4...@trustvc/w3c-context@1.3.0-alpha.5) (2025-08-18) ### Bug Fixes * rendermethod v2 ([#73](https://github.com/TrustVC/w3c/issues/73)) ([6e1a067](https://github.com/TrustVC/w3c/commit/6e1a06772e23278bd2de6beaaee5ca9adb5608aa)) --- packages/w3c-context/CHANGELOG.md | 7 +++++++ packages/w3c-context/package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/w3c-context/CHANGELOG.md b/packages/w3c-context/CHANGELOG.md index 7475a5b2..db1e2cba 100644 --- a/packages/w3c-context/CHANGELOG.md +++ b/packages/w3c-context/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.5](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-context@1.3.0-alpha.4...@trustvc/w3c-context@1.3.0-alpha.5) (2025-08-18) + + +### Bug Fixes + +* rendermethod v2 ([#73](https://github.com/TrustVC/w3c/issues/73)) ([6e1a067](https://github.com/TrustVC/w3c/commit/6e1a06772e23278bd2de6beaaee5ca9adb5608aa)) + # [1.3.0-alpha.4](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-context@1.3.0-alpha.3...@trustvc/w3c-context@1.3.0-alpha.4) (2025-08-18) diff --git a/packages/w3c-context/package.json b/packages/w3c-context/package.json index 9adc4da3..8e3f4c45 100644 --- a/packages/w3c-context/package.json +++ b/packages/w3c-context/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c-context", - "version": "1.3.0-alpha.4", + "version": "1.3.0-alpha.5", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", From 000c17e3177f942ec04bfe9dfcb1c287f180f10f Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Mon, 18 Aug 2025 09:11:30 +0000 Subject: [PATCH 050/122] chore(release): @trustvc/w3c-credential-status@1.3.0-alpha.5 [skip ci] # [1.3.0-alpha.5](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-credential-status@1.3.0-alpha.4...@trustvc/w3c-credential-status@1.3.0-alpha.5) (2025-08-18) ### Bug Fixes * rendermethod v2 ([#73](https://github.com/TrustVC/w3c/issues/73)) ([6e1a067](https://github.com/TrustVC/w3c/commit/6e1a06772e23278bd2de6beaaee5ca9adb5608aa)) --- packages/w3c-credential-status/CHANGELOG.md | 7 +++++++ packages/w3c-credential-status/package.json | 4 ++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/packages/w3c-credential-status/CHANGELOG.md b/packages/w3c-credential-status/CHANGELOG.md index 25503136..23f29c92 100644 --- a/packages/w3c-credential-status/CHANGELOG.md +++ b/packages/w3c-credential-status/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.5](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-credential-status@1.3.0-alpha.4...@trustvc/w3c-credential-status@1.3.0-alpha.5) (2025-08-18) + + +### Bug Fixes + +* rendermethod v2 ([#73](https://github.com/TrustVC/w3c/issues/73)) ([6e1a067](https://github.com/TrustVC/w3c/commit/6e1a06772e23278bd2de6beaaee5ca9adb5608aa)) + # [1.3.0-alpha.4](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-credential-status@1.3.0-alpha.3...@trustvc/w3c-credential-status@1.3.0-alpha.4) (2025-08-18) diff --git a/packages/w3c-credential-status/package.json b/packages/w3c-credential-status/package.json index 1e32dd86..2f86b809 100644 --- a/packages/w3c-credential-status/package.json +++ b/packages/w3c-credential-status/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c-credential-status", - "version": "1.3.0-alpha.4", + "version": "1.3.0-alpha.5", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", @@ -29,7 +29,7 @@ } }, "dependencies": { - "@trustvc/w3c-context": "^1.3.0-alpha.4", + "@trustvc/w3c-context": "^1.3.0-alpha.5", "@trustvc/w3c-issuer": "^1.3.0-alpha.3", "base64url-universal": "^2.0.0", "pako": "^2.1.0" From 732f6f772707cf43d1f49464ae7093d5f3b9ae67 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Mon, 18 Aug 2025 09:12:10 +0000 Subject: [PATCH 051/122] chore(release): @trustvc/w3c-vc@1.3.0-alpha.5 [skip ci] # [1.3.0-alpha.5](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.3.0-alpha.4...@trustvc/w3c-vc@1.3.0-alpha.5) (2025-08-18) ### Bug Fixes * rendermethod v2 ([#73](https://github.com/TrustVC/w3c/issues/73)) ([6e1a067](https://github.com/TrustVC/w3c/commit/6e1a06772e23278bd2de6beaaee5ca9adb5608aa)) --- packages/w3c-vc/CHANGELOG.md | 7 +++++++ packages/w3c-vc/package.json | 4 ++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/packages/w3c-vc/CHANGELOG.md b/packages/w3c-vc/CHANGELOG.md index 708f7108..29ad20c9 100644 --- a/packages/w3c-vc/CHANGELOG.md +++ b/packages/w3c-vc/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.5](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.3.0-alpha.4...@trustvc/w3c-vc@1.3.0-alpha.5) (2025-08-18) + + +### Bug Fixes + +* rendermethod v2 ([#73](https://github.com/TrustVC/w3c/issues/73)) ([6e1a067](https://github.com/TrustVC/w3c/commit/6e1a06772e23278bd2de6beaaee5ca9adb5608aa)) + # [1.3.0-alpha.4](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.3.0-alpha.3...@trustvc/w3c-vc@1.3.0-alpha.4) (2025-08-18) diff --git a/packages/w3c-vc/package.json b/packages/w3c-vc/package.json index 90625153..43d8d763 100644 --- a/packages/w3c-vc/package.json +++ b/packages/w3c-vc/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c-vc", - "version": "1.3.0-alpha.4", + "version": "1.3.0-alpha.5", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", @@ -35,7 +35,7 @@ "@digitalbazaar/ecdsa-multikey": "^1.8.0", "@digitalbazaar/ecdsa-sd-2023-cryptosuite": "^3.4.1", "@mattrglobal/jsonld-signatures-bbs": "^1.2.0", - "@trustvc/w3c-credential-status": "^1.3.0-alpha.4", + "@trustvc/w3c-credential-status": "^1.3.0-alpha.5", "@trustvc/w3c-issuer": "^1.3.0-alpha.3", "did-resolver": "^4.1.0", "jsonld": "^6.0.0", From c46e1dc22d246b76ec45c93addc43087f56a4eb4 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Mon, 18 Aug 2025 09:12:46 +0000 Subject: [PATCH 052/122] chore(release): @trustvc/w3c-cli@1.3.0-alpha.5 [skip ci] # [1.3.0-alpha.5](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-cli@1.3.0-alpha.4...@trustvc/w3c-cli@1.3.0-alpha.5) (2025-08-18) ### Bug Fixes * rendermethod v2 ([#73](https://github.com/TrustVC/w3c/issues/73)) ([6e1a067](https://github.com/TrustVC/w3c/commit/6e1a06772e23278bd2de6beaaee5ca9adb5608aa)) --- apps/w3c-cli/CHANGELOG.md | 7 +++++++ apps/w3c-cli/package.json | 8 ++++---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/apps/w3c-cli/CHANGELOG.md b/apps/w3c-cli/CHANGELOG.md index 32e4dec4..4b7c2192 100644 --- a/apps/w3c-cli/CHANGELOG.md +++ b/apps/w3c-cli/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.5](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-cli@1.3.0-alpha.4...@trustvc/w3c-cli@1.3.0-alpha.5) (2025-08-18) + + +### Bug Fixes + +* rendermethod v2 ([#73](https://github.com/TrustVC/w3c/issues/73)) ([6e1a067](https://github.com/TrustVC/w3c/commit/6e1a06772e23278bd2de6beaaee5ca9adb5608aa)) + # [1.3.0-alpha.4](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-cli@1.3.0-alpha.3...@trustvc/w3c-cli@1.3.0-alpha.4) (2025-08-18) diff --git a/apps/w3c-cli/package.json b/apps/w3c-cli/package.json index 0585a908..6c0b5be5 100644 --- a/apps/w3c-cli/package.json +++ b/apps/w3c-cli/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c-cli", - "version": "1.3.0-alpha.4", + "version": "1.3.0-alpha.5", "description": "CLI for TrustVC W3C", "main": "dist/main.js", "types": "dist/main.d.ts", @@ -34,9 +34,9 @@ }, "dependencies": { "@inquirer/prompts": "^5.3.8", - "@trustvc/w3c-context": "^1.3.0-alpha.4", - "@trustvc/w3c-credential-status": "^1.3.0-alpha.4", - "@trustvc/w3c-vc": "^1.3.0-alpha.4", + "@trustvc/w3c-context": "^1.3.0-alpha.5", + "@trustvc/w3c-credential-status": "^1.3.0-alpha.5", + "@trustvc/w3c-vc": "^1.3.0-alpha.5", "@trustvc/w3c-issuer": "^1.3.0-alpha.3", "@types/yargs": "^17.0.32", "chalk": "^4.1.2", From 53f71c58d239f77115191fae37e7e4ead4a98d8f Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Mon, 18 Aug 2025 09:13:24 +0000 Subject: [PATCH 053/122] chore(release): @trustvc/w3c@1.3.0-alpha.5 [skip ci] # [1.3.0-alpha.5](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.3.0-alpha.4...@trustvc/w3c@1.3.0-alpha.5) (2025-08-18) ### Bug Fixes * rendermethod v2 ([#73](https://github.com/TrustVC/w3c/issues/73)) ([6e1a067](https://github.com/TrustVC/w3c/commit/6e1a06772e23278bd2de6beaaee5ca9adb5608aa)) --- packages/w3c/CHANGELOG.md | 7 +++++++ packages/w3c/package.json | 8 ++++---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/packages/w3c/CHANGELOG.md b/packages/w3c/CHANGELOG.md index e1ea3cbf..4e861c40 100644 --- a/packages/w3c/CHANGELOG.md +++ b/packages/w3c/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.5](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.3.0-alpha.4...@trustvc/w3c@1.3.0-alpha.5) (2025-08-18) + + +### Bug Fixes + +* rendermethod v2 ([#73](https://github.com/TrustVC/w3c/issues/73)) ([6e1a067](https://github.com/TrustVC/w3c/commit/6e1a06772e23278bd2de6beaaee5ca9adb5608aa)) + # [1.3.0-alpha.4](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.3.0-alpha.3...@trustvc/w3c@1.3.0-alpha.4) (2025-08-18) diff --git a/packages/w3c/package.json b/packages/w3c/package.json index fa84ca1b..a3b9ecfe 100644 --- a/packages/w3c/package.json +++ b/packages/w3c/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c", - "version": "1.3.0-alpha.4", + "version": "1.3.0-alpha.5", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", @@ -32,10 +32,10 @@ } }, "dependencies": { - "@trustvc/w3c-context": "^1.3.0-alpha.4", - "@trustvc/w3c-credential-status": "^1.3.0-alpha.4", + "@trustvc/w3c-context": "^1.3.0-alpha.5", + "@trustvc/w3c-credential-status": "^1.3.0-alpha.5", "@trustvc/w3c-issuer": "^1.3.0-alpha.3", - "@trustvc/w3c-vc": "^1.3.0-alpha.4" + "@trustvc/w3c-vc": "^1.3.0-alpha.5" }, "repository": { "type": "git", From 7fe399e7b58910912cce4920bab177732791538b Mon Sep 17 00:00:00 2001 From: rongquan1 <85145303+rongquan1@users.noreply.github.com> Date: Tue, 19 Aug 2025 11:25:05 +0800 Subject: [PATCH 054/122] feat: add support for w3c data model 2.0 with bitstring status list and ecdsa (#75) * feat: add support for w3c data model 2.0 with bitstring status list and ecdsa * fix: refactor --- package-lock.json | 48 +++-- packages/w3c-credential-status/README.md | 191 ++++++++++++++---- .../BitstringStatusList/assertions.test.ts | 96 ++++++--- .../src/lib/BitstringStatusList/assertions.ts | 42 +++- .../src/lib/index.test.ts | 96 ++++++++- .../w3c-credential-status/src/lib/index.ts | 38 +++- .../w3c-credential-status/src/lib/types.ts | 4 +- .../src/lib/utils.test.ts | 2 +- .../w3c-credential-status/src/lib/utils.ts | 16 +- packages/w3c-vc/package.json | 1 + packages/w3c-vc/src/lib/helper/index.ts | 30 ++- packages/w3c-vc/src/lib/types.ts | 2 +- .../lib/verify/credentialStatus/index.test.ts | 39 +++- packages/w3c-vc/src/lib/w3c-vc.ts | 46 ++++- 14 files changed, 533 insertions(+), 118 deletions(-) diff --git a/package-lock.json b/package-lock.json index fd472b0f..b2bd535f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -115,14 +115,14 @@ }, "apps/w3c-cli": { "name": "@trustvc/w3c-cli", - "version": "1.3.0-alpha.3", + "version": "1.3.0-alpha.5", "license": "Apache-2.0", "dependencies": { "@inquirer/prompts": "^5.3.8", - "@trustvc/w3c-context": "^1.3.0-alpha.3", - "@trustvc/w3c-credential-status": "^1.3.0-alpha.3", + "@trustvc/w3c-context": "^1.3.0-alpha.5", + "@trustvc/w3c-credential-status": "^1.3.0-alpha.5", "@trustvc/w3c-issuer": "^1.3.0-alpha.3", - "@trustvc/w3c-vc": "^1.3.0-alpha.3", + "@trustvc/w3c-vc": "^1.3.0-alpha.5", "@types/yargs": "^17.0.32", "chalk": "^4.1.2", "inquirer": "^10.0.1", @@ -13016,6 +13016,18 @@ "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", "dev": true }, + "node_modules/cbor": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/cbor/-/cbor-9.0.2.tgz", + "integrity": "sha512-JPypkxsB10s9QOWwa6zwPzqE1Md3vqpPc+cai4sAecuCsRyAtAl/pMyhPlMbT/xtPnm2dznJZYRLui57qiRhaQ==", + "license": "MIT", + "dependencies": { + "nofilter": "^3.1.0" + }, + "engines": { + "node": ">=16" + } + }, "node_modules/cborg": { "version": "4.2.12", "resolved": "https://registry.npmjs.org/cborg/-/cborg-4.2.12.tgz", @@ -21667,6 +21679,15 @@ "node": ">=4" } }, + "node_modules/nofilter": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/nofilter/-/nofilter-3.1.0.tgz", + "integrity": "sha512-l2NNj07e9afPnhAhvgVrCD/oy2Ai1yfLpuo3EpiO1jFTsB4sFz6oIfAfSZyQzVpkZQ9xS8ZS5g1jCBgq4Hwo0g==", + "license": "MIT", + "engines": { + "node": ">=12.19" + } + }, "node_modules/nopt": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", @@ -32798,13 +32819,13 @@ }, "packages/w3c": { "name": "@trustvc/w3c", - "version": "1.3.0-alpha.3", + "version": "1.3.0-alpha.5", "license": "Apache-2.0", "dependencies": { - "@trustvc/w3c-context": "^1.3.0-alpha.3", - "@trustvc/w3c-credential-status": "^1.3.0-alpha.3", + "@trustvc/w3c-context": "^1.3.0-alpha.5", + "@trustvc/w3c-credential-status": "^1.3.0-alpha.5", "@trustvc/w3c-issuer": "^1.3.0-alpha.3", - "@trustvc/w3c-vc": "^1.3.0-alpha.3" + "@trustvc/w3c-vc": "^1.3.0-alpha.5" }, "engines": { "node": ">=18.x" @@ -32812,7 +32833,7 @@ }, "packages/w3c-context": { "name": "@trustvc/w3c-context", - "version": "1.3.0-alpha.3", + "version": "1.3.0-alpha.5", "license": "Apache-2.0", "dependencies": { "did-resolver": "^4.1.0", @@ -32904,10 +32925,10 @@ }, "packages/w3c-credential-status": { "name": "@trustvc/w3c-credential-status", - "version": "1.3.0-alpha.3", + "version": "1.3.0-alpha.5", "license": "Apache-2.0", "dependencies": { - "@trustvc/w3c-context": "^1.3.0-alpha.3", + "@trustvc/w3c-context": "^1.3.0-alpha.5", "@trustvc/w3c-issuer": "^1.3.0-alpha.3", "base64url-universal": "^2.0.0", "pako": "^2.1.0" @@ -32935,15 +32956,16 @@ }, "packages/w3c-vc": { "name": "@trustvc/w3c-vc", - "version": "1.3.0-alpha.3", + "version": "1.3.0-alpha.5", "license": "Apache-2.0", "dependencies": { "@digitalbazaar/data-integrity": "^2.5.0", "@digitalbazaar/ecdsa-multikey": "^1.8.0", "@digitalbazaar/ecdsa-sd-2023-cryptosuite": "^3.4.1", "@mattrglobal/jsonld-signatures-bbs": "^1.2.0", - "@trustvc/w3c-credential-status": "^1.3.0-alpha.3", + "@trustvc/w3c-credential-status": "^1.3.0-alpha.5", "@trustvc/w3c-issuer": "^1.3.0-alpha.3", + "cbor": "^9.0.2", "did-resolver": "^4.1.0", "jsonld": "^6.0.0", "jsonld-signatures": "^11.5.0", diff --git a/packages/w3c-credential-status/README.md b/packages/w3c-credential-status/README.md index cc7a9450..593ed883 100644 --- a/packages/w3c-credential-status/README.md +++ b/packages/w3c-credential-status/README.md @@ -2,14 +2,28 @@ Implements credential status management for Verifiable Credentials (VCs) using @trustvc/w3c-credential-status. It supports lifecycle operations such as revocation and suspension without altering the original credential, enabling verifiers to check a credential's current status. The project utilizes status lists and handles the credential validation process. -[Bitstring Status List](https://www.w3.org/TR/2023/WD-vc-status-list-20230427/) refers to a method of representing the revocation/suspension status of multiple items (such as digital certificates or credentials) using a bitstring (a sequence of bits). This technique allows for efficient tracking and management of which items are valid or revoked without needing to maintain extensive individual records for each item. +This package supports both **W3C VC Data Model v1.1** (legacy) and **W3C VC Data Model v2.0** (modern) specifications: + +- **v1.1 Support**: Uses `StatusList2021Credential` with `StatusList2021Entry` credential status +- **v2.0 Support**: Uses `BitstringStatusListCredential` with `BitstringStatusListEntry` credential status + +The [Bitstring Status List](https://www.w3.org/TR/vc-bitstring-status-list/) specification (v2.0) and the legacy [Status List 2021](https://www.w3.org/TR/2023/WD-vc-status-list-20230427/) specification (v1.1) both refer to methods of representing the revocation/suspension status of multiple items (such as digital certificates or credentials) using a bitstring (a sequence of bits). This technique allows for efficient tracking and management of which items are valid or revoked without needing to maintain extensive individual records for each item. ## Revoking/Suspending a VC -The revocation or suspension of a [Verifiable Credentials v1.1. -](https://www.w3.org/TR/vc-data-model/) is achieved by changing the binary value of the bitstring at its given position in the bitstring. Every time the bitstring state changes, it must be compressed, encoded, and published as a Status VC of type `StatusList2021Entry`. +The revocation or suspension of Verifiable Credentials is achieved by changing the binary value of the bitstring at its given position in the bitstring. Every time the bitstring state changes, it must be compressed, encoded, and published as a Status VC. + +**For W3C VC Data Model v1.1:** +- Status VC type: `StatusList2021Credential` +- Credential status type: `StatusList2021Entry` +- Credential subject type: `StatusList2021` -This module provides functionality to create/updat a signed Verifiable Credential (VC) for credential status, using a specified cryptographic suite and key pair. It supports the creation of different types of credential status VCs such as [StatusList2021Credential](https://www.w3.org/TR/2023/WD-vc-status-list-20230427/). +**For W3C VC Data Model v2.0:** +- Status VC type: `BitstringStatusListCredential` +- Credential status type: `BitstringStatusListEntry` +- Credential subject type: `BitstringStatusList` + +This module provides functionality to create/update a signed Verifiable Credential (VC) for credential status, using a specified cryptographic suite and key pair. It supports both legacy BBS+ signatures and modern ECDSA-SD-2023 cryptosuites. ## Table of Contents @@ -49,8 +63,12 @@ npm install @trustvc/w3c-credential-status ## Features -- Create Credential Status Verifiable Credentials (e.g., BBS). -- Update revocation status for existing VC. +- **Dual Version Support**: Compatible with both W3C VC Data Model v1.1 and v2.0 +- **Multiple Cryptosuites**: Supports BBS+ (legacy) and ECDSA-SD-2023 (modern) signatures +- **Flexible Status Types**: Create both `StatusList2021Credential` and `BitstringStatusListCredential` +- **Backward Compatibility**: Existing v1.1 implementations continue to work +- Create Credential Status Verifiable Credentials with various cryptographic suites +- Update revocation status for existing VCs --- @@ -76,7 +94,7 @@ import { signCredential, SignedVerifiableCredential } from '@trustvc/w3c-vc'; Pick a URL where you'd like to host your credential status. (e.g., https://example.com/credentials/statuslist/1) ```typescript -const hostingUrl = https://example.com/credentials/statuslist/1; +const hostingUrl = 'https://example.com/credentials/statuslist/1'; ``` You can create a new StatusList object with a default or custom length. By default, the list is 131,072 bits (16 KB), but you can adjust it if needed. @@ -92,12 +110,11 @@ const credentialStatus = new StatusList({ length: 131072 }); The StatusList can serve different purposes, such as revocation or suspension of credentials. You can choose the purpose using the following setup: -```typecript +```typescript type CredentialStatusPurpose = 'revocation' | 'suspension'; // Choose between 'revocation' or 'suspension' -const purpose: CredentialStatusPurpose = "revocation"; - +const purpose: CredentialStatusPurpose = 'revocation'; ``` #### Step 4 - Retrieve and update the status of the index of the StatusList @@ -140,36 +157,53 @@ import { PrivateKeyPair } from '@trustvc/w3c-issuer'; * - options.id (string): The ID of the credential. * - options.credentialSubject (object): The credential subject. * - keyPair (PrivateKeyPair): The key pair options for signing - * - type (VCCredentialStatusType): The type of the credential status VC. Defaults to 'StatusList2021Credential'. - * - cryptoSuite (string): The cryptosuite to be used for signing. Defaults to 'BbsBlsSignature2020'. + * - type (VCCredentialStatusType): The type of the credential status VC. + * Options: 'StatusList2021Credential' (v1.1) or 'BitstringStatusListCredential' (v2.0) + * - cryptoSuite (string): The cryptosuite to be used for signing. + * Options: 'BbsBlsSignature2020' (legacy) or 'ecdsa-sd-2023' (modern) * * Returns: * - A Promise that resolves to: * - RawCredentialStatusVC: The signed credential status Verifiable Credential. */ -const options = { +// Example for W3C VC Data Model v1.1 (legacy) +const optionsV1 = { id: hostingUrl, credentialSubject: { id: `${hostingUrl}#list`, - type: 'StatusList2021', + type: 'StatusList2021', // v1.1 credential subject type statusPurpose: purpose, encodedList, }; } -const keyPair = { - "id": "did:web:trustvc.github.io:did:1#keys-1", - "type": "Bls12381G2Key2020", - "controller": "did:web:trustvc.github.io:did:1", - "seedBase58": "", - "privateKeyBase58": "", - "publicKeyBase58": "oRfEeWFresvhRtXCkihZbxyoi2JER7gHTJ5psXhHsdCoU1MttRMi3Yp9b9fpjmKh7bMgfWKLESiK2YovRd8KGzJsGuamoAXfqDDVhckxuc9nmsJ84skCSTijKeU4pfAcxeJ" -}; +const credentialStatusVCV1 = await createCredentialStatusPayload( + optionsV1, + keyPair, + 'StatusList2021Credential', // v1.1 credential type + 'BbsBlsSignature2020' // legacy cryptosuite +); + +// Example for W3C VC Data Model v2.0 (modern) +const optionsV2 = { + id: hostingUrl, + credentialSubject: { + id: `${hostingUrl}#list`, + type: 'BitstringStatusList', // v2.0 credential subject type + statusPurpose: purpose, + encodedList, + }; +} -const credentialStatusVC = await createCredentialStatusPayload(options, keyPair); +const credentialStatusVCV2 = await createCredentialStatusPayload( + optionsV2, + keyPair, + 'BitstringStatusListCredential', // v2.0 credential type + 'ecdsa-sd-2023' // modern cryptosuite +); -console.log('Credential Status VC:', credentialStatusVC); +console.log('Credential Status VC:', credentialStatusVCV2); // Sign the credential status payload const { signed, error } = await signCredential(credentialStatusPayload, keypairData); @@ -183,7 +217,7 @@ const signedCredentialStatusVC = signed; ```
- signCredential Result + signCredential Result (v1.1 with BBS+) ```js Signed Credential: { @@ -221,6 +255,44 @@ Signed Credential: {
+
+ signCredential Result (v2.0 with ECDSA-SD-2023) + +```js +Signed Credential: { + '@context': [ + 'https://www.w3.org/ns/credentials/v2', + 'https://w3id.org/security/data-integrity/v2' + ], + credentialStatus: { + id: 'https://trustvc.github.io/did/credentials/statuslist/1#1', + statusListCredential: 'https://trustvc.github.io/did/credentials/statuslist/1', + statusListIndex: '1', + statusPurpose: 'revocation', + type: 'BitstringStatusListEntry' + }, + validFrom: '2024-04-01T12:19:52Z', + credentialSubject: { + id: 'did:example:b34ca6cd37bbf23', + type: [ 'Person' ], + name: 'TrustVC' + }, + validUntil: '2029-12-03T12:19:52Z', + issuer: 'did:web:trustvc.github.io:did:1', + type: [ 'VerifiableCredential' ], + proof: { + type: 'DataIntegrityProof', + cryptosuite: 'ecdsa-sd-2023', + created: '2024-10-02T09:04:07Z', + proofPurpose: 'assertionMethod', + proofValue: 'u2V0AhVhAip...', + verificationMethod: 'did:web:trustvc.github.io:did:1#multikey-1' + } +} +``` + +
+ --- ### 2. Update revocation status for existing VC @@ -284,19 +356,20 @@ After updating the status list, encode it and create a signed credential status // Encode the updated status list const encodedList = await statusList.encode(); -// Create the credential status payload +// Create the credential status payload (v1.1 example) const credentialStatusPayload = await createCredentialStatusPayload( { id: hostingUrl, credentialSubject: { id: `${hostingUrl}#list`, - type: 'StatusList2021', + type: 'StatusList2021', // Use 'BitstringStatusList' for v2.0 statusPurpose: purpose, encodedList, }, }, keypairData, // Your key pair data - 'StatusList2021Credential', + 'StatusList2021Credential', // Use 'BitstringStatusListCredential' for v2.0 + 'BbsBlsSignature2020' // Use 'ecdsa-sd-2023' for modern cryptosuite ); // Sign the credential status payload @@ -315,7 +388,7 @@ const signedCredentialStatusVC = signed; ### `createCredentialStatusPayload` -> Creates a credential status payload. +> Creates a credential status payload for both W3C VC Data Model v1.1 and v2.0. > > #### Parameters: > @@ -323,11 +396,17 @@ const signedCredentialStatusVC = signed; > > `keypairData (object)`: The key pair data used for signing. > -> `credentialType (string)`: The type of credential (e.g., >'StatusList2021Credential'). +> `credentialType (VCCredentialStatusType)`: The type of credential. Options: +> - `'StatusList2021Credential'` (v1.1 legacy) +> - `'BitstringStatusListCredential'` (v2.0 modern) +> +> `cryptoSuite (CryptoSuiteName)`: The cryptosuite for signing. Options: +> - `'BbsBlsSignature2020'` (legacy BBS+ signatures) +> - `'ecdsa-sd-2023'` (modern ECDSA-SD-2023 signatures) ### `signCredential` -> Signs the credential status payload. +> Signs the credential status payload using the specified cryptosuite. > > #### Parameters: > @@ -337,7 +416,7 @@ const signedCredentialStatusVC = signed; ### `StatusList` -> Creates a new StatusList instance with a specified length and an optional >initial buffer. +> Creates a new StatusList instance with a specified length and an optional initial buffer. Compatible with both v1.1 and v2.0 credential formats. > > #### Constructor > @@ -349,7 +428,7 @@ const signedCredentialStatusVC = signed; > > `length (number)`: The length of the bitstring. > -> `buffer (Buffer | undefined)`: An optional buffer containing the initial >state of the bitstring. +> `buffer (Buffer | undefined)`: An optional buffer containing the initial state of the bitstring. > > #### Methods > @@ -359,4 +438,48 @@ const signedCredentialStatusVC = signed; > > `encode(): Promise` > -> `static decode({ encodedList }: { encodedList: string }): >Promise` +> `static decode({ encodedList }: { encodedList: string }): Promise` + +### Types + +#### `VCCredentialStatusType` +```typescript +type VCCredentialStatusType = 'BitstringStatusListCredential' | 'StatusList2021Credential'; +``` + +#### `CredentialStatusType` +```typescript +type CredentialStatusType = 'BitstringStatusListEntry' | 'StatusList2021Entry'; +``` + +#### `VCCredentialSubjectType` +```typescript +type VCCredentialSubjectType = 'BitstringStatusList' | 'StatusList2021'; +``` + +#### `CredentialStatusPurpose` +```typescript +type CredentialStatusPurpose = 'revocation' | 'suspension' | 'message'; +``` + +## Migration Guide + +### From v1.1 to v2.0 + +To migrate from W3C VC Data Model v1.1 to v2.0: + +1. **Update credential types:** + - `StatusList2021Credential` → `BitstringStatusListCredential` + - `StatusList2021Entry` → `BitstringStatusListEntry` + - `StatusList2021` → `BitstringStatusList` + +2. **Update cryptosuite:** + - `BbsBlsSignature2020` → `ecdsa-sd-2023` + +3. **Update key pair format:** + - Legacy BLS keys → Modern ECDSA multikey format + +4. **Update contexts:** + - v1.1 contexts → v2.0 contexts (handled automatically) + +The `StatusList` class remains the same and works with both versions. diff --git a/packages/w3c-credential-status/src/lib/BitstringStatusList/assertions.test.ts b/packages/w3c-credential-status/src/lib/BitstringStatusList/assertions.test.ts index d184570b..8f636a5d 100644 --- a/packages/w3c-credential-status/src/lib/BitstringStatusList/assertions.test.ts +++ b/packages/w3c-credential-status/src/lib/BitstringStatusList/assertions.test.ts @@ -1,6 +1,7 @@ import { describe, it, expect } from 'vitest'; import { _checkCredentialSubjectForStatusList2021Credential, + _checkCredentialSubjectForBitstringStatusListCredential, isBoolean, isNonNegativeInteger, isNumber, @@ -81,62 +82,103 @@ describe('assertions', () => { }); }); - describe('_checkCredentialSubjectForStatusList2021Credential', () => { + describe.each([ + { + functionName: '_checkCredentialSubjectForStatusList2021Credential', + testFunction: _checkCredentialSubjectForStatusList2021Credential, + expectedType: 'StatusList2021' as const, + credentialType: 'StatusList2021Credential', + wrongType: 'BitstringStatusList' as const, + }, + { + functionName: '_checkCredentialSubjectForBitstringStatusListCredential', + testFunction: _checkCredentialSubjectForBitstringStatusListCredential, + expectedType: 'BitstringStatusList' as const, + credentialType: 'BitstringStatusListCredential', + wrongType: 'StatusList2021' as const, + }, + ])('$functionName', ({ testFunction, expectedType, credentialType, wrongType }) => { it('should throw if no credentialSubject', () => { - expect(() => - _checkCredentialSubjectForStatusList2021Credential(undefined as any), - ).toThrowErrorMatchingInlineSnapshot(`[Error: Credential subject must be an object.]`); + expect(() => testFunction(undefined as any)).toThrow('Credential subject must be an object.'); }); it('should throw if no type', () => { expect(() => - _checkCredentialSubjectForStatusList2021Credential({} as any), - ).toThrowErrorMatchingInlineSnapshot(`[Error: Credential subject must have a type.]`); + testFunction({ + statusPurpose: 'revocation', + encodedList: 'test', + } as any), + ).toThrow('Credential subject must have a type.'); }); + it('should throw if wrong type', () => { expect(() => - _checkCredentialSubjectForStatusList2021Credential({ type: 'test' } as any), - ).toThrowErrorMatchingInlineSnapshot( - `[Error: Invalid type for credentialSubject: Credential subject for StatusList2021Credential must have type "StatusList2021".]`, + testFunction({ + type: wrongType, + statusPurpose: 'revocation', + encodedList: 'test', + } as any), + ).toThrow( + `Invalid type for credentialSubject: Credential subject for ${credentialType} must have type "${expectedType}".`, ); }); it('should throw if no statusPurpose', () => { expect(() => - _checkCredentialSubjectForStatusList2021Credential({ type: 'StatusList2021' } as any), - ).toThrowErrorMatchingInlineSnapshot( - `[Error: Credential subject must have a statusPurpose.]`, - ); + testFunction({ + type: expectedType, + encodedList: 'test', + } as any), + ).toThrow('Credential subject must have a statusPurpose.'); }); - it('should throw if wrong statusPurpose', () => { + + it('should throw if invalid statusPurpose', () => { expect(() => - _checkCredentialSubjectForStatusList2021Credential({ - type: 'StatusList2021', + testFunction({ + type: expectedType, + encodedList: 'test', statusPurpose: 'test', } as any), - ).toThrowErrorMatchingInlineSnapshot( - `[Error: Unsupported statusPurpose: statusPurpose must be "revocation" or "suspension".]`, - ); + ).toThrow('Unsupported statusPurpose: statusPurpose must be "revocation" or "suspension".'); }); it('should throw if no encodedList', () => { expect(() => - _checkCredentialSubjectForStatusList2021Credential({ - type: 'StatusList2021', + testFunction({ + type: expectedType, statusPurpose: 'revocation', } as any), - ).toThrowErrorMatchingInlineSnapshot(`[Error: Credential subject must have an encodedList.]`); + ).toThrow('Credential subject must have an encodedList.'); }); + it('should throw if empty encodedList', () => { expect(() => - _checkCredentialSubjectForStatusList2021Credential({ - type: 'StatusList2021', + testFunction({ + type: expectedType, statusPurpose: 'revocation', encodedList: '', } as any), - ).toThrowErrorMatchingInlineSnapshot( - `[Error: Credential subject must have a non-empty encodedList.]`, - ); + ).toThrow('Credential subject must have a non-empty encodedList.'); + }); + + it('should not throw for valid credential subject with revocation', () => { + expect(() => + testFunction({ + type: expectedType, + statusPurpose: 'revocation', + encodedList: 'H4sIAAAAAAAAA-3BMQEAAADCoPVPbQwfoAAAAAAAAAAAAAAAAAAAAIC3AYbSVKsAQAAA', + }), + ).not.toThrow(); + }); + + it('should not throw for valid credential subject with suspension', () => { + expect(() => + testFunction({ + type: expectedType, + statusPurpose: 'suspension', + encodedList: 'H4sIAAAAAAAAA-3BMQEAAADCoPVPbQwfoAAAAAAAAAAAAAAAAAAAAIC3AYbSVKsAQAAA', + }), + ).not.toThrow(); }); }); }); diff --git a/packages/w3c-credential-status/src/lib/BitstringStatusList/assertions.ts b/packages/w3c-credential-status/src/lib/BitstringStatusList/assertions.ts index 269fae6d..b1c8e26e 100644 --- a/packages/w3c-credential-status/src/lib/BitstringStatusList/assertions.ts +++ b/packages/w3c-credential-status/src/lib/BitstringStatusList/assertions.ts @@ -76,12 +76,16 @@ export const assertStatusListIndexWithinRange = ( }; /** - * Check if the credential subject is valid for a StatusList2021Credential. + * Check if the credential subject is valid for the given credential type. * @param credentialSubject - The credential subject to be signed. + * @param expectedType - The expected credential subject type. + * @param credentialType - The credential type for error messages. * @throws {Error} - Throws an error if the credential subject is invalid. */ -export function _checkCredentialSubjectForStatusList2021Credential( +export function _checkCredentialSubjectForStatusListCredential( credentialSubject: VCBitstringCredentialSubject, + expectedType: 'StatusList2021' | 'BitstringStatusList', + credentialType: 'StatusList2021Credential' | 'BitstringStatusListCredential', ): void { // Check if credentialSubject is an object if (!credentialSubject) { @@ -93,9 +97,9 @@ export function _checkCredentialSubjectForStatusList2021Credential( throw new Error('Credential subject must have a type.'); } // Check if credentialSubject has the correct type - if (credentialSubject.type !== 'StatusList2021') { + if (credentialSubject.type !== expectedType) { throw new Error( - 'Invalid type for credentialSubject: Credential subject for StatusList2021Credential must have type "StatusList2021".', + `Invalid type for credentialSubject: Credential subject for ${credentialType} must have type "${expectedType}".`, ); } @@ -114,3 +118,33 @@ export function _checkCredentialSubjectForStatusList2021Credential( throw new Error('Credential subject must have a non-empty encodedList.'); } } + +/** + * Check if the credential subject is valid for a StatusList2021Credential. + * @param credentialSubject - The credential subject to be signed. + * @throws {Error} - Throws an error if the credential subject is invalid. + */ +export function _checkCredentialSubjectForStatusList2021Credential( + credentialSubject: VCBitstringCredentialSubject, +): void { + _checkCredentialSubjectForStatusListCredential( + credentialSubject, + 'StatusList2021', + 'StatusList2021Credential', + ); +} + +/** + * Check if the credential subject is valid for a BitstringStatusListCredential. + * @param credentialSubject - The credential subject to be signed. + * @throws {Error} - Throws an error if the credential subject is invalid. + */ +export function _checkCredentialSubjectForBitstringStatusListCredential( + credentialSubject: VCBitstringCredentialSubject, +): void { + _checkCredentialSubjectForStatusListCredential( + credentialSubject, + 'BitstringStatusList', + 'BitstringStatusListCredential', + ); +} diff --git a/packages/w3c-credential-status/src/lib/index.test.ts b/packages/w3c-credential-status/src/lib/index.test.ts index 091bba80..846f8088 100644 --- a/packages/w3c-credential-status/src/lib/index.test.ts +++ b/packages/w3c-credential-status/src/lib/index.test.ts @@ -1,10 +1,14 @@ -import { PrivateKeyPair, VerificationType } from '@trustvc/w3c-issuer'; +import { + BBSPrivateKeyPair, + EcdsaSd2023PrivateKeyPair, + VerificationType, +} from '@trustvc/w3c-issuer'; import { describe, expect, it } from 'vitest'; import { createCredentialStatusPayload } from './index'; -const PRIVATE_KEY_PAIR: PrivateKeyPair = { +const BLS_KEY_PAIR: BBSPrivateKeyPair = { id: 'did:web:trustvc.github.io:did:1#keys-1', - type: 'Bls12381G2Key2020' as VerificationType, + type: VerificationType.Bls12381G2Key2020, controller: 'did:web:trustvc.github.io:did:1', seedBase58: 'GWP69tmSWJjqC1RoJ27FehcVqkVyeYAz6h5ABwoNSNdS', privateKeyBase58: '4LDU56PUhA9ZEutnR1qCWQnUhtLtpLu2EHSq4h1o7vtF', @@ -12,9 +16,18 @@ const PRIVATE_KEY_PAIR: PrivateKeyPair = { 'oRfEeWFresvhRtXCkihZbxyoi2JER7gHTJ5psXhHsdCoU1MttRMi3Yp9b9fpjmKh7bMgfWKLESiK2YovRd8KGzJsGuamoAXfqDDVhckxuc9nmsJ84skCSTijKeU4pfAcxeJ', }; +const ECDSA_SD_KEY_PAIR: EcdsaSd2023PrivateKeyPair = { + '@context': 'https://w3id.org/security/multikey/v1', + id: 'did:web:trustvc.github.io:did:1#multikey-1', + type: VerificationType.Multikey, + controller: 'did:web:trustvc.github.io:did:1', + publicKeyMultibase: 'zDnaemDNwi4G5eTzGfRooFFu5Kns3be6yfyVNtiaMhWkZbwtc', + secretKeyMultibase: 'z42tmUXTVn3n9BihE6NhdMpvVBTnFTgmb6fw18o5Ud6puhRW', +}; + describe('w3c-credential-status', () => { describe('createCredentialStatusVC', () => { - it('should create a credential status VC successfully', async () => { + it('should create a credential status VC successfully with BLS cryptosuite', async () => { const credentialStatusPayload = await createCredentialStatusPayload( { id: 'https://example.com/credentials/3732', @@ -25,7 +38,7 @@ describe('w3c-credential-status', () => { encodedList: 'encodedList', }, }, - PRIVATE_KEY_PAIR, + BLS_KEY_PAIR, ); expect(credentialStatusPayload).toMatchObject({ @@ -47,13 +60,84 @@ describe('w3c-credential-status', () => { }); }); + it('should create a credential status VC with ECDSA-SD-2023 and v1.1 context', async () => { + const credentialStatusPayload = await createCredentialStatusPayload( + { + id: 'https://example.com/credentials/3732', + credentialSubject: { + type: 'StatusList2021', + id: 'https://example.com/credentials/status/3#list', + statusPurpose: 'revocation', + encodedList: 'encodedList', + }, + }, + ECDSA_SD_KEY_PAIR, + 'StatusList2021Credential', + 'ecdsa-sd-2023', + ); + + expect(credentialStatusPayload).toMatchObject({ + '@context': [ + 'https://www.w3.org/2018/credentials/v1', + 'https://w3id.org/security/data-integrity/v2', + 'https://w3id.org/vc/status-list/2021/v1', + ], + credentialSubject: { + encodedList: 'encodedList', + id: 'https://example.com/credentials/status/3#list', + statusPurpose: 'revocation', + type: 'StatusList2021', + }, + issuanceDate: expect.any(String), + issuer: 'did:web:trustvc.github.io:did:1', + type: ['VerifiableCredential', 'StatusList2021Credential'], + validFrom: expect.any(String), + }); + }); + + it('should create a credential status VC with ECDSA-SD-2023 and v2.0 context', async () => { + const credentialStatusPayload = await createCredentialStatusPayload( + { + id: 'https://example.com/credentials/3732', + credentialSubject: { + type: 'BitstringStatusList', + id: 'https://example.com/credentials/status/3#list', + statusPurpose: 'revocation', + encodedList: 'encodedList', + }, + }, + ECDSA_SD_KEY_PAIR, + 'BitstringStatusListCredential', + 'ecdsa-sd-2023', + ); + + expect(credentialStatusPayload).toMatchObject({ + '@context': [ + 'https://www.w3.org/ns/credentials/v2', + 'https://w3id.org/security/data-integrity/v2', + ], + credentialSubject: { + encodedList: 'encodedList', + id: 'https://example.com/credentials/status/3#list', + statusPurpose: 'revocation', + type: 'BitstringStatusList', + }, + issuer: 'did:web:trustvc.github.io:did:1', + type: ['VerifiableCredential', 'BitstringStatusListCredential'], + validFrom: expect.any(String), + }); + + // Explicitly verify that issuanceDate is not present in v2.0 + expect(credentialStatusPayload).not.toHaveProperty('issuanceDate'); + }); + it('should return an error if type is not supported', async () => { expect( createCredentialStatusPayload( { id: 'https://example.com/credentials/3732', } as any, - PRIVATE_KEY_PAIR, + BLS_KEY_PAIR, 'unsupported' as any, ), ).rejects.toThrowError('Unsupported type: unsupported'); diff --git a/packages/w3c-credential-status/src/lib/index.ts b/packages/w3c-credential-status/src/lib/index.ts index f93556f0..eb8af9d2 100644 --- a/packages/w3c-credential-status/src/lib/index.ts +++ b/packages/w3c-credential-status/src/lib/index.ts @@ -1,16 +1,21 @@ import { BBS_V1_URL, CredentialContextVersion, + DATA_INTEGRITY_V2_URL, STATUS_LIST_2021_CREDENTIAL_URL, } from '@trustvc/w3c-context'; import { PrivateKeyPair } from '@trustvc/w3c-issuer'; -import { _checkCredentialSubjectForStatusList2021Credential } from './BitstringStatusList/assertions'; +import { + _checkCredentialSubjectForStatusList2021Credential, + _checkCredentialSubjectForBitstringStatusListCredential, +} from './BitstringStatusList/assertions'; import { VCBitstringCredentialSubjectType, VCCredentialStatusType, } from './BitstringStatusList/types'; import { CreateVCCredentialStatusOptions, + CryptoSuiteName, GeneralCredentialStatus, RawCredentialStatusVC, } from './types'; @@ -34,14 +39,14 @@ export const VCCredentialStatusTypeToVCCredentialSubjectType: Record< * @param {object} options.credentialSubject - The credential subject. * @param {PrivateKeyPair} keyPair - The key pair options for signing. * @param {VCCredentialStatusType} type - The type of the credential status VC. Defaults to 'StatusList2021Credential'. - * @param {string} cryptoSuite - The cryptosuite to be used for signing. Defaults to 'BbsBlsSignature2020'. + * @param {CryptoSuiteName} cryptoSuite - The cryptosuite to be used for signing. Defaults to 'BbsBlsSignature2020'. * @returns {Promise} */ export const createCredentialStatusPayload = async ( options: CreateVCCredentialStatusOptions, keyPair: PrivateKeyPair, type: VCCredentialStatusType = 'StatusList2021Credential', - cryptoSuite = 'BbsBlsSignature2020', + cryptoSuite: CryptoSuiteName = 'BbsBlsSignature2020', ): Promise => { try { const { id, credentialSubject } = options; @@ -50,6 +55,9 @@ export const createCredentialStatusPayload = async ( case 'StatusList2021Credential': _checkCredentialSubjectForStatusList2021Credential(credentialSubject); break; + case 'BitstringStatusListCredential': + _checkCredentialSubjectForBitstringStatusListCredential(credentialSubject); + break; default: throw new Error(`Unsupported type: ${type}`); } @@ -58,12 +66,18 @@ export const createCredentialStatusPayload = async ( credentialSubject.id = `${id}#list`; } - const context = [CredentialContextVersion.v1]; + // Determine version based on credential type + const isV2 = type === 'BitstringStatusListCredential'; + const context = [isV2 ? CredentialContextVersion.v2 : CredentialContextVersion.v1]; + // Add cryptosuite-specific contexts if (cryptoSuite === 'BbsBlsSignature2020') { context.push(BBS_V1_URL); + } else { + context.push(DATA_INTEGRITY_V2_URL); } + // Add status list context only for v1.1 (v2.0 has it built-in) if (type === 'StatusList2021Credential') { context.push(STATUS_LIST_2021_CREDENTIAL_URL); } @@ -74,8 +88,12 @@ export const createCredentialStatusPayload = async ( '@context': context, type: ['VerifiableCredential', type], issuer: keyPair.controller, - issuanceDate: new Date().toISOString(), - validFrom, + ...(isV2 + ? { validFrom } + : { + issuanceDate: new Date().toISOString(), + validFrom, + }), credentialSubject, }; @@ -89,11 +107,13 @@ export const createCredentialStatusPayload = async ( }; /** - * Checks if the input credential status is a StatusList2021Credential. + * Checks if the input credential status is a StatusList2021Credential / BitstringStatusListCredential. * @param {GeneralCredentialStatus} credentialStatus - The credential status to be checked. - * @returns {boolean} - Returns true if the credential status is a StatusList2021Credential, false otherwise. + * @returns {boolean} - Returns true if the credential status is a StatusList2021Credential / BitstringStatusListCredential, false otherwise. */ -export const isCredentialStatusStatusList = (credentialStatus: GeneralCredentialStatus) => { +export const isCredentialStatusStatusList = ( + credentialStatus: GeneralCredentialStatus, +): boolean => { try { assertCredentialStatusStatusListType(credentialStatus?.type); return true; diff --git a/packages/w3c-credential-status/src/lib/types.ts b/packages/w3c-credential-status/src/lib/types.ts index 8e43de21..08d4df1d 100644 --- a/packages/w3c-credential-status/src/lib/types.ts +++ b/packages/w3c-credential-status/src/lib/types.ts @@ -44,7 +44,7 @@ export type RawCredentialStatusVC = { '@context': string | string[]; type: string[]; issuer: string | Record; - issuanceDate: string; + issuanceDate?: string; validFrom?: string; validUntil?: string; expirationDate?: string; @@ -60,3 +60,5 @@ export type SignedCredentialStatusVC = RawCredentialStatusVC & { proofValue: string; }; }; + +export type CryptoSuiteName = 'BbsBlsSignature2020' | 'bbs-2023' | 'ecdsa-sd-2023'; diff --git a/packages/w3c-credential-status/src/lib/utils.test.ts b/packages/w3c-credential-status/src/lib/utils.test.ts index 374e9d61..c47f90d9 100644 --- a/packages/w3c-credential-status/src/lib/utils.test.ts +++ b/packages/w3c-credential-status/src/lib/utils.test.ts @@ -89,7 +89,7 @@ describe('utils.ts', () => { it('should throw an error if the VC is not found', async () => { expect( - fetchCredentialStatusVC('https://trustvc.github.io/did/credentials/statuslist/2'), + fetchCredentialStatusVC('https://trustvc.github.io/did/credentials/statuslist/3'), ).rejects.toThrowError('Credential Status VC not found'); }); diff --git a/packages/w3c-credential-status/src/lib/utils.ts b/packages/w3c-credential-status/src/lib/utils.ts index ad8af4a3..983a0e64 100644 --- a/packages/w3c-credential-status/src/lib/utils.ts +++ b/packages/w3c-credential-status/src/lib/utils.ts @@ -20,7 +20,11 @@ import { * @throws {Error} - Throws an error if the type is not supported. */ export const assertCredentialStatusType = (type: T): void => { - const supportedTypes: T[] = ['StatusList2021Entry', 'TransferableRecords'] as T[]; + const supportedTypes: T[] = [ + 'StatusList2021Entry', + 'BitstringStatusListEntry', + 'TransferableRecords', + ] as T[]; if (!supportedTypes.includes(type)) { throw new Error(`Unsupported type: ${type}`); @@ -33,7 +37,7 @@ export const assertCredentialStatusType = (type: T): void => { * @throws {Error} - Throws an error if the type is not supported. */ export const assertCredentialStatusStatusListType = (type: T): void => { - const supportedTypes: T[] = ['StatusList2021Entry'] as T[]; + const supportedTypes: T[] = ['StatusList2021Entry', 'BitstringStatusListEntry'] as T[]; if (!supportedTypes.includes(type)) { throw new Error(`Unsupported type: ${type}`); @@ -75,6 +79,9 @@ export const assertCredentialStatus = (credentialStatus: GeneralCredentialStatus case 'StatusList2021Entry': assertStatusList2021Entry(credentialStatus as BitstringStatusListCredentialStatus); break; + case 'BitstringStatusListEntry': + assertBitstringStatusListEntry(credentialStatus as BitstringStatusListCredentialStatus); + break; default: throw new Error(`Unsupported type: ${credentialStatus.type}`); } @@ -103,7 +110,7 @@ export function _validateUriId({ id, propertyName }: { id: string; propertyName: } } -export const assertStatusList2021Entry = ( +const _assertStatusListCredentialStatus = ( credentialStatus: BitstringStatusListCredentialStatus, ): void => { const { type, statusPurpose, statusListIndex, statusListCredential } = credentialStatus; @@ -116,6 +123,9 @@ export const assertStatusList2021Entry = ( }); }; +export const assertStatusList2021Entry = _assertStatusListCredentialStatus; +export const assertBitstringStatusListEntry = _assertStatusListCredentialStatus; + export const assertTransferableRecords = ( credentialStatus: TransferableRecordsCredentialStatus, mode: 'sign' | 'verify' = 'verify', diff --git a/packages/w3c-vc/package.json b/packages/w3c-vc/package.json index 43d8d763..bf28205c 100644 --- a/packages/w3c-vc/package.json +++ b/packages/w3c-vc/package.json @@ -37,6 +37,7 @@ "@mattrglobal/jsonld-signatures-bbs": "^1.2.0", "@trustvc/w3c-credential-status": "^1.3.0-alpha.5", "@trustvc/w3c-issuer": "^1.3.0-alpha.3", + "cbor": "^9.0.2", "did-resolver": "^4.1.0", "jsonld": "^6.0.0", "jsonld-signatures": "^11.5.0", diff --git a/packages/w3c-vc/src/lib/helper/index.ts b/packages/w3c-vc/src/lib/helper/index.ts index 7b990466..ee36ed8a 100644 --- a/packages/w3c-vc/src/lib/helper/index.ts +++ b/packages/w3c-vc/src/lib/helper/index.ts @@ -1,5 +1,6 @@ import { CredentialContextVersion } from '@trustvc/w3c-context'; import { + assertBitstringStatusListEntry, assertCredentialStatusType, assertStatusList2021Entry, assertTransferableRecords, @@ -289,8 +290,12 @@ export function _checkCredential( throw new Error('"proof" property is already there.'); } - // The "id" is generated programmatically later on - if (credential.id) { + // The "id" is generated programmatically later on, except for status list credentials which require it + const isStatusListCredential = credential.type?.some( + (type: string) => + type === 'BitstringStatusListCredential' || type === 'StatusList2021Credential', + ); + if (credential.id && !isStatusListCredential) { throw new Error('"id" is a defined field and should not be set by the user.'); } } @@ -448,6 +453,8 @@ export const _checkCredentialStatus = ( if (type === 'StatusList2021Entry') { assertStatusList2021Entry(credentialStatus as BitstringStatusListCredentialStatus); + } else if (type === 'BitstringStatusListEntry') { + assertBitstringStatusListEntry(credentialStatus as BitstringStatusListCredentialStatus); } else if (type === 'TransferableRecords') { assertTransferableRecords(credentialStatus as TransferableRecordsCredentialStatus, mode); } else { @@ -468,12 +475,21 @@ export const prefilCredentialId = ( credential: RawVerifiableCredential, cryptoSuite?: string, ): RawVerifiableCredential => { - // Use proper URI format for ECDSA-SD-2023 - // Use blank node format for BBS+ (maintains backward compatibility) - if (cryptoSuite === 'ecdsa-sd-2023') { - credential.id = `urn:uuid:${uuidv7()}`; + // Don't overwrite existing id for status list credentials types + const isStatusListCredential = credential.type?.some( + (type: string) => + type === 'BitstringStatusListCredential' || type === 'StatusList2021Credential', + ); + if (credential.id && isStatusListCredential) { + // Keep the existing id for status list credentials } else { - credential.id = `urn:bnid:_:${uuidv7()}`; + // Use proper URI format for ECDSA-SD-2023 + // Use blank node format for BBS+ (maintains backward compatibility) + if (cryptoSuite === 'ecdsa-sd-2023') { + credential.id = `urn:uuid:${uuidv7()}`; + } else { + credential.id = `urn:bnid:_:${uuidv7()}`; + } } if (credential?.credentialStatus?.type === 'TransferableRecords') { diff --git a/packages/w3c-vc/src/lib/types.ts b/packages/w3c-vc/src/lib/types.ts index 9945838e..0fcf798b 100644 --- a/packages/w3c-vc/src/lib/types.ts +++ b/packages/w3c-vc/src/lib/types.ts @@ -44,7 +44,7 @@ export type SignedVerifiableCredential = { id: string; type: string | string[]; issuer: string | Record; - issuanceDate: string; + issuanceDate?: string; validFrom?: string; validUntil?: string; expirationDate?: string; diff --git a/packages/w3c-vc/src/lib/verify/credentialStatus/index.test.ts b/packages/w3c-vc/src/lib/verify/credentialStatus/index.test.ts index 5fb565b2..64a50704 100644 --- a/packages/w3c-vc/src/lib/verify/credentialStatus/index.test.ts +++ b/packages/w3c-vc/src/lib/verify/credentialStatus/index.test.ts @@ -1,12 +1,12 @@ import * as w3c_credential_status from '@trustvc/w3c-credential-status'; import { CredentialStatusPurpose, CredentialStatusType } from '@trustvc/w3c-credential-status'; -import { describe, expect, it, vi } from 'vitest'; +import { describe, expect, it, vi, afterEach } from 'vitest'; import { SignedVerifiableCredential } from '../../types'; import * as w3c_vc from './../../w3c-vc'; import { verifyCredentialStatus } from './index'; // First 10 (index 0 - 9) position is marked as True. -const credentialStatusVC: SignedVerifiableCredential = { +const credentialStatusVC_BBS_V1: SignedVerifiableCredential = { '@context': [ 'https://www.w3.org/2018/credentials/v1', 'https://w3id.org/security/bbs/v1', @@ -33,7 +33,7 @@ const credentialStatusVC: SignedVerifiableCredential = { }, }; -const credentialStatusVC_withInvalidEncodedList = { +const credentialStatusVC_withInvalidEncodedList: SignedVerifiableCredential = { '@context': [ 'https://www.w3.org/2018/credentials/v1', 'https://w3id.org/security/bbs/v1', @@ -68,10 +68,22 @@ const credentialStatus = { statusListCredential: 'https://trustvc.github.io/did/credentials/statuslist/1', }; +const credentialStatus2 = { + id: 'https://trustvc.github.io/did/credentials/statuslist/2#1', + type: 'BitstringStatusListEntry' as CredentialStatusType, + statusPurpose: 'revocation' as CredentialStatusPurpose, + statusListIndex: '5', + statusListCredential: 'https://trustvc.github.io/did/credentials/statuslist/2', +}; + +afterEach(() => { + vi.restoreAllMocks(); +}); + describe('verifyCredentialStatus', () => { it('should verify a credential status successfully', async () => { vi.spyOn(w3c_credential_status, 'fetchCredentialStatusVC').mockResolvedValue( - credentialStatusVC, + credentialStatusVC_BBS_V1, ); vi.spyOn(w3c_vc, 'verifyCredential').mockResolvedValue({ verified: true }); @@ -95,7 +107,7 @@ describe('verifyCredentialStatus', () => { it('should return an error if the credential is not verified', async () => { vi.spyOn(w3c_credential_status, 'fetchCredentialStatusVC').mockResolvedValue( - credentialStatusVC, + credentialStatusVC_BBS_V1, ); vi.spyOn(w3c_vc, 'verifyCredential').mockResolvedValue({ verified: false }); @@ -117,7 +129,7 @@ describe('verifyCredentialStatus', () => { it('should return an error if statusPurpose does not match the statusPurpose in the VC', async () => { vi.spyOn(w3c_credential_status, 'fetchCredentialStatusVC').mockResolvedValue( - credentialStatusVC, + credentialStatusVC_BBS_V1, ); vi.spyOn(w3c_vc, 'verifyCredential').mockResolvedValue({ verified: true }); @@ -161,7 +173,7 @@ describe('verifyCredentialStatus', () => { it('should return an error if statusListIndex is out of range', async () => { vi.spyOn(w3c_credential_status, 'fetchCredentialStatusVC').mockResolvedValue( - credentialStatusVC, + credentialStatusVC_BBS_V1, ); vi.spyOn(w3c_vc, 'verifyCredential').mockResolvedValue({ verified: true }); @@ -172,4 +184,17 @@ describe('verifyCredentialStatus', () => { expect(error).toBe('Invalid statusListIndex: Index out of range: min=0, max=131071'); }); + + it('should verify a credential status successfully with ECDSA-SD-2023 and v2.0 context', async () => { + const { status } = await verifyCredentialStatus(credentialStatus2); + expect(status).toBe(true); + + // Test with different index to verify it returns false + const { status: status2, purpose } = await verifyCredentialStatus({ + ...credentialStatus2, + statusListIndex: '10', + }); + expect(status2).toBe(false); + expect(purpose).toBe('revocation'); + }); }); diff --git a/packages/w3c-vc/src/lib/w3c-vc.ts b/packages/w3c-vc/src/lib/w3c-vc.ts index f3c6f39d..07dcc13a 100644 --- a/packages/w3c-vc/src/lib/w3c-vc.ts +++ b/packages/w3c-vc/src/lib/w3c-vc.ts @@ -124,6 +124,36 @@ const isEcdsaSdBaseProof = (proofValue: string): boolean => { } }; +/** + * Extracts mandatory pointers from an ECDSA-SD-2023 base proof value + * @param {string} proofValue - The base proof value string + * @returns {Promise} - Array of mandatory pointers, empty array if extraction fails + */ +const extractMandatoryPointers = async (proofValue: string): Promise => { + try { + if (!isEcdsaSdBaseProof(proofValue)) { + return []; + } + + // Decode the base64url-no-pad-encoded value + const decodedProofValue = Buffer.from(proofValue.slice(1), 'base64url'); + + // CBOR decode the components after the 3-byte header + const cbor = await import('cbor'); + const components = cbor.decode(decodedProofValue.slice(3)); + + // Components array: [baseSignature, publicKey, hmacKey, signatures, mandatoryPointers] + if (Array.isArray(components) && components.length === 5) { + return components[4] || []; + } + + return []; + } catch (error) { + // If we can't parse the mandatory pointers, return empty array + return []; + } +}; + /** * Signs a credential using the specified cryptosuite. Defaults to 'BbsBlsSignature2020'. * @param {object} credential - The credential to be signed. @@ -370,15 +400,21 @@ export const deriveCredential = async ( const selectivePointers = revealedAttributes; - // Ensure credentialSubject is included if no credentialSubject properties are selected - // This maintains credential validity while allowing selective disclosure within credentialSubject - const hasCredentialSubjectPointers = selectivePointers.some((pointer) => + // Extract mandatory pointers from the base proof + const mandatoryPointers = await extractMandatoryPointers(proof.proofValue as string); + + // Check if credentialSubject is already in mandatory pointers or selective pointers + const hasCredentialSubjectInMandatory = mandatoryPointers.some((pointer) => + pointer.startsWith('/credentialSubject'), + ); + const hasCredentialSubjectInSelective = selectivePointers.some((pointer) => pointer.startsWith('/credentialSubject'), ); let finalSelectivePointers = selectivePointers; - if (!hasCredentialSubjectPointers) { - // If no credentialSubject properties are selected, include the entire credentialSubject + if (!hasCredentialSubjectInMandatory && !hasCredentialSubjectInSelective) { + // Only add /credentialSubject if it's not already in mandatory pointers + // and no credentialSubject properties are selected // This ensures the derived credential remains valid per W3C VC specification finalSelectivePointers = [...selectivePointers, '/credentialSubject']; } From 569512acabcbd58a67ca21b9117e3e8e62076684 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Tue, 19 Aug 2025 03:29:24 +0000 Subject: [PATCH 055/122] chore(release): @trustvc/w3c-issuer@1.3.0-alpha.4 [skip ci] # [1.3.0-alpha.4](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-issuer@1.3.0-alpha.3...@trustvc/w3c-issuer@1.3.0-alpha.4) (2025-08-19) ### Features * add support for w3c data model 2.0 with bitstring status list and ecdsa ([#75](https://github.com/TrustVC/w3c/issues/75)) ([7fe399e](https://github.com/TrustVC/w3c/commit/7fe399e7b58910912cce4920bab177732791538b)) --- packages/w3c-issuer/CHANGELOG.md | 7 +++++++ packages/w3c-issuer/package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/w3c-issuer/CHANGELOG.md b/packages/w3c-issuer/CHANGELOG.md index f8333f31..18211665 100644 --- a/packages/w3c-issuer/CHANGELOG.md +++ b/packages/w3c-issuer/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.4](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-issuer@1.3.0-alpha.3...@trustvc/w3c-issuer@1.3.0-alpha.4) (2025-08-19) + + +### Features + +* add support for w3c data model 2.0 with bitstring status list and ecdsa ([#75](https://github.com/TrustVC/w3c/issues/75)) ([7fe399e](https://github.com/TrustVC/w3c/commit/7fe399e7b58910912cce4920bab177732791538b)) + # [1.3.0-alpha.3](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-issuer@1.3.0-alpha.2...@trustvc/w3c-issuer@1.3.0-alpha.3) (2025-08-13) diff --git a/packages/w3c-issuer/package.json b/packages/w3c-issuer/package.json index 5fe9a02a..d0856318 100644 --- a/packages/w3c-issuer/package.json +++ b/packages/w3c-issuer/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c-issuer", - "version": "1.3.0-alpha.3", + "version": "1.3.0-alpha.4", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", From 401869c93ab4c19fdb3d349efa887c4b3735f2e5 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Tue, 19 Aug 2025 03:29:58 +0000 Subject: [PATCH 056/122] chore(release): @trustvc/w3c-context@1.3.0-alpha.6 [skip ci] # [1.3.0-alpha.6](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-context@1.3.0-alpha.5...@trustvc/w3c-context@1.3.0-alpha.6) (2025-08-19) ### Features * add support for w3c data model 2.0 with bitstring status list and ecdsa ([#75](https://github.com/TrustVC/w3c/issues/75)) ([7fe399e](https://github.com/TrustVC/w3c/commit/7fe399e7b58910912cce4920bab177732791538b)) --- packages/w3c-context/CHANGELOG.md | 7 +++++++ packages/w3c-context/package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/w3c-context/CHANGELOG.md b/packages/w3c-context/CHANGELOG.md index db1e2cba..7af20508 100644 --- a/packages/w3c-context/CHANGELOG.md +++ b/packages/w3c-context/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.6](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-context@1.3.0-alpha.5...@trustvc/w3c-context@1.3.0-alpha.6) (2025-08-19) + + +### Features + +* add support for w3c data model 2.0 with bitstring status list and ecdsa ([#75](https://github.com/TrustVC/w3c/issues/75)) ([7fe399e](https://github.com/TrustVC/w3c/commit/7fe399e7b58910912cce4920bab177732791538b)) + # [1.3.0-alpha.5](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-context@1.3.0-alpha.4...@trustvc/w3c-context@1.3.0-alpha.5) (2025-08-18) diff --git a/packages/w3c-context/package.json b/packages/w3c-context/package.json index 8e3f4c45..177069ce 100644 --- a/packages/w3c-context/package.json +++ b/packages/w3c-context/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c-context", - "version": "1.3.0-alpha.5", + "version": "1.3.0-alpha.6", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", From 6cc25344feb918b746da899538174e4087651fea Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Tue, 19 Aug 2025 03:30:30 +0000 Subject: [PATCH 057/122] chore(release): @trustvc/w3c-credential-status@1.3.0-alpha.6 [skip ci] # [1.3.0-alpha.6](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-credential-status@1.3.0-alpha.5...@trustvc/w3c-credential-status@1.3.0-alpha.6) (2025-08-19) ### Features * add support for w3c data model 2.0 with bitstring status list and ecdsa ([#75](https://github.com/TrustVC/w3c/issues/75)) ([7fe399e](https://github.com/TrustVC/w3c/commit/7fe399e7b58910912cce4920bab177732791538b)) --- packages/w3c-credential-status/CHANGELOG.md | 7 +++++++ packages/w3c-credential-status/package.json | 6 +++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/packages/w3c-credential-status/CHANGELOG.md b/packages/w3c-credential-status/CHANGELOG.md index 23f29c92..174c6f48 100644 --- a/packages/w3c-credential-status/CHANGELOG.md +++ b/packages/w3c-credential-status/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.6](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-credential-status@1.3.0-alpha.5...@trustvc/w3c-credential-status@1.3.0-alpha.6) (2025-08-19) + + +### Features + +* add support for w3c data model 2.0 with bitstring status list and ecdsa ([#75](https://github.com/TrustVC/w3c/issues/75)) ([7fe399e](https://github.com/TrustVC/w3c/commit/7fe399e7b58910912cce4920bab177732791538b)) + # [1.3.0-alpha.5](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-credential-status@1.3.0-alpha.4...@trustvc/w3c-credential-status@1.3.0-alpha.5) (2025-08-18) diff --git a/packages/w3c-credential-status/package.json b/packages/w3c-credential-status/package.json index 2f86b809..b5fb5c24 100644 --- a/packages/w3c-credential-status/package.json +++ b/packages/w3c-credential-status/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c-credential-status", - "version": "1.3.0-alpha.5", + "version": "1.3.0-alpha.6", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", @@ -29,8 +29,8 @@ } }, "dependencies": { - "@trustvc/w3c-context": "^1.3.0-alpha.5", - "@trustvc/w3c-issuer": "^1.3.0-alpha.3", + "@trustvc/w3c-context": "^1.3.0-alpha.6", + "@trustvc/w3c-issuer": "^1.3.0-alpha.4", "base64url-universal": "^2.0.0", "pako": "^2.1.0" }, From f46ca3fcd13974552c7e09adceb10467a2583fe8 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Tue, 19 Aug 2025 03:31:03 +0000 Subject: [PATCH 058/122] chore(release): @trustvc/w3c-vc@1.3.0-alpha.6 [skip ci] # [1.3.0-alpha.6](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.3.0-alpha.5...@trustvc/w3c-vc@1.3.0-alpha.6) (2025-08-19) ### Features * add support for w3c data model 2.0 with bitstring status list and ecdsa ([#75](https://github.com/TrustVC/w3c/issues/75)) ([7fe399e](https://github.com/TrustVC/w3c/commit/7fe399e7b58910912cce4920bab177732791538b)) --- packages/w3c-vc/CHANGELOG.md | 7 +++++++ packages/w3c-vc/package.json | 6 +++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/packages/w3c-vc/CHANGELOG.md b/packages/w3c-vc/CHANGELOG.md index 29ad20c9..e2835b4b 100644 --- a/packages/w3c-vc/CHANGELOG.md +++ b/packages/w3c-vc/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.6](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.3.0-alpha.5...@trustvc/w3c-vc@1.3.0-alpha.6) (2025-08-19) + + +### Features + +* add support for w3c data model 2.0 with bitstring status list and ecdsa ([#75](https://github.com/TrustVC/w3c/issues/75)) ([7fe399e](https://github.com/TrustVC/w3c/commit/7fe399e7b58910912cce4920bab177732791538b)) + # [1.3.0-alpha.5](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.3.0-alpha.4...@trustvc/w3c-vc@1.3.0-alpha.5) (2025-08-18) diff --git a/packages/w3c-vc/package.json b/packages/w3c-vc/package.json index bf28205c..174d0297 100644 --- a/packages/w3c-vc/package.json +++ b/packages/w3c-vc/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c-vc", - "version": "1.3.0-alpha.5", + "version": "1.3.0-alpha.6", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", @@ -35,8 +35,8 @@ "@digitalbazaar/ecdsa-multikey": "^1.8.0", "@digitalbazaar/ecdsa-sd-2023-cryptosuite": "^3.4.1", "@mattrglobal/jsonld-signatures-bbs": "^1.2.0", - "@trustvc/w3c-credential-status": "^1.3.0-alpha.5", - "@trustvc/w3c-issuer": "^1.3.0-alpha.3", + "@trustvc/w3c-credential-status": "^1.3.0-alpha.6", + "@trustvc/w3c-issuer": "^1.3.0-alpha.4", "cbor": "^9.0.2", "did-resolver": "^4.1.0", "jsonld": "^6.0.0", From 13daa8b48bba9d347b0a47b34a03f08f1bac6acc Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Tue, 19 Aug 2025 03:31:33 +0000 Subject: [PATCH 059/122] chore(release): @trustvc/w3c-cli@1.3.0-alpha.6 [skip ci] # [1.3.0-alpha.6](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-cli@1.3.0-alpha.5...@trustvc/w3c-cli@1.3.0-alpha.6) (2025-08-19) ### Features * add support for w3c data model 2.0 with bitstring status list and ecdsa ([#75](https://github.com/TrustVC/w3c/issues/75)) ([7fe399e](https://github.com/TrustVC/w3c/commit/7fe399e7b58910912cce4920bab177732791538b)) --- apps/w3c-cli/CHANGELOG.md | 7 +++++++ apps/w3c-cli/package.json | 10 +++++----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/apps/w3c-cli/CHANGELOG.md b/apps/w3c-cli/CHANGELOG.md index 4b7c2192..8b5efbf0 100644 --- a/apps/w3c-cli/CHANGELOG.md +++ b/apps/w3c-cli/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.6](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-cli@1.3.0-alpha.5...@trustvc/w3c-cli@1.3.0-alpha.6) (2025-08-19) + + +### Features + +* add support for w3c data model 2.0 with bitstring status list and ecdsa ([#75](https://github.com/TrustVC/w3c/issues/75)) ([7fe399e](https://github.com/TrustVC/w3c/commit/7fe399e7b58910912cce4920bab177732791538b)) + # [1.3.0-alpha.5](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-cli@1.3.0-alpha.4...@trustvc/w3c-cli@1.3.0-alpha.5) (2025-08-18) diff --git a/apps/w3c-cli/package.json b/apps/w3c-cli/package.json index 6c0b5be5..75bced71 100644 --- a/apps/w3c-cli/package.json +++ b/apps/w3c-cli/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c-cli", - "version": "1.3.0-alpha.5", + "version": "1.3.0-alpha.6", "description": "CLI for TrustVC W3C", "main": "dist/main.js", "types": "dist/main.d.ts", @@ -34,10 +34,10 @@ }, "dependencies": { "@inquirer/prompts": "^5.3.8", - "@trustvc/w3c-context": "^1.3.0-alpha.5", - "@trustvc/w3c-credential-status": "^1.3.0-alpha.5", - "@trustvc/w3c-vc": "^1.3.0-alpha.5", - "@trustvc/w3c-issuer": "^1.3.0-alpha.3", + "@trustvc/w3c-context": "^1.3.0-alpha.6", + "@trustvc/w3c-credential-status": "^1.3.0-alpha.6", + "@trustvc/w3c-vc": "^1.3.0-alpha.6", + "@trustvc/w3c-issuer": "^1.3.0-alpha.4", "@types/yargs": "^17.0.32", "chalk": "^4.1.2", "inquirer": "^10.0.1", From 3c0b2fa1979984c6574e409856b936b95a0d9547 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Tue, 19 Aug 2025 03:32:03 +0000 Subject: [PATCH 060/122] chore(release): @trustvc/w3c@1.3.0-alpha.6 [skip ci] # [1.3.0-alpha.6](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.3.0-alpha.5...@trustvc/w3c@1.3.0-alpha.6) (2025-08-19) ### Features * add support for w3c data model 2.0 with bitstring status list and ecdsa ([#75](https://github.com/TrustVC/w3c/issues/75)) ([7fe399e](https://github.com/TrustVC/w3c/commit/7fe399e7b58910912cce4920bab177732791538b)) --- packages/w3c/CHANGELOG.md | 7 +++++++ packages/w3c/package.json | 10 +++++----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/packages/w3c/CHANGELOG.md b/packages/w3c/CHANGELOG.md index 4e861c40..944d7f29 100644 --- a/packages/w3c/CHANGELOG.md +++ b/packages/w3c/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.6](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.3.0-alpha.5...@trustvc/w3c@1.3.0-alpha.6) (2025-08-19) + + +### Features + +* add support for w3c data model 2.0 with bitstring status list and ecdsa ([#75](https://github.com/TrustVC/w3c/issues/75)) ([7fe399e](https://github.com/TrustVC/w3c/commit/7fe399e7b58910912cce4920bab177732791538b)) + # [1.3.0-alpha.5](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.3.0-alpha.4...@trustvc/w3c@1.3.0-alpha.5) (2025-08-18) diff --git a/packages/w3c/package.json b/packages/w3c/package.json index a3b9ecfe..a4dec473 100644 --- a/packages/w3c/package.json +++ b/packages/w3c/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c", - "version": "1.3.0-alpha.5", + "version": "1.3.0-alpha.6", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", @@ -32,10 +32,10 @@ } }, "dependencies": { - "@trustvc/w3c-context": "^1.3.0-alpha.5", - "@trustvc/w3c-credential-status": "^1.3.0-alpha.5", - "@trustvc/w3c-issuer": "^1.3.0-alpha.3", - "@trustvc/w3c-vc": "^1.3.0-alpha.5" + "@trustvc/w3c-context": "^1.3.0-alpha.6", + "@trustvc/w3c-credential-status": "^1.3.0-alpha.6", + "@trustvc/w3c-issuer": "^1.3.0-alpha.4", + "@trustvc/w3c-vc": "^1.3.0-alpha.6" }, "repository": { "type": "git", From 0cc8941b9dc8a8a8cac800ad76ec64cfd7e29753 Mon Sep 17 00:00:00 2001 From: RishabhS7 <59636880+RishabhS7@users.noreply.github.com> Date: Tue, 19 Aug 2025 11:23:14 +0530 Subject: [PATCH 061/122] fix: expose version detection function (#76) --- apps/w3c-cli/package.json | 2 +- packages/w3c-context/package.json | 2 +- packages/w3c-credential-status/package.json | 2 +- packages/w3c-issuer/package.json | 2 +- packages/w3c-vc/package.json | 2 +- packages/w3c-vc/src/index.ts | 8 ++++++++ packages/w3c/package.json | 2 +- 7 files changed, 14 insertions(+), 6 deletions(-) diff --git a/apps/w3c-cli/package.json b/apps/w3c-cli/package.json index 75bced71..21e11a40 100644 --- a/apps/w3c-cli/package.json +++ b/apps/w3c-cli/package.json @@ -56,4 +56,4 @@ "registry": "https://registry.npmjs.org/" }, "private": false -} +} \ No newline at end of file diff --git a/packages/w3c-context/package.json b/packages/w3c-context/package.json index 177069ce..da8e2066 100644 --- a/packages/w3c-context/package.json +++ b/packages/w3c-context/package.json @@ -49,4 +49,4 @@ "registry": "https://registry.npmjs.org/" }, "private": false -} +} \ No newline at end of file diff --git a/packages/w3c-credential-status/package.json b/packages/w3c-credential-status/package.json index b5fb5c24..eca7f823 100644 --- a/packages/w3c-credential-status/package.json +++ b/packages/w3c-credential-status/package.json @@ -47,4 +47,4 @@ "registry": "https://registry.npmjs.org/" }, "private": false -} +} \ No newline at end of file diff --git a/packages/w3c-issuer/package.json b/packages/w3c-issuer/package.json index d0856318..3f9fbfd8 100644 --- a/packages/w3c-issuer/package.json +++ b/packages/w3c-issuer/package.json @@ -50,4 +50,4 @@ "registry": "https://registry.npmjs.org/" }, "private": false -} +} \ No newline at end of file diff --git a/packages/w3c-vc/package.json b/packages/w3c-vc/package.json index 174d0297..89cd4649 100644 --- a/packages/w3c-vc/package.json +++ b/packages/w3c-vc/package.json @@ -66,4 +66,4 @@ "devDependencies": { "@types/uuid": "^10.0.0" } -} +} \ No newline at end of file diff --git a/packages/w3c-vc/src/index.ts b/packages/w3c-vc/src/index.ts index 75c05c4d..1da699d9 100644 --- a/packages/w3c-vc/src/index.ts +++ b/packages/w3c-vc/src/index.ts @@ -5,6 +5,10 @@ import { isSignedDocument, signCredential, verifyCredential, + isRawDocumentV1_1, + isRawDocumentV2_0, + isSignedDocumentV1_1, + isSignedDocumentV2_0, } from './lib/w3c-vc'; import { getDocumentLoader } from '@trustvc/w3c-context'; @@ -25,4 +29,8 @@ export { signCredential, verifyCredential, verifyCredentialStatus, + isRawDocumentV1_1, + isRawDocumentV2_0, + isSignedDocumentV1_1, + isSignedDocumentV2_0, }; diff --git a/packages/w3c/package.json b/packages/w3c/package.json index a4dec473..b47cf051 100644 --- a/packages/w3c/package.json +++ b/packages/w3c/package.json @@ -50,4 +50,4 @@ "registry": "https://registry.npmjs.org/" }, "private": false -} +} \ No newline at end of file From 2ff7d45301859bb337f8e0991cb011e8b82cddb9 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Tue, 19 Aug 2025 05:55:45 +0000 Subject: [PATCH 062/122] chore(release): @trustvc/w3c-issuer@1.3.0-alpha.5 [skip ci] # [1.3.0-alpha.5](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-issuer@1.3.0-alpha.4...@trustvc/w3c-issuer@1.3.0-alpha.5) (2025-08-19) ### Bug Fixes * expose version detection function ([#76](https://github.com/TrustVC/w3c/issues/76)) ([0cc8941](https://github.com/TrustVC/w3c/commit/0cc8941b9dc8a8a8cac800ad76ec64cfd7e29753)) --- packages/w3c-issuer/CHANGELOG.md | 7 +++++++ packages/w3c-issuer/package.json | 4 ++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/packages/w3c-issuer/CHANGELOG.md b/packages/w3c-issuer/CHANGELOG.md index 18211665..dbecd9b0 100644 --- a/packages/w3c-issuer/CHANGELOG.md +++ b/packages/w3c-issuer/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.5](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-issuer@1.3.0-alpha.4...@trustvc/w3c-issuer@1.3.0-alpha.5) (2025-08-19) + + +### Bug Fixes + +* expose version detection function ([#76](https://github.com/TrustVC/w3c/issues/76)) ([0cc8941](https://github.com/TrustVC/w3c/commit/0cc8941b9dc8a8a8cac800ad76ec64cfd7e29753)) + # [1.3.0-alpha.4](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-issuer@1.3.0-alpha.3...@trustvc/w3c-issuer@1.3.0-alpha.4) (2025-08-19) diff --git a/packages/w3c-issuer/package.json b/packages/w3c-issuer/package.json index 3f9fbfd8..1511d37a 100644 --- a/packages/w3c-issuer/package.json +++ b/packages/w3c-issuer/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c-issuer", - "version": "1.3.0-alpha.4", + "version": "1.3.0-alpha.5", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", @@ -50,4 +50,4 @@ "registry": "https://registry.npmjs.org/" }, "private": false -} \ No newline at end of file +} From 636c647826d58d15324bddb5ef313832879feaf7 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Tue, 19 Aug 2025 05:56:16 +0000 Subject: [PATCH 063/122] chore(release): @trustvc/w3c-context@1.3.0-alpha.7 [skip ci] # [1.3.0-alpha.7](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-context@1.3.0-alpha.6...@trustvc/w3c-context@1.3.0-alpha.7) (2025-08-19) ### Bug Fixes * expose version detection function ([#76](https://github.com/TrustVC/w3c/issues/76)) ([0cc8941](https://github.com/TrustVC/w3c/commit/0cc8941b9dc8a8a8cac800ad76ec64cfd7e29753)) --- packages/w3c-context/CHANGELOG.md | 7 +++++++ packages/w3c-context/package.json | 4 ++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/packages/w3c-context/CHANGELOG.md b/packages/w3c-context/CHANGELOG.md index 7af20508..f2534e6e 100644 --- a/packages/w3c-context/CHANGELOG.md +++ b/packages/w3c-context/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.7](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-context@1.3.0-alpha.6...@trustvc/w3c-context@1.3.0-alpha.7) (2025-08-19) + + +### Bug Fixes + +* expose version detection function ([#76](https://github.com/TrustVC/w3c/issues/76)) ([0cc8941](https://github.com/TrustVC/w3c/commit/0cc8941b9dc8a8a8cac800ad76ec64cfd7e29753)) + # [1.3.0-alpha.6](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-context@1.3.0-alpha.5...@trustvc/w3c-context@1.3.0-alpha.6) (2025-08-19) diff --git a/packages/w3c-context/package.json b/packages/w3c-context/package.json index da8e2066..7fbb11bf 100644 --- a/packages/w3c-context/package.json +++ b/packages/w3c-context/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c-context", - "version": "1.3.0-alpha.6", + "version": "1.3.0-alpha.7", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", @@ -49,4 +49,4 @@ "registry": "https://registry.npmjs.org/" }, "private": false -} \ No newline at end of file +} From 5468fde3eb471c7de7c5c60b1134c06921f12295 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Tue, 19 Aug 2025 05:56:48 +0000 Subject: [PATCH 064/122] chore(release): @trustvc/w3c-credential-status@1.3.0-alpha.7 [skip ci] # [1.3.0-alpha.7](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-credential-status@1.3.0-alpha.6...@trustvc/w3c-credential-status@1.3.0-alpha.7) (2025-08-19) ### Bug Fixes * expose version detection function ([#76](https://github.com/TrustVC/w3c/issues/76)) ([0cc8941](https://github.com/TrustVC/w3c/commit/0cc8941b9dc8a8a8cac800ad76ec64cfd7e29753)) --- packages/w3c-credential-status/CHANGELOG.md | 7 +++++++ packages/w3c-credential-status/package.json | 8 ++++---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/packages/w3c-credential-status/CHANGELOG.md b/packages/w3c-credential-status/CHANGELOG.md index 174c6f48..8dfad40f 100644 --- a/packages/w3c-credential-status/CHANGELOG.md +++ b/packages/w3c-credential-status/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.7](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-credential-status@1.3.0-alpha.6...@trustvc/w3c-credential-status@1.3.0-alpha.7) (2025-08-19) + + +### Bug Fixes + +* expose version detection function ([#76](https://github.com/TrustVC/w3c/issues/76)) ([0cc8941](https://github.com/TrustVC/w3c/commit/0cc8941b9dc8a8a8cac800ad76ec64cfd7e29753)) + # [1.3.0-alpha.6](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-credential-status@1.3.0-alpha.5...@trustvc/w3c-credential-status@1.3.0-alpha.6) (2025-08-19) diff --git a/packages/w3c-credential-status/package.json b/packages/w3c-credential-status/package.json index eca7f823..f92c80fc 100644 --- a/packages/w3c-credential-status/package.json +++ b/packages/w3c-credential-status/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c-credential-status", - "version": "1.3.0-alpha.6", + "version": "1.3.0-alpha.7", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", @@ -29,8 +29,8 @@ } }, "dependencies": { - "@trustvc/w3c-context": "^1.3.0-alpha.6", - "@trustvc/w3c-issuer": "^1.3.0-alpha.4", + "@trustvc/w3c-context": "^1.3.0-alpha.7", + "@trustvc/w3c-issuer": "^1.3.0-alpha.5", "base64url-universal": "^2.0.0", "pako": "^2.1.0" }, @@ -47,4 +47,4 @@ "registry": "https://registry.npmjs.org/" }, "private": false -} \ No newline at end of file +} From 0e84ac91c46dc7c7d3db41f4d3beddbdc799ae3e Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Tue, 19 Aug 2025 05:57:21 +0000 Subject: [PATCH 065/122] chore(release): @trustvc/w3c-vc@1.3.0-alpha.7 [skip ci] # [1.3.0-alpha.7](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.3.0-alpha.6...@trustvc/w3c-vc@1.3.0-alpha.7) (2025-08-19) ### Bug Fixes * expose version detection function ([#76](https://github.com/TrustVC/w3c/issues/76)) ([0cc8941](https://github.com/TrustVC/w3c/commit/0cc8941b9dc8a8a8cac800ad76ec64cfd7e29753)) --- packages/w3c-vc/CHANGELOG.md | 7 +++++++ packages/w3c-vc/package.json | 8 ++++---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/packages/w3c-vc/CHANGELOG.md b/packages/w3c-vc/CHANGELOG.md index e2835b4b..fe4c4136 100644 --- a/packages/w3c-vc/CHANGELOG.md +++ b/packages/w3c-vc/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.7](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.3.0-alpha.6...@trustvc/w3c-vc@1.3.0-alpha.7) (2025-08-19) + + +### Bug Fixes + +* expose version detection function ([#76](https://github.com/TrustVC/w3c/issues/76)) ([0cc8941](https://github.com/TrustVC/w3c/commit/0cc8941b9dc8a8a8cac800ad76ec64cfd7e29753)) + # [1.3.0-alpha.6](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.3.0-alpha.5...@trustvc/w3c-vc@1.3.0-alpha.6) (2025-08-19) diff --git a/packages/w3c-vc/package.json b/packages/w3c-vc/package.json index 89cd4649..874c35c6 100644 --- a/packages/w3c-vc/package.json +++ b/packages/w3c-vc/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c-vc", - "version": "1.3.0-alpha.6", + "version": "1.3.0-alpha.7", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", @@ -35,8 +35,8 @@ "@digitalbazaar/ecdsa-multikey": "^1.8.0", "@digitalbazaar/ecdsa-sd-2023-cryptosuite": "^3.4.1", "@mattrglobal/jsonld-signatures-bbs": "^1.2.0", - "@trustvc/w3c-credential-status": "^1.3.0-alpha.6", - "@trustvc/w3c-issuer": "^1.3.0-alpha.4", + "@trustvc/w3c-credential-status": "^1.3.0-alpha.7", + "@trustvc/w3c-issuer": "^1.3.0-alpha.5", "cbor": "^9.0.2", "did-resolver": "^4.1.0", "jsonld": "^6.0.0", @@ -66,4 +66,4 @@ "devDependencies": { "@types/uuid": "^10.0.0" } -} \ No newline at end of file +} From 708e91405db3e9e9b6420bbff41cbf200b794b4b Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Tue, 19 Aug 2025 05:57:50 +0000 Subject: [PATCH 066/122] chore(release): @trustvc/w3c-cli@1.3.0-alpha.7 [skip ci] # [1.3.0-alpha.7](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-cli@1.3.0-alpha.6...@trustvc/w3c-cli@1.3.0-alpha.7) (2025-08-19) ### Bug Fixes * expose version detection function ([#76](https://github.com/TrustVC/w3c/issues/76)) ([0cc8941](https://github.com/TrustVC/w3c/commit/0cc8941b9dc8a8a8cac800ad76ec64cfd7e29753)) --- apps/w3c-cli/CHANGELOG.md | 7 +++++++ apps/w3c-cli/package.json | 12 ++++++------ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/apps/w3c-cli/CHANGELOG.md b/apps/w3c-cli/CHANGELOG.md index 8b5efbf0..108af5e1 100644 --- a/apps/w3c-cli/CHANGELOG.md +++ b/apps/w3c-cli/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.7](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-cli@1.3.0-alpha.6...@trustvc/w3c-cli@1.3.0-alpha.7) (2025-08-19) + + +### Bug Fixes + +* expose version detection function ([#76](https://github.com/TrustVC/w3c/issues/76)) ([0cc8941](https://github.com/TrustVC/w3c/commit/0cc8941b9dc8a8a8cac800ad76ec64cfd7e29753)) + # [1.3.0-alpha.6](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-cli@1.3.0-alpha.5...@trustvc/w3c-cli@1.3.0-alpha.6) (2025-08-19) diff --git a/apps/w3c-cli/package.json b/apps/w3c-cli/package.json index 21e11a40..486fd368 100644 --- a/apps/w3c-cli/package.json +++ b/apps/w3c-cli/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c-cli", - "version": "1.3.0-alpha.6", + "version": "1.3.0-alpha.7", "description": "CLI for TrustVC W3C", "main": "dist/main.js", "types": "dist/main.d.ts", @@ -34,10 +34,10 @@ }, "dependencies": { "@inquirer/prompts": "^5.3.8", - "@trustvc/w3c-context": "^1.3.0-alpha.6", - "@trustvc/w3c-credential-status": "^1.3.0-alpha.6", - "@trustvc/w3c-vc": "^1.3.0-alpha.6", - "@trustvc/w3c-issuer": "^1.3.0-alpha.4", + "@trustvc/w3c-context": "^1.3.0-alpha.7", + "@trustvc/w3c-credential-status": "^1.3.0-alpha.7", + "@trustvc/w3c-vc": "^1.3.0-alpha.7", + "@trustvc/w3c-issuer": "^1.3.0-alpha.5", "@types/yargs": "^17.0.32", "chalk": "^4.1.2", "inquirer": "^10.0.1", @@ -56,4 +56,4 @@ "registry": "https://registry.npmjs.org/" }, "private": false -} \ No newline at end of file +} From 82a2305df19049d9bc93f32f091d56d71165ac28 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Tue, 19 Aug 2025 05:58:21 +0000 Subject: [PATCH 067/122] chore(release): @trustvc/w3c@1.3.0-alpha.7 [skip ci] # [1.3.0-alpha.7](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.3.0-alpha.6...@trustvc/w3c@1.3.0-alpha.7) (2025-08-19) ### Bug Fixes * expose version detection function ([#76](https://github.com/TrustVC/w3c/issues/76)) ([0cc8941](https://github.com/TrustVC/w3c/commit/0cc8941b9dc8a8a8cac800ad76ec64cfd7e29753)) --- packages/w3c/CHANGELOG.md | 7 +++++++ packages/w3c/package.json | 12 ++++++------ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/packages/w3c/CHANGELOG.md b/packages/w3c/CHANGELOG.md index 944d7f29..6a851921 100644 --- a/packages/w3c/CHANGELOG.md +++ b/packages/w3c/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.7](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.3.0-alpha.6...@trustvc/w3c@1.3.0-alpha.7) (2025-08-19) + + +### Bug Fixes + +* expose version detection function ([#76](https://github.com/TrustVC/w3c/issues/76)) ([0cc8941](https://github.com/TrustVC/w3c/commit/0cc8941b9dc8a8a8cac800ad76ec64cfd7e29753)) + # [1.3.0-alpha.6](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.3.0-alpha.5...@trustvc/w3c@1.3.0-alpha.6) (2025-08-19) diff --git a/packages/w3c/package.json b/packages/w3c/package.json index b47cf051..5d8d27be 100644 --- a/packages/w3c/package.json +++ b/packages/w3c/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c", - "version": "1.3.0-alpha.6", + "version": "1.3.0-alpha.7", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", @@ -32,10 +32,10 @@ } }, "dependencies": { - "@trustvc/w3c-context": "^1.3.0-alpha.6", - "@trustvc/w3c-credential-status": "^1.3.0-alpha.6", - "@trustvc/w3c-issuer": "^1.3.0-alpha.4", - "@trustvc/w3c-vc": "^1.3.0-alpha.6" + "@trustvc/w3c-context": "^1.3.0-alpha.7", + "@trustvc/w3c-credential-status": "^1.3.0-alpha.7", + "@trustvc/w3c-issuer": "^1.3.0-alpha.5", + "@trustvc/w3c-vc": "^1.3.0-alpha.7" }, "repository": { "type": "git", @@ -50,4 +50,4 @@ "registry": "https://registry.npmjs.org/" }, "private": false -} \ No newline at end of file +} From 7ab08247d7ff537ca5bf8db3267ba6b85d1ae3b6 Mon Sep 17 00:00:00 2001 From: Moiz Shaikh <58319530+Moiz47@users.noreply.github.com> Date: Wed, 27 Aug 2025 08:12:29 +0530 Subject: [PATCH 068/122] fix: use base64url decode (#77) Co-authored-by: moiz-sgtradex --- packages/w3c-vc/package.json | 1 + packages/w3c-vc/src/lib/w3c-vc.ts | 13 +++++++------ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/packages/w3c-vc/package.json b/packages/w3c-vc/package.json index 874c35c6..149c27ce 100644 --- a/packages/w3c-vc/package.json +++ b/packages/w3c-vc/package.json @@ -37,6 +37,7 @@ "@mattrglobal/jsonld-signatures-bbs": "^1.2.0", "@trustvc/w3c-credential-status": "^1.3.0-alpha.7", "@trustvc/w3c-issuer": "^1.3.0-alpha.5", + "base64url-universal": "^2.0.0", "cbor": "^9.0.2", "did-resolver": "^4.1.0", "jsonld": "^6.0.0", diff --git a/packages/w3c-vc/src/lib/w3c-vc.ts b/packages/w3c-vc/src/lib/w3c-vc.ts index 07dcc13a..3f1d8ad7 100644 --- a/packages/w3c-vc/src/lib/w3c-vc.ts +++ b/packages/w3c-vc/src/lib/w3c-vc.ts @@ -110,13 +110,14 @@ export const isSignedDocumentV2_0 = ( * @param {string} proofValue - The proof value string to check * @returns {boolean} - true if this is a base proof, false otherwise */ -const isEcdsaSdBaseProof = (proofValue: string): boolean => { +const isEcdsaSdBaseProof = async (proofValue: string): Promise => { try { if (!proofValue || !proofValue.startsWith('u')) { return false; } - // Decode to check the structure - const decoded = Buffer.from(proofValue.slice(1), 'base64url'); + // @ts-ignore: No types available for base64url-universal + const { decode } = await import('base64url-universal'); + const decoded = decode(proofValue.slice(1)); // Check if it has the base proof header (0xd9, 0x5d, 0x00) return decoded.length >= 3 && decoded[0] === 0xd9 && decoded[1] === 0x5d && decoded[2] === 0x00; } catch { @@ -131,7 +132,7 @@ const isEcdsaSdBaseProof = (proofValue: string): boolean => { */ const extractMandatoryPointers = async (proofValue: string): Promise => { try { - if (!isEcdsaSdBaseProof(proofValue)) { + if (!(await isEcdsaSdBaseProof(proofValue))) { return []; } @@ -289,7 +290,7 @@ export const verifyCredential = async ( if (cryptosuite === 'ecdsa-sd-2023') { // Check if this is a base credential (non-derived) by examining the proofValue structure - if (isEcdsaSdBaseProof(proof.proofValue as string)) { + if (await isEcdsaSdBaseProof(proof.proofValue as string)) { // This is a base proof - ECDSA-SD-2023 base credentials require derivation before verification return { verified: false, @@ -385,7 +386,7 @@ export const deriveCredential = async ( if (cryptosuite === 'ecdsa-sd-2023') { // Check if this is already a derived credential by examining the proofValue structure - if (!isEcdsaSdBaseProof(proof.proofValue as string)) { + if (!(await isEcdsaSdBaseProof(proof.proofValue as string))) { return { error: `${cryptosuite} derived credentials cannot be further derived. Multiple rounds of derivation are not supported by this cryptosuite.`, }; From 2b959a24884070d5546f67913100c97ea0080370 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 27 Aug 2025 02:45:37 +0000 Subject: [PATCH 069/122] chore(release): @trustvc/w3c-vc@1.3.0-alpha.8 [skip ci] # [1.3.0-alpha.8](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.3.0-alpha.7...@trustvc/w3c-vc@1.3.0-alpha.8) (2025-08-27) ### Bug Fixes * use base64url decode ([#77](https://github.com/TrustVC/w3c/issues/77)) ([7ab0824](https://github.com/TrustVC/w3c/commit/7ab08247d7ff537ca5bf8db3267ba6b85d1ae3b6)) --- packages/w3c-vc/CHANGELOG.md | 7 +++++++ packages/w3c-vc/package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/w3c-vc/CHANGELOG.md b/packages/w3c-vc/CHANGELOG.md index fe4c4136..08913a18 100644 --- a/packages/w3c-vc/CHANGELOG.md +++ b/packages/w3c-vc/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.8](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.3.0-alpha.7...@trustvc/w3c-vc@1.3.0-alpha.8) (2025-08-27) + + +### Bug Fixes + +* use base64url decode ([#77](https://github.com/TrustVC/w3c/issues/77)) ([7ab0824](https://github.com/TrustVC/w3c/commit/7ab08247d7ff537ca5bf8db3267ba6b85d1ae3b6)) + # [1.3.0-alpha.7](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.3.0-alpha.6...@trustvc/w3c-vc@1.3.0-alpha.7) (2025-08-19) diff --git a/packages/w3c-vc/package.json b/packages/w3c-vc/package.json index 149c27ce..1ee16ea8 100644 --- a/packages/w3c-vc/package.json +++ b/packages/w3c-vc/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c-vc", - "version": "1.3.0-alpha.7", + "version": "1.3.0-alpha.8", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", From eea8d5a437a51ea0970e9b747840005c8ebdcf59 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 27 Aug 2025 02:46:05 +0000 Subject: [PATCH 070/122] chore(release): @trustvc/w3c-cli@1.3.0-alpha.8 [skip ci] # [1.3.0-alpha.8](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-cli@1.3.0-alpha.7...@trustvc/w3c-cli@1.3.0-alpha.8) (2025-08-27) ### Bug Fixes * use base64url decode ([#77](https://github.com/TrustVC/w3c/issues/77)) ([7ab0824](https://github.com/TrustVC/w3c/commit/7ab08247d7ff537ca5bf8db3267ba6b85d1ae3b6)) --- apps/w3c-cli/CHANGELOG.md | 7 +++++++ apps/w3c-cli/package.json | 4 ++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/apps/w3c-cli/CHANGELOG.md b/apps/w3c-cli/CHANGELOG.md index 108af5e1..915884dc 100644 --- a/apps/w3c-cli/CHANGELOG.md +++ b/apps/w3c-cli/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.8](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-cli@1.3.0-alpha.7...@trustvc/w3c-cli@1.3.0-alpha.8) (2025-08-27) + + +### Bug Fixes + +* use base64url decode ([#77](https://github.com/TrustVC/w3c/issues/77)) ([7ab0824](https://github.com/TrustVC/w3c/commit/7ab08247d7ff537ca5bf8db3267ba6b85d1ae3b6)) + # [1.3.0-alpha.7](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-cli@1.3.0-alpha.6...@trustvc/w3c-cli@1.3.0-alpha.7) (2025-08-19) diff --git a/apps/w3c-cli/package.json b/apps/w3c-cli/package.json index 486fd368..2bdb252c 100644 --- a/apps/w3c-cli/package.json +++ b/apps/w3c-cli/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c-cli", - "version": "1.3.0-alpha.7", + "version": "1.3.0-alpha.8", "description": "CLI for TrustVC W3C", "main": "dist/main.js", "types": "dist/main.d.ts", @@ -36,7 +36,7 @@ "@inquirer/prompts": "^5.3.8", "@trustvc/w3c-context": "^1.3.0-alpha.7", "@trustvc/w3c-credential-status": "^1.3.0-alpha.7", - "@trustvc/w3c-vc": "^1.3.0-alpha.7", + "@trustvc/w3c-vc": "^1.3.0-alpha.8", "@trustvc/w3c-issuer": "^1.3.0-alpha.5", "@types/yargs": "^17.0.32", "chalk": "^4.1.2", From 05b40f13459b46cd59b85f8fc19e64abc5b905d6 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 27 Aug 2025 02:46:35 +0000 Subject: [PATCH 071/122] chore(release): @trustvc/w3c@1.3.0-alpha.8 [skip ci] # [1.3.0-alpha.8](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.3.0-alpha.7...@trustvc/w3c@1.3.0-alpha.8) (2025-08-27) ### Bug Fixes * use base64url decode ([#77](https://github.com/TrustVC/w3c/issues/77)) ([7ab0824](https://github.com/TrustVC/w3c/commit/7ab08247d7ff537ca5bf8db3267ba6b85d1ae3b6)) --- packages/w3c/CHANGELOG.md | 7 +++++++ packages/w3c/package.json | 4 ++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/packages/w3c/CHANGELOG.md b/packages/w3c/CHANGELOG.md index 6a851921..6b5cc7a9 100644 --- a/packages/w3c/CHANGELOG.md +++ b/packages/w3c/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.8](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.3.0-alpha.7...@trustvc/w3c@1.3.0-alpha.8) (2025-08-27) + + +### Bug Fixes + +* use base64url decode ([#77](https://github.com/TrustVC/w3c/issues/77)) ([7ab0824](https://github.com/TrustVC/w3c/commit/7ab08247d7ff537ca5bf8db3267ba6b85d1ae3b6)) + # [1.3.0-alpha.7](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.3.0-alpha.6...@trustvc/w3c@1.3.0-alpha.7) (2025-08-19) diff --git a/packages/w3c/package.json b/packages/w3c/package.json index 5d8d27be..14f18e38 100644 --- a/packages/w3c/package.json +++ b/packages/w3c/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c", - "version": "1.3.0-alpha.7", + "version": "1.3.0-alpha.8", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", @@ -35,7 +35,7 @@ "@trustvc/w3c-context": "^1.3.0-alpha.7", "@trustvc/w3c-credential-status": "^1.3.0-alpha.7", "@trustvc/w3c-issuer": "^1.3.0-alpha.5", - "@trustvc/w3c-vc": "^1.3.0-alpha.7" + "@trustvc/w3c-vc": "^1.3.0-alpha.8" }, "repository": { "type": "git", From 972deb7c1c08083766a6b46290ae6d5648bacff1 Mon Sep 17 00:00:00 2001 From: rongquan1 <85145303+rongquan1@users.noreply.github.com> Date: Wed, 27 Aug 2025 17:05:31 +0800 Subject: [PATCH 072/122] fix: handle both buffer and uint8array env in base proof header check (#78) --- package-lock.json | 37 ++++++++++++++++--------------- packages/w3c-vc/src/lib/w3c-vc.ts | 8 ++++++- 2 files changed, 26 insertions(+), 19 deletions(-) diff --git a/package-lock.json b/package-lock.json index b2bd535f..46dfdc90 100644 --- a/package-lock.json +++ b/package-lock.json @@ -115,14 +115,14 @@ }, "apps/w3c-cli": { "name": "@trustvc/w3c-cli", - "version": "1.3.0-alpha.5", + "version": "1.3.0-alpha.8", "license": "Apache-2.0", "dependencies": { "@inquirer/prompts": "^5.3.8", - "@trustvc/w3c-context": "^1.3.0-alpha.5", - "@trustvc/w3c-credential-status": "^1.3.0-alpha.5", - "@trustvc/w3c-issuer": "^1.3.0-alpha.3", - "@trustvc/w3c-vc": "^1.3.0-alpha.5", + "@trustvc/w3c-context": "^1.3.0-alpha.7", + "@trustvc/w3c-credential-status": "^1.3.0-alpha.7", + "@trustvc/w3c-issuer": "^1.3.0-alpha.5", + "@trustvc/w3c-vc": "^1.3.0-alpha.8", "@types/yargs": "^17.0.32", "chalk": "^4.1.2", "inquirer": "^10.0.1", @@ -32819,13 +32819,13 @@ }, "packages/w3c": { "name": "@trustvc/w3c", - "version": "1.3.0-alpha.5", + "version": "1.3.0-alpha.8", "license": "Apache-2.0", "dependencies": { - "@trustvc/w3c-context": "^1.3.0-alpha.5", - "@trustvc/w3c-credential-status": "^1.3.0-alpha.5", - "@trustvc/w3c-issuer": "^1.3.0-alpha.3", - "@trustvc/w3c-vc": "^1.3.0-alpha.5" + "@trustvc/w3c-context": "^1.3.0-alpha.7", + "@trustvc/w3c-credential-status": "^1.3.0-alpha.7", + "@trustvc/w3c-issuer": "^1.3.0-alpha.5", + "@trustvc/w3c-vc": "^1.3.0-alpha.8" }, "engines": { "node": ">=18.x" @@ -32833,7 +32833,7 @@ }, "packages/w3c-context": { "name": "@trustvc/w3c-context", - "version": "1.3.0-alpha.5", + "version": "1.3.0-alpha.7", "license": "Apache-2.0", "dependencies": { "did-resolver": "^4.1.0", @@ -32925,11 +32925,11 @@ }, "packages/w3c-credential-status": { "name": "@trustvc/w3c-credential-status", - "version": "1.3.0-alpha.5", + "version": "1.3.0-alpha.7", "license": "Apache-2.0", "dependencies": { - "@trustvc/w3c-context": "^1.3.0-alpha.5", - "@trustvc/w3c-issuer": "^1.3.0-alpha.3", + "@trustvc/w3c-context": "^1.3.0-alpha.7", + "@trustvc/w3c-issuer": "^1.3.0-alpha.5", "base64url-universal": "^2.0.0", "pako": "^2.1.0" }, @@ -32939,7 +32939,7 @@ }, "packages/w3c-issuer": { "name": "@trustvc/w3c-issuer", - "version": "1.3.0-alpha.3", + "version": "1.3.0-alpha.5", "license": "Apache-2.0", "dependencies": { "@digitalbazaar/bls12-381-multikey": "^2.1.0", @@ -32956,15 +32956,16 @@ }, "packages/w3c-vc": { "name": "@trustvc/w3c-vc", - "version": "1.3.0-alpha.5", + "version": "1.3.0-alpha.8", "license": "Apache-2.0", "dependencies": { "@digitalbazaar/data-integrity": "^2.5.0", "@digitalbazaar/ecdsa-multikey": "^1.8.0", "@digitalbazaar/ecdsa-sd-2023-cryptosuite": "^3.4.1", "@mattrglobal/jsonld-signatures-bbs": "^1.2.0", - "@trustvc/w3c-credential-status": "^1.3.0-alpha.5", - "@trustvc/w3c-issuer": "^1.3.0-alpha.3", + "@trustvc/w3c-credential-status": "^1.3.0-alpha.7", + "@trustvc/w3c-issuer": "^1.3.0-alpha.5", + "base64url-universal": "^2.0.0", "cbor": "^9.0.2", "did-resolver": "^4.1.0", "jsonld": "^6.0.0", diff --git a/packages/w3c-vc/src/lib/w3c-vc.ts b/packages/w3c-vc/src/lib/w3c-vc.ts index 3f1d8ad7..9d80e1e5 100644 --- a/packages/w3c-vc/src/lib/w3c-vc.ts +++ b/packages/w3c-vc/src/lib/w3c-vc.ts @@ -119,7 +119,13 @@ const isEcdsaSdBaseProof = async (proofValue: string): Promise => { const { decode } = await import('base64url-universal'); const decoded = decode(proofValue.slice(1)); // Check if it has the base proof header (0xd9, 0x5d, 0x00) - return decoded.length >= 3 && decoded[0] === 0xd9 && decoded[1] === 0x5d && decoded[2] === 0x00; + // Convert to numbers to handle both Buffer (Node.js) and Uint8Array (browser) environments + return ( + decoded.length >= 3 && + Number(decoded[0]) === 0xd9 && + Number(decoded[1]) === 0x5d && + Number(decoded[2]) === 0x00 + ); } catch { return false; } From c4fa9bbc294a498ad962c05dce19cd4b206dcdb1 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 27 Aug 2025 09:08:11 +0000 Subject: [PATCH 073/122] chore(release): @trustvc/w3c-issuer@1.3.0-alpha.6 [skip ci] # [1.3.0-alpha.6](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-issuer@1.3.0-alpha.5...@trustvc/w3c-issuer@1.3.0-alpha.6) (2025-08-27) ### Bug Fixes * handle both buffer and uint8array env in base proof header check ([#78](https://github.com/TrustVC/w3c/issues/78)) ([972deb7](https://github.com/TrustVC/w3c/commit/972deb7c1c08083766a6b46290ae6d5648bacff1)) --- packages/w3c-issuer/CHANGELOG.md | 7 +++++++ packages/w3c-issuer/package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/w3c-issuer/CHANGELOG.md b/packages/w3c-issuer/CHANGELOG.md index dbecd9b0..e2ab5951 100644 --- a/packages/w3c-issuer/CHANGELOG.md +++ b/packages/w3c-issuer/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.6](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-issuer@1.3.0-alpha.5...@trustvc/w3c-issuer@1.3.0-alpha.6) (2025-08-27) + + +### Bug Fixes + +* handle both buffer and uint8array env in base proof header check ([#78](https://github.com/TrustVC/w3c/issues/78)) ([972deb7](https://github.com/TrustVC/w3c/commit/972deb7c1c08083766a6b46290ae6d5648bacff1)) + # [1.3.0-alpha.5](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-issuer@1.3.0-alpha.4...@trustvc/w3c-issuer@1.3.0-alpha.5) (2025-08-19) diff --git a/packages/w3c-issuer/package.json b/packages/w3c-issuer/package.json index 1511d37a..c4a82e3d 100644 --- a/packages/w3c-issuer/package.json +++ b/packages/w3c-issuer/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c-issuer", - "version": "1.3.0-alpha.5", + "version": "1.3.0-alpha.6", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", From 4dd2df99ff663cc5cb7f2d9f3f8782f862f91366 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 27 Aug 2025 09:08:43 +0000 Subject: [PATCH 074/122] chore(release): @trustvc/w3c-context@1.3.0-alpha.8 [skip ci] # [1.3.0-alpha.8](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-context@1.3.0-alpha.7...@trustvc/w3c-context@1.3.0-alpha.8) (2025-08-27) ### Bug Fixes * handle both buffer and uint8array env in base proof header check ([#78](https://github.com/TrustVC/w3c/issues/78)) ([972deb7](https://github.com/TrustVC/w3c/commit/972deb7c1c08083766a6b46290ae6d5648bacff1)) --- packages/w3c-context/CHANGELOG.md | 7 +++++++ packages/w3c-context/package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/w3c-context/CHANGELOG.md b/packages/w3c-context/CHANGELOG.md index f2534e6e..d6c2e979 100644 --- a/packages/w3c-context/CHANGELOG.md +++ b/packages/w3c-context/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.8](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-context@1.3.0-alpha.7...@trustvc/w3c-context@1.3.0-alpha.8) (2025-08-27) + + +### Bug Fixes + +* handle both buffer and uint8array env in base proof header check ([#78](https://github.com/TrustVC/w3c/issues/78)) ([972deb7](https://github.com/TrustVC/w3c/commit/972deb7c1c08083766a6b46290ae6d5648bacff1)) + # [1.3.0-alpha.7](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-context@1.3.0-alpha.6...@trustvc/w3c-context@1.3.0-alpha.7) (2025-08-19) diff --git a/packages/w3c-context/package.json b/packages/w3c-context/package.json index 7fbb11bf..2f9aca45 100644 --- a/packages/w3c-context/package.json +++ b/packages/w3c-context/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c-context", - "version": "1.3.0-alpha.7", + "version": "1.3.0-alpha.8", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", From 4d0d001e2a9911de35ebc8d20b240d59e20f5197 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 27 Aug 2025 09:09:17 +0000 Subject: [PATCH 075/122] chore(release): @trustvc/w3c-credential-status@1.3.0-alpha.8 [skip ci] # [1.3.0-alpha.8](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-credential-status@1.3.0-alpha.7...@trustvc/w3c-credential-status@1.3.0-alpha.8) (2025-08-27) ### Bug Fixes * handle both buffer and uint8array env in base proof header check ([#78](https://github.com/TrustVC/w3c/issues/78)) ([972deb7](https://github.com/TrustVC/w3c/commit/972deb7c1c08083766a6b46290ae6d5648bacff1)) --- packages/w3c-credential-status/CHANGELOG.md | 7 +++++++ packages/w3c-credential-status/package.json | 6 +++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/packages/w3c-credential-status/CHANGELOG.md b/packages/w3c-credential-status/CHANGELOG.md index 8dfad40f..290d0af2 100644 --- a/packages/w3c-credential-status/CHANGELOG.md +++ b/packages/w3c-credential-status/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.8](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-credential-status@1.3.0-alpha.7...@trustvc/w3c-credential-status@1.3.0-alpha.8) (2025-08-27) + + +### Bug Fixes + +* handle both buffer and uint8array env in base proof header check ([#78](https://github.com/TrustVC/w3c/issues/78)) ([972deb7](https://github.com/TrustVC/w3c/commit/972deb7c1c08083766a6b46290ae6d5648bacff1)) + # [1.3.0-alpha.7](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-credential-status@1.3.0-alpha.6...@trustvc/w3c-credential-status@1.3.0-alpha.7) (2025-08-19) diff --git a/packages/w3c-credential-status/package.json b/packages/w3c-credential-status/package.json index f92c80fc..730ffc65 100644 --- a/packages/w3c-credential-status/package.json +++ b/packages/w3c-credential-status/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c-credential-status", - "version": "1.3.0-alpha.7", + "version": "1.3.0-alpha.8", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", @@ -29,8 +29,8 @@ } }, "dependencies": { - "@trustvc/w3c-context": "^1.3.0-alpha.7", - "@trustvc/w3c-issuer": "^1.3.0-alpha.5", + "@trustvc/w3c-context": "^1.3.0-alpha.8", + "@trustvc/w3c-issuer": "^1.3.0-alpha.6", "base64url-universal": "^2.0.0", "pako": "^2.1.0" }, From a862c445dc63dab9aaef6add7a0a2489f7fe55db Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 27 Aug 2025 09:09:51 +0000 Subject: [PATCH 076/122] chore(release): @trustvc/w3c-vc@1.3.0-alpha.9 [skip ci] # [1.3.0-alpha.9](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.3.0-alpha.8...@trustvc/w3c-vc@1.3.0-alpha.9) (2025-08-27) ### Bug Fixes * handle both buffer and uint8array env in base proof header check ([#78](https://github.com/TrustVC/w3c/issues/78)) ([972deb7](https://github.com/TrustVC/w3c/commit/972deb7c1c08083766a6b46290ae6d5648bacff1)) --- packages/w3c-vc/CHANGELOG.md | 7 +++++++ packages/w3c-vc/package.json | 6 +++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/packages/w3c-vc/CHANGELOG.md b/packages/w3c-vc/CHANGELOG.md index 08913a18..d367d662 100644 --- a/packages/w3c-vc/CHANGELOG.md +++ b/packages/w3c-vc/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.9](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.3.0-alpha.8...@trustvc/w3c-vc@1.3.0-alpha.9) (2025-08-27) + + +### Bug Fixes + +* handle both buffer and uint8array env in base proof header check ([#78](https://github.com/TrustVC/w3c/issues/78)) ([972deb7](https://github.com/TrustVC/w3c/commit/972deb7c1c08083766a6b46290ae6d5648bacff1)) + # [1.3.0-alpha.8](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.3.0-alpha.7...@trustvc/w3c-vc@1.3.0-alpha.8) (2025-08-27) diff --git a/packages/w3c-vc/package.json b/packages/w3c-vc/package.json index 1ee16ea8..06e36a37 100644 --- a/packages/w3c-vc/package.json +++ b/packages/w3c-vc/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c-vc", - "version": "1.3.0-alpha.8", + "version": "1.3.0-alpha.9", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", @@ -35,8 +35,8 @@ "@digitalbazaar/ecdsa-multikey": "^1.8.0", "@digitalbazaar/ecdsa-sd-2023-cryptosuite": "^3.4.1", "@mattrglobal/jsonld-signatures-bbs": "^1.2.0", - "@trustvc/w3c-credential-status": "^1.3.0-alpha.7", - "@trustvc/w3c-issuer": "^1.3.0-alpha.5", + "@trustvc/w3c-credential-status": "^1.3.0-alpha.8", + "@trustvc/w3c-issuer": "^1.3.0-alpha.6", "base64url-universal": "^2.0.0", "cbor": "^9.0.2", "did-resolver": "^4.1.0", From 4b813bf06c66a893203e26d5a3dd6ddf830067dd Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 27 Aug 2025 09:10:21 +0000 Subject: [PATCH 077/122] chore(release): @trustvc/w3c-cli@1.3.0-alpha.9 [skip ci] # [1.3.0-alpha.9](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-cli@1.3.0-alpha.8...@trustvc/w3c-cli@1.3.0-alpha.9) (2025-08-27) ### Bug Fixes * handle both buffer and uint8array env in base proof header check ([#78](https://github.com/TrustVC/w3c/issues/78)) ([972deb7](https://github.com/TrustVC/w3c/commit/972deb7c1c08083766a6b46290ae6d5648bacff1)) --- apps/w3c-cli/CHANGELOG.md | 7 +++++++ apps/w3c-cli/package.json | 10 +++++----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/apps/w3c-cli/CHANGELOG.md b/apps/w3c-cli/CHANGELOG.md index 915884dc..23d5aa08 100644 --- a/apps/w3c-cli/CHANGELOG.md +++ b/apps/w3c-cli/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.9](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-cli@1.3.0-alpha.8...@trustvc/w3c-cli@1.3.0-alpha.9) (2025-08-27) + + +### Bug Fixes + +* handle both buffer and uint8array env in base proof header check ([#78](https://github.com/TrustVC/w3c/issues/78)) ([972deb7](https://github.com/TrustVC/w3c/commit/972deb7c1c08083766a6b46290ae6d5648bacff1)) + # [1.3.0-alpha.8](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-cli@1.3.0-alpha.7...@trustvc/w3c-cli@1.3.0-alpha.8) (2025-08-27) diff --git a/apps/w3c-cli/package.json b/apps/w3c-cli/package.json index 2bdb252c..20e5bbd4 100644 --- a/apps/w3c-cli/package.json +++ b/apps/w3c-cli/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c-cli", - "version": "1.3.0-alpha.8", + "version": "1.3.0-alpha.9", "description": "CLI for TrustVC W3C", "main": "dist/main.js", "types": "dist/main.d.ts", @@ -34,10 +34,10 @@ }, "dependencies": { "@inquirer/prompts": "^5.3.8", - "@trustvc/w3c-context": "^1.3.0-alpha.7", - "@trustvc/w3c-credential-status": "^1.3.0-alpha.7", - "@trustvc/w3c-vc": "^1.3.0-alpha.8", - "@trustvc/w3c-issuer": "^1.3.0-alpha.5", + "@trustvc/w3c-context": "^1.3.0-alpha.8", + "@trustvc/w3c-credential-status": "^1.3.0-alpha.8", + "@trustvc/w3c-vc": "^1.3.0-alpha.9", + "@trustvc/w3c-issuer": "^1.3.0-alpha.6", "@types/yargs": "^17.0.32", "chalk": "^4.1.2", "inquirer": "^10.0.1", From 4b93cd3ab190bd97d6d05887662c6dcf757d4e6f Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 27 Aug 2025 09:10:52 +0000 Subject: [PATCH 078/122] chore(release): @trustvc/w3c@1.3.0-alpha.9 [skip ci] # [1.3.0-alpha.9](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.3.0-alpha.8...@trustvc/w3c@1.3.0-alpha.9) (2025-08-27) ### Bug Fixes * handle both buffer and uint8array env in base proof header check ([#78](https://github.com/TrustVC/w3c/issues/78)) ([972deb7](https://github.com/TrustVC/w3c/commit/972deb7c1c08083766a6b46290ae6d5648bacff1)) --- packages/w3c/CHANGELOG.md | 7 +++++++ packages/w3c/package.json | 10 +++++----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/packages/w3c/CHANGELOG.md b/packages/w3c/CHANGELOG.md index 6b5cc7a9..f7530877 100644 --- a/packages/w3c/CHANGELOG.md +++ b/packages/w3c/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.9](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.3.0-alpha.8...@trustvc/w3c@1.3.0-alpha.9) (2025-08-27) + + +### Bug Fixes + +* handle both buffer and uint8array env in base proof header check ([#78](https://github.com/TrustVC/w3c/issues/78)) ([972deb7](https://github.com/TrustVC/w3c/commit/972deb7c1c08083766a6b46290ae6d5648bacff1)) + # [1.3.0-alpha.8](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.3.0-alpha.7...@trustvc/w3c@1.3.0-alpha.8) (2025-08-27) diff --git a/packages/w3c/package.json b/packages/w3c/package.json index 14f18e38..ce1a7193 100644 --- a/packages/w3c/package.json +++ b/packages/w3c/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c", - "version": "1.3.0-alpha.8", + "version": "1.3.0-alpha.9", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", @@ -32,10 +32,10 @@ } }, "dependencies": { - "@trustvc/w3c-context": "^1.3.0-alpha.7", - "@trustvc/w3c-credential-status": "^1.3.0-alpha.7", - "@trustvc/w3c-issuer": "^1.3.0-alpha.5", - "@trustvc/w3c-vc": "^1.3.0-alpha.8" + "@trustvc/w3c-context": "^1.3.0-alpha.8", + "@trustvc/w3c-credential-status": "^1.3.0-alpha.8", + "@trustvc/w3c-issuer": "^1.3.0-alpha.6", + "@trustvc/w3c-vc": "^1.3.0-alpha.9" }, "repository": { "type": "git", From 8e39ce85c999127398c6abeaab6bda588d2fc948 Mon Sep 17 00:00:00 2001 From: RishabhS7 <59636880+RishabhS7@users.noreply.github.com> Date: Tue, 2 Sep 2025 13:13:12 +0530 Subject: [PATCH 079/122] chore: add isDerived function for v2 documents (#79) * chore: add isDerived function for v2 documents * fix: remove test file --- packages/w3c-vc/src/index.ts | 2 ++ packages/w3c-vc/src/lib/w3c-vc.ts | 32 +++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/packages/w3c-vc/src/index.ts b/packages/w3c-vc/src/index.ts index 1da699d9..22d4f74e 100644 --- a/packages/w3c-vc/src/index.ts +++ b/packages/w3c-vc/src/index.ts @@ -9,6 +9,7 @@ import { isRawDocumentV2_0, isSignedDocumentV1_1, isSignedDocumentV2_0, + isDerived, } from './lib/w3c-vc'; import { getDocumentLoader } from '@trustvc/w3c-context'; @@ -33,4 +34,5 @@ export { isRawDocumentV2_0, isSignedDocumentV1_1, isSignedDocumentV2_0, + isDerived, }; diff --git a/packages/w3c-vc/src/lib/w3c-vc.ts b/packages/w3c-vc/src/lib/w3c-vc.ts index 9d80e1e5..968756ef 100644 --- a/packages/w3c-vc/src/lib/w3c-vc.ts +++ b/packages/w3c-vc/src/lib/w3c-vc.ts @@ -131,6 +131,38 @@ const isEcdsaSdBaseProof = async (proofValue: string): Promise => { } }; +/** + * Determines whether a verifiable credential is a derived credential. + * + * Derived credentials are selective disclosure proofs that contain only a subset + * of the original credential's claims, rather than the full base credential. + * + * @param {SignedVerifiableCredential} document - The document to check. + * @returns {Promise} - True if the document is a derived credential, false otherwise. + */ +export const isDerived = async (document: SignedVerifiableCredential) => { + // BBS+ signatures always indicate derived credentials (selective disclosure proofs) + if (document.proof?.type === 'BbsBlsSignatureProof2020') { + return true; + } else if (document.proof?.type === 'DataIntegrityProof') { + // For Data Integrity Proofs, check the cryptosuite to determine the specific verification approach + const proof = jsonld.getValues(document, 'proof')[0]; + const cryptosuite = proof.cryptosuite; + + // ECDSA Selective Disclosure 2023 cryptosuite + if (cryptosuite === 'ecdsa-sd-2023') { + // Check if this is a base proof (original credential) or derived proof (selective disclosure) + if (await isEcdsaSdBaseProof(proof.proofValue as string)) { + return false; // Base proof - contains all original claims + } else return true; // Derived proof - contains only selected claims + } + // Other Data Integrity cryptosuites are not derived + return false; + } + // No recognized proof type for selective disclosure + return false; +}; + /** * Extracts mandatory pointers from an ECDSA-SD-2023 base proof value * @param {string} proofValue - The base proof value string From 8b7f586bb1f7736a0c58cc19d8455988a0222987 Mon Sep 17 00:00:00 2001 From: RishabhS7 <59636880+RishabhS7@users.noreply.github.com> Date: Tue, 2 Sep 2025 13:54:08 +0530 Subject: [PATCH 080/122] fix: update package lock (#80) * fix: package lock * fix: update package lock --- package-lock.json | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/package-lock.json b/package-lock.json index 46dfdc90..0cd2e2c0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -115,14 +115,14 @@ }, "apps/w3c-cli": { "name": "@trustvc/w3c-cli", - "version": "1.3.0-alpha.8", + "version": "1.3.0-alpha.9", "license": "Apache-2.0", "dependencies": { "@inquirer/prompts": "^5.3.8", - "@trustvc/w3c-context": "^1.3.0-alpha.7", - "@trustvc/w3c-credential-status": "^1.3.0-alpha.7", - "@trustvc/w3c-issuer": "^1.3.0-alpha.5", - "@trustvc/w3c-vc": "^1.3.0-alpha.8", + "@trustvc/w3c-context": "^1.3.0-alpha.8", + "@trustvc/w3c-credential-status": "^1.3.0-alpha.8", + "@trustvc/w3c-issuer": "^1.3.0-alpha.6", + "@trustvc/w3c-vc": "^1.3.0-alpha.9", "@types/yargs": "^17.0.32", "chalk": "^4.1.2", "inquirer": "^10.0.1", @@ -32819,13 +32819,13 @@ }, "packages/w3c": { "name": "@trustvc/w3c", - "version": "1.3.0-alpha.8", + "version": "1.3.0-alpha.9", "license": "Apache-2.0", "dependencies": { - "@trustvc/w3c-context": "^1.3.0-alpha.7", - "@trustvc/w3c-credential-status": "^1.3.0-alpha.7", - "@trustvc/w3c-issuer": "^1.3.0-alpha.5", - "@trustvc/w3c-vc": "^1.3.0-alpha.8" + "@trustvc/w3c-context": "^1.3.0-alpha.8", + "@trustvc/w3c-credential-status": "^1.3.0-alpha.8", + "@trustvc/w3c-issuer": "^1.3.0-alpha.6", + "@trustvc/w3c-vc": "^1.3.0-alpha.9" }, "engines": { "node": ">=18.x" @@ -32833,7 +32833,7 @@ }, "packages/w3c-context": { "name": "@trustvc/w3c-context", - "version": "1.3.0-alpha.7", + "version": "1.3.0-alpha.8", "license": "Apache-2.0", "dependencies": { "did-resolver": "^4.1.0", @@ -32925,11 +32925,11 @@ }, "packages/w3c-credential-status": { "name": "@trustvc/w3c-credential-status", - "version": "1.3.0-alpha.7", + "version": "1.3.0-alpha.8", "license": "Apache-2.0", "dependencies": { - "@trustvc/w3c-context": "^1.3.0-alpha.7", - "@trustvc/w3c-issuer": "^1.3.0-alpha.5", + "@trustvc/w3c-context": "^1.3.0-alpha.8", + "@trustvc/w3c-issuer": "^1.3.0-alpha.6", "base64url-universal": "^2.0.0", "pako": "^2.1.0" }, @@ -32939,7 +32939,7 @@ }, "packages/w3c-issuer": { "name": "@trustvc/w3c-issuer", - "version": "1.3.0-alpha.5", + "version": "1.3.0-alpha.6", "license": "Apache-2.0", "dependencies": { "@digitalbazaar/bls12-381-multikey": "^2.1.0", @@ -32956,15 +32956,15 @@ }, "packages/w3c-vc": { "name": "@trustvc/w3c-vc", - "version": "1.3.0-alpha.8", + "version": "1.3.0-alpha.9", "license": "Apache-2.0", "dependencies": { "@digitalbazaar/data-integrity": "^2.5.0", "@digitalbazaar/ecdsa-multikey": "^1.8.0", "@digitalbazaar/ecdsa-sd-2023-cryptosuite": "^3.4.1", "@mattrglobal/jsonld-signatures-bbs": "^1.2.0", - "@trustvc/w3c-credential-status": "^1.3.0-alpha.7", - "@trustvc/w3c-issuer": "^1.3.0-alpha.5", + "@trustvc/w3c-credential-status": "^1.3.0-alpha.8", + "@trustvc/w3c-issuer": "^1.3.0-alpha.6", "base64url-universal": "^2.0.0", "cbor": "^9.0.2", "did-resolver": "^4.1.0", From f41596f1745efcb869ca7d42196cf52e9ebdf738 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Tue, 2 Sep 2025 08:26:47 +0000 Subject: [PATCH 081/122] chore(release): @trustvc/w3c-issuer@1.3.0-alpha.7 [skip ci] # [1.3.0-alpha.7](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-issuer@1.3.0-alpha.6...@trustvc/w3c-issuer@1.3.0-alpha.7) (2025-09-02) ### Bug Fixes * update package lock ([#80](https://github.com/TrustVC/w3c/issues/80)) ([8b7f586](https://github.com/TrustVC/w3c/commit/8b7f586bb1f7736a0c58cc19d8455988a0222987)) --- packages/w3c-issuer/CHANGELOG.md | 7 +++++++ packages/w3c-issuer/package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/w3c-issuer/CHANGELOG.md b/packages/w3c-issuer/CHANGELOG.md index e2ab5951..c9965814 100644 --- a/packages/w3c-issuer/CHANGELOG.md +++ b/packages/w3c-issuer/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.7](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-issuer@1.3.0-alpha.6...@trustvc/w3c-issuer@1.3.0-alpha.7) (2025-09-02) + + +### Bug Fixes + +* update package lock ([#80](https://github.com/TrustVC/w3c/issues/80)) ([8b7f586](https://github.com/TrustVC/w3c/commit/8b7f586bb1f7736a0c58cc19d8455988a0222987)) + # [1.3.0-alpha.6](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-issuer@1.3.0-alpha.5...@trustvc/w3c-issuer@1.3.0-alpha.6) (2025-08-27) diff --git a/packages/w3c-issuer/package.json b/packages/w3c-issuer/package.json index c4a82e3d..7478d32c 100644 --- a/packages/w3c-issuer/package.json +++ b/packages/w3c-issuer/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c-issuer", - "version": "1.3.0-alpha.6", + "version": "1.3.0-alpha.7", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", From b637685444655e163a715ae7188e75f80a7a7f06 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Tue, 2 Sep 2025 08:27:25 +0000 Subject: [PATCH 082/122] chore(release): @trustvc/w3c-context@1.3.0-alpha.9 [skip ci] # [1.3.0-alpha.9](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-context@1.3.0-alpha.8...@trustvc/w3c-context@1.3.0-alpha.9) (2025-09-02) ### Bug Fixes * update package lock ([#80](https://github.com/TrustVC/w3c/issues/80)) ([8b7f586](https://github.com/TrustVC/w3c/commit/8b7f586bb1f7736a0c58cc19d8455988a0222987)) --- packages/w3c-context/CHANGELOG.md | 7 +++++++ packages/w3c-context/package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/w3c-context/CHANGELOG.md b/packages/w3c-context/CHANGELOG.md index d6c2e979..02b59094 100644 --- a/packages/w3c-context/CHANGELOG.md +++ b/packages/w3c-context/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.9](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-context@1.3.0-alpha.8...@trustvc/w3c-context@1.3.0-alpha.9) (2025-09-02) + + +### Bug Fixes + +* update package lock ([#80](https://github.com/TrustVC/w3c/issues/80)) ([8b7f586](https://github.com/TrustVC/w3c/commit/8b7f586bb1f7736a0c58cc19d8455988a0222987)) + # [1.3.0-alpha.8](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-context@1.3.0-alpha.7...@trustvc/w3c-context@1.3.0-alpha.8) (2025-08-27) diff --git a/packages/w3c-context/package.json b/packages/w3c-context/package.json index 2f9aca45..f1d6d9f4 100644 --- a/packages/w3c-context/package.json +++ b/packages/w3c-context/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c-context", - "version": "1.3.0-alpha.8", + "version": "1.3.0-alpha.9", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", From 2d09dabf4d8d8e27c6fa6d4f364d84c149a2c529 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Tue, 2 Sep 2025 08:28:05 +0000 Subject: [PATCH 083/122] chore(release): @trustvc/w3c-credential-status@1.3.0-alpha.9 [skip ci] # [1.3.0-alpha.9](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-credential-status@1.3.0-alpha.8...@trustvc/w3c-credential-status@1.3.0-alpha.9) (2025-09-02) ### Bug Fixes * update package lock ([#80](https://github.com/TrustVC/w3c/issues/80)) ([8b7f586](https://github.com/TrustVC/w3c/commit/8b7f586bb1f7736a0c58cc19d8455988a0222987)) --- packages/w3c-credential-status/CHANGELOG.md | 7 +++++++ packages/w3c-credential-status/package.json | 6 +++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/packages/w3c-credential-status/CHANGELOG.md b/packages/w3c-credential-status/CHANGELOG.md index 290d0af2..99b0a31f 100644 --- a/packages/w3c-credential-status/CHANGELOG.md +++ b/packages/w3c-credential-status/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.9](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-credential-status@1.3.0-alpha.8...@trustvc/w3c-credential-status@1.3.0-alpha.9) (2025-09-02) + + +### Bug Fixes + +* update package lock ([#80](https://github.com/TrustVC/w3c/issues/80)) ([8b7f586](https://github.com/TrustVC/w3c/commit/8b7f586bb1f7736a0c58cc19d8455988a0222987)) + # [1.3.0-alpha.8](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-credential-status@1.3.0-alpha.7...@trustvc/w3c-credential-status@1.3.0-alpha.8) (2025-08-27) diff --git a/packages/w3c-credential-status/package.json b/packages/w3c-credential-status/package.json index 730ffc65..0b720b25 100644 --- a/packages/w3c-credential-status/package.json +++ b/packages/w3c-credential-status/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c-credential-status", - "version": "1.3.0-alpha.8", + "version": "1.3.0-alpha.9", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", @@ -29,8 +29,8 @@ } }, "dependencies": { - "@trustvc/w3c-context": "^1.3.0-alpha.8", - "@trustvc/w3c-issuer": "^1.3.0-alpha.6", + "@trustvc/w3c-context": "^1.3.0-alpha.9", + "@trustvc/w3c-issuer": "^1.3.0-alpha.7", "base64url-universal": "^2.0.0", "pako": "^2.1.0" }, From fdd38800c493e29aa77b7a5d2744a2a4b7fe1b2e Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Tue, 2 Sep 2025 08:28:45 +0000 Subject: [PATCH 084/122] chore(release): @trustvc/w3c-vc@1.3.0-alpha.10 [skip ci] # [1.3.0-alpha.10](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.3.0-alpha.9...@trustvc/w3c-vc@1.3.0-alpha.10) (2025-09-02) ### Bug Fixes * update package lock ([#80](https://github.com/TrustVC/w3c/issues/80)) ([8b7f586](https://github.com/TrustVC/w3c/commit/8b7f586bb1f7736a0c58cc19d8455988a0222987)) --- packages/w3c-vc/CHANGELOG.md | 7 +++++++ packages/w3c-vc/package.json | 6 +++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/packages/w3c-vc/CHANGELOG.md b/packages/w3c-vc/CHANGELOG.md index d367d662..c87e90dc 100644 --- a/packages/w3c-vc/CHANGELOG.md +++ b/packages/w3c-vc/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.10](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.3.0-alpha.9...@trustvc/w3c-vc@1.3.0-alpha.10) (2025-09-02) + + +### Bug Fixes + +* update package lock ([#80](https://github.com/TrustVC/w3c/issues/80)) ([8b7f586](https://github.com/TrustVC/w3c/commit/8b7f586bb1f7736a0c58cc19d8455988a0222987)) + # [1.3.0-alpha.9](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.3.0-alpha.8...@trustvc/w3c-vc@1.3.0-alpha.9) (2025-08-27) diff --git a/packages/w3c-vc/package.json b/packages/w3c-vc/package.json index 06e36a37..d8a4a93f 100644 --- a/packages/w3c-vc/package.json +++ b/packages/w3c-vc/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c-vc", - "version": "1.3.0-alpha.9", + "version": "1.3.0-alpha.10", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", @@ -35,8 +35,8 @@ "@digitalbazaar/ecdsa-multikey": "^1.8.0", "@digitalbazaar/ecdsa-sd-2023-cryptosuite": "^3.4.1", "@mattrglobal/jsonld-signatures-bbs": "^1.2.0", - "@trustvc/w3c-credential-status": "^1.3.0-alpha.8", - "@trustvc/w3c-issuer": "^1.3.0-alpha.6", + "@trustvc/w3c-credential-status": "^1.3.0-alpha.9", + "@trustvc/w3c-issuer": "^1.3.0-alpha.7", "base64url-universal": "^2.0.0", "cbor": "^9.0.2", "did-resolver": "^4.1.0", From 5cfb7b5503b2a192ee399e342cb862b02ba73063 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Tue, 2 Sep 2025 08:29:25 +0000 Subject: [PATCH 085/122] chore(release): @trustvc/w3c-cli@1.3.0-alpha.10 [skip ci] # [1.3.0-alpha.10](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-cli@1.3.0-alpha.9...@trustvc/w3c-cli@1.3.0-alpha.10) (2025-09-02) ### Bug Fixes * update package lock ([#80](https://github.com/TrustVC/w3c/issues/80)) ([8b7f586](https://github.com/TrustVC/w3c/commit/8b7f586bb1f7736a0c58cc19d8455988a0222987)) --- apps/w3c-cli/CHANGELOG.md | 7 +++++++ apps/w3c-cli/package.json | 10 +++++----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/apps/w3c-cli/CHANGELOG.md b/apps/w3c-cli/CHANGELOG.md index 23d5aa08..8e1e1a72 100644 --- a/apps/w3c-cli/CHANGELOG.md +++ b/apps/w3c-cli/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.10](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-cli@1.3.0-alpha.9...@trustvc/w3c-cli@1.3.0-alpha.10) (2025-09-02) + + +### Bug Fixes + +* update package lock ([#80](https://github.com/TrustVC/w3c/issues/80)) ([8b7f586](https://github.com/TrustVC/w3c/commit/8b7f586bb1f7736a0c58cc19d8455988a0222987)) + # [1.3.0-alpha.9](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-cli@1.3.0-alpha.8...@trustvc/w3c-cli@1.3.0-alpha.9) (2025-08-27) diff --git a/apps/w3c-cli/package.json b/apps/w3c-cli/package.json index 20e5bbd4..b7b62c8c 100644 --- a/apps/w3c-cli/package.json +++ b/apps/w3c-cli/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c-cli", - "version": "1.3.0-alpha.9", + "version": "1.3.0-alpha.10", "description": "CLI for TrustVC W3C", "main": "dist/main.js", "types": "dist/main.d.ts", @@ -34,10 +34,10 @@ }, "dependencies": { "@inquirer/prompts": "^5.3.8", - "@trustvc/w3c-context": "^1.3.0-alpha.8", - "@trustvc/w3c-credential-status": "^1.3.0-alpha.8", - "@trustvc/w3c-vc": "^1.3.0-alpha.9", - "@trustvc/w3c-issuer": "^1.3.0-alpha.6", + "@trustvc/w3c-context": "^1.3.0-alpha.9", + "@trustvc/w3c-credential-status": "^1.3.0-alpha.9", + "@trustvc/w3c-vc": "^1.3.0-alpha.10", + "@trustvc/w3c-issuer": "^1.3.0-alpha.7", "@types/yargs": "^17.0.32", "chalk": "^4.1.2", "inquirer": "^10.0.1", From e13a1a5742d1961acbbcc251e80a88a08b2ec892 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Tue, 2 Sep 2025 08:30:07 +0000 Subject: [PATCH 086/122] chore(release): @trustvc/w3c@1.3.0-alpha.10 [skip ci] # [1.3.0-alpha.10](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.3.0-alpha.9...@trustvc/w3c@1.3.0-alpha.10) (2025-09-02) ### Bug Fixes * update package lock ([#80](https://github.com/TrustVC/w3c/issues/80)) ([8b7f586](https://github.com/TrustVC/w3c/commit/8b7f586bb1f7736a0c58cc19d8455988a0222987)) --- packages/w3c/CHANGELOG.md | 7 +++++++ packages/w3c/package.json | 10 +++++----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/packages/w3c/CHANGELOG.md b/packages/w3c/CHANGELOG.md index f7530877..b09fc209 100644 --- a/packages/w3c/CHANGELOG.md +++ b/packages/w3c/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.10](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.3.0-alpha.9...@trustvc/w3c@1.3.0-alpha.10) (2025-09-02) + + +### Bug Fixes + +* update package lock ([#80](https://github.com/TrustVC/w3c/issues/80)) ([8b7f586](https://github.com/TrustVC/w3c/commit/8b7f586bb1f7736a0c58cc19d8455988a0222987)) + # [1.3.0-alpha.9](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.3.0-alpha.8...@trustvc/w3c@1.3.0-alpha.9) (2025-08-27) diff --git a/packages/w3c/package.json b/packages/w3c/package.json index ce1a7193..5ca432c7 100644 --- a/packages/w3c/package.json +++ b/packages/w3c/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c", - "version": "1.3.0-alpha.9", + "version": "1.3.0-alpha.10", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", @@ -32,10 +32,10 @@ } }, "dependencies": { - "@trustvc/w3c-context": "^1.3.0-alpha.8", - "@trustvc/w3c-credential-status": "^1.3.0-alpha.8", - "@trustvc/w3c-issuer": "^1.3.0-alpha.6", - "@trustvc/w3c-vc": "^1.3.0-alpha.9" + "@trustvc/w3c-context": "^1.3.0-alpha.9", + "@trustvc/w3c-credential-status": "^1.3.0-alpha.9", + "@trustvc/w3c-issuer": "^1.3.0-alpha.7", + "@trustvc/w3c-vc": "^1.3.0-alpha.10" }, "repository": { "type": "git", From 5130d91079e67c2fc2b4dbf948995e930bc2ed12 Mon Sep 17 00:00:00 2001 From: rongquan1 <85145303+rongquan1@users.noreply.github.com> Date: Wed, 10 Sep 2025 13:05:27 +0800 Subject: [PATCH 087/122] fix: add derivation support for ecdsa bitstring vc (#81) --- package-lock.json | 36 +++++++++---------- .../src/lib/verify/credentialStatus/index.ts | 29 ++++++++++----- 2 files changed, 39 insertions(+), 26 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0cd2e2c0..8e21a4fb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -115,14 +115,14 @@ }, "apps/w3c-cli": { "name": "@trustvc/w3c-cli", - "version": "1.3.0-alpha.9", + "version": "1.3.0-alpha.10", "license": "Apache-2.0", "dependencies": { "@inquirer/prompts": "^5.3.8", - "@trustvc/w3c-context": "^1.3.0-alpha.8", - "@trustvc/w3c-credential-status": "^1.3.0-alpha.8", - "@trustvc/w3c-issuer": "^1.3.0-alpha.6", - "@trustvc/w3c-vc": "^1.3.0-alpha.9", + "@trustvc/w3c-context": "^1.3.0-alpha.9", + "@trustvc/w3c-credential-status": "^1.3.0-alpha.9", + "@trustvc/w3c-issuer": "^1.3.0-alpha.7", + "@trustvc/w3c-vc": "^1.3.0-alpha.10", "@types/yargs": "^17.0.32", "chalk": "^4.1.2", "inquirer": "^10.0.1", @@ -32819,13 +32819,13 @@ }, "packages/w3c": { "name": "@trustvc/w3c", - "version": "1.3.0-alpha.9", + "version": "1.3.0-alpha.10", "license": "Apache-2.0", "dependencies": { - "@trustvc/w3c-context": "^1.3.0-alpha.8", - "@trustvc/w3c-credential-status": "^1.3.0-alpha.8", - "@trustvc/w3c-issuer": "^1.3.0-alpha.6", - "@trustvc/w3c-vc": "^1.3.0-alpha.9" + "@trustvc/w3c-context": "^1.3.0-alpha.9", + "@trustvc/w3c-credential-status": "^1.3.0-alpha.9", + "@trustvc/w3c-issuer": "^1.3.0-alpha.7", + "@trustvc/w3c-vc": "^1.3.0-alpha.10" }, "engines": { "node": ">=18.x" @@ -32833,7 +32833,7 @@ }, "packages/w3c-context": { "name": "@trustvc/w3c-context", - "version": "1.3.0-alpha.8", + "version": "1.3.0-alpha.9", "license": "Apache-2.0", "dependencies": { "did-resolver": "^4.1.0", @@ -32925,11 +32925,11 @@ }, "packages/w3c-credential-status": { "name": "@trustvc/w3c-credential-status", - "version": "1.3.0-alpha.8", + "version": "1.3.0-alpha.9", "license": "Apache-2.0", "dependencies": { - "@trustvc/w3c-context": "^1.3.0-alpha.8", - "@trustvc/w3c-issuer": "^1.3.0-alpha.6", + "@trustvc/w3c-context": "^1.3.0-alpha.9", + "@trustvc/w3c-issuer": "^1.3.0-alpha.7", "base64url-universal": "^2.0.0", "pako": "^2.1.0" }, @@ -32939,7 +32939,7 @@ }, "packages/w3c-issuer": { "name": "@trustvc/w3c-issuer", - "version": "1.3.0-alpha.6", + "version": "1.3.0-alpha.7", "license": "Apache-2.0", "dependencies": { "@digitalbazaar/bls12-381-multikey": "^2.1.0", @@ -32956,15 +32956,15 @@ }, "packages/w3c-vc": { "name": "@trustvc/w3c-vc", - "version": "1.3.0-alpha.9", + "version": "1.3.0-alpha.10", "license": "Apache-2.0", "dependencies": { "@digitalbazaar/data-integrity": "^2.5.0", "@digitalbazaar/ecdsa-multikey": "^1.8.0", "@digitalbazaar/ecdsa-sd-2023-cryptosuite": "^3.4.1", "@mattrglobal/jsonld-signatures-bbs": "^1.2.0", - "@trustvc/w3c-credential-status": "^1.3.0-alpha.8", - "@trustvc/w3c-issuer": "^1.3.0-alpha.6", + "@trustvc/w3c-credential-status": "^1.3.0-alpha.9", + "@trustvc/w3c-issuer": "^1.3.0-alpha.7", "base64url-universal": "^2.0.0", "cbor": "^9.0.2", "did-resolver": "^4.1.0", diff --git a/packages/w3c-vc/src/lib/verify/credentialStatus/index.ts b/packages/w3c-vc/src/lib/verify/credentialStatus/index.ts index 5d1bf256..31addf1d 100644 --- a/packages/w3c-vc/src/lib/verify/credentialStatus/index.ts +++ b/packages/w3c-vc/src/lib/verify/credentialStatus/index.ts @@ -9,7 +9,7 @@ import { } from '@trustvc/w3c-credential-status'; import { _checkCredentialStatus } from '../../helper'; import { CredentialStatus, CredentialStatusResult } from './types'; -import { verifyCredential } from '../../w3c-vc'; +import { deriveCredential, verifyCredential } from '../../w3c-vc'; import { SignedVerifiableCredential } from '../../types'; import { DocumentLoader } from '@trustvc/w3c-context'; @@ -52,14 +52,27 @@ export const verifyCredentialStatus = async ( assertStatusListIndexWithinRange(bitstringStatusList, index); // Check if the statusListCredential is valid - const vcStatusListVerificationResult = await verifyCredential(vcStatusList, options); + const DERIVE_CREDENTIAL_ERROR = 'Use deriveCredential() first'; + let vcStatusListVerificationResult = await verifyCredential(vcStatusList, options); + + // Handle ECDSA-SD-2023 base credentials that need derivation before verification + if ( + !vcStatusListVerificationResult?.verified && + vcStatusListVerificationResult.error?.includes(DERIVE_CREDENTIAL_ERROR) + ) { + const derivedResult = await deriveCredential(vcStatusList, []); + vcStatusListVerificationResult = await verifyCredential(derivedResult.derived, options); + } + + // Throw error if verification still fails if (!vcStatusListVerificationResult?.verified) { - console.error( - `Failed to verify Credential Status VC: ${vcStatusListVerificationResult.verified}. Error: ${vcStatusListVerificationResult.error}`, - ); - throw new Error( - `Failed to verify Credential Status VC: ${vcStatusListVerificationResult.verified}`, - ); + const errorMessage = `Failed to verify Credential Status VC: ${vcStatusListVerificationResult.verified}`; + const detailedError = vcStatusListVerificationResult.error + ? `. Error: ${vcStatusListVerificationResult.error}` + : ''; + + console.error(errorMessage + detailedError); + throw new Error(errorMessage); } const status = bitstringStatusList.getStatus(index); From 9e7c2bb7b932b043ccb0aded143574f5a669a934 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 10 Sep 2025 05:08:06 +0000 Subject: [PATCH 088/122] chore(release): @trustvc/w3c-issuer@1.3.0-alpha.8 [skip ci] # [1.3.0-alpha.8](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-issuer@1.3.0-alpha.7...@trustvc/w3c-issuer@1.3.0-alpha.8) (2025-09-10) ### Bug Fixes * add derivation support for ecdsa bitstring vc ([#81](https://github.com/TrustVC/w3c/issues/81)) ([5130d91](https://github.com/TrustVC/w3c/commit/5130d91079e67c2fc2b4dbf948995e930bc2ed12)) --- packages/w3c-issuer/CHANGELOG.md | 7 +++++++ packages/w3c-issuer/package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/w3c-issuer/CHANGELOG.md b/packages/w3c-issuer/CHANGELOG.md index c9965814..195c7ed7 100644 --- a/packages/w3c-issuer/CHANGELOG.md +++ b/packages/w3c-issuer/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.8](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-issuer@1.3.0-alpha.7...@trustvc/w3c-issuer@1.3.0-alpha.8) (2025-09-10) + + +### Bug Fixes + +* add derivation support for ecdsa bitstring vc ([#81](https://github.com/TrustVC/w3c/issues/81)) ([5130d91](https://github.com/TrustVC/w3c/commit/5130d91079e67c2fc2b4dbf948995e930bc2ed12)) + # [1.3.0-alpha.7](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-issuer@1.3.0-alpha.6...@trustvc/w3c-issuer@1.3.0-alpha.7) (2025-09-02) diff --git a/packages/w3c-issuer/package.json b/packages/w3c-issuer/package.json index 7478d32c..eeebc934 100644 --- a/packages/w3c-issuer/package.json +++ b/packages/w3c-issuer/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c-issuer", - "version": "1.3.0-alpha.7", + "version": "1.3.0-alpha.8", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", From 4e445914afec57eed8066d24dbf7f8e1a3a8b299 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 10 Sep 2025 05:08:37 +0000 Subject: [PATCH 089/122] chore(release): @trustvc/w3c-context@1.3.0-alpha.10 [skip ci] # [1.3.0-alpha.10](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-context@1.3.0-alpha.9...@trustvc/w3c-context@1.3.0-alpha.10) (2025-09-10) ### Bug Fixes * add derivation support for ecdsa bitstring vc ([#81](https://github.com/TrustVC/w3c/issues/81)) ([5130d91](https://github.com/TrustVC/w3c/commit/5130d91079e67c2fc2b4dbf948995e930bc2ed12)) --- packages/w3c-context/CHANGELOG.md | 7 +++++++ packages/w3c-context/package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/w3c-context/CHANGELOG.md b/packages/w3c-context/CHANGELOG.md index 02b59094..faf7a84d 100644 --- a/packages/w3c-context/CHANGELOG.md +++ b/packages/w3c-context/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.10](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-context@1.3.0-alpha.9...@trustvc/w3c-context@1.3.0-alpha.10) (2025-09-10) + + +### Bug Fixes + +* add derivation support for ecdsa bitstring vc ([#81](https://github.com/TrustVC/w3c/issues/81)) ([5130d91](https://github.com/TrustVC/w3c/commit/5130d91079e67c2fc2b4dbf948995e930bc2ed12)) + # [1.3.0-alpha.9](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-context@1.3.0-alpha.8...@trustvc/w3c-context@1.3.0-alpha.9) (2025-09-02) diff --git a/packages/w3c-context/package.json b/packages/w3c-context/package.json index f1d6d9f4..c1d7e6ea 100644 --- a/packages/w3c-context/package.json +++ b/packages/w3c-context/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c-context", - "version": "1.3.0-alpha.9", + "version": "1.3.0-alpha.10", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", From 12021bb2e29b33ac9470e070e0a02873c8cfe727 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 10 Sep 2025 05:09:08 +0000 Subject: [PATCH 090/122] chore(release): @trustvc/w3c-credential-status@1.3.0-alpha.10 [skip ci] # [1.3.0-alpha.10](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-credential-status@1.3.0-alpha.9...@trustvc/w3c-credential-status@1.3.0-alpha.10) (2025-09-10) ### Bug Fixes * add derivation support for ecdsa bitstring vc ([#81](https://github.com/TrustVC/w3c/issues/81)) ([5130d91](https://github.com/TrustVC/w3c/commit/5130d91079e67c2fc2b4dbf948995e930bc2ed12)) --- packages/w3c-credential-status/CHANGELOG.md | 7 +++++++ packages/w3c-credential-status/package.json | 6 +++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/packages/w3c-credential-status/CHANGELOG.md b/packages/w3c-credential-status/CHANGELOG.md index 99b0a31f..619f1469 100644 --- a/packages/w3c-credential-status/CHANGELOG.md +++ b/packages/w3c-credential-status/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.10](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-credential-status@1.3.0-alpha.9...@trustvc/w3c-credential-status@1.3.0-alpha.10) (2025-09-10) + + +### Bug Fixes + +* add derivation support for ecdsa bitstring vc ([#81](https://github.com/TrustVC/w3c/issues/81)) ([5130d91](https://github.com/TrustVC/w3c/commit/5130d91079e67c2fc2b4dbf948995e930bc2ed12)) + # [1.3.0-alpha.9](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-credential-status@1.3.0-alpha.8...@trustvc/w3c-credential-status@1.3.0-alpha.9) (2025-09-02) diff --git a/packages/w3c-credential-status/package.json b/packages/w3c-credential-status/package.json index 0b720b25..44e1c031 100644 --- a/packages/w3c-credential-status/package.json +++ b/packages/w3c-credential-status/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c-credential-status", - "version": "1.3.0-alpha.9", + "version": "1.3.0-alpha.10", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", @@ -29,8 +29,8 @@ } }, "dependencies": { - "@trustvc/w3c-context": "^1.3.0-alpha.9", - "@trustvc/w3c-issuer": "^1.3.0-alpha.7", + "@trustvc/w3c-context": "^1.3.0-alpha.10", + "@trustvc/w3c-issuer": "^1.3.0-alpha.8", "base64url-universal": "^2.0.0", "pako": "^2.1.0" }, From 3a5f47c8ad5960f1285a63756fb767d4aa5e6f28 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 10 Sep 2025 05:09:40 +0000 Subject: [PATCH 091/122] chore(release): @trustvc/w3c-vc@1.3.0-alpha.11 [skip ci] # [1.3.0-alpha.11](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.3.0-alpha.10...@trustvc/w3c-vc@1.3.0-alpha.11) (2025-09-10) ### Bug Fixes * add derivation support for ecdsa bitstring vc ([#81](https://github.com/TrustVC/w3c/issues/81)) ([5130d91](https://github.com/TrustVC/w3c/commit/5130d91079e67c2fc2b4dbf948995e930bc2ed12)) --- packages/w3c-vc/CHANGELOG.md | 7 +++++++ packages/w3c-vc/package.json | 6 +++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/packages/w3c-vc/CHANGELOG.md b/packages/w3c-vc/CHANGELOG.md index c87e90dc..4b41703e 100644 --- a/packages/w3c-vc/CHANGELOG.md +++ b/packages/w3c-vc/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.11](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.3.0-alpha.10...@trustvc/w3c-vc@1.3.0-alpha.11) (2025-09-10) + + +### Bug Fixes + +* add derivation support for ecdsa bitstring vc ([#81](https://github.com/TrustVC/w3c/issues/81)) ([5130d91](https://github.com/TrustVC/w3c/commit/5130d91079e67c2fc2b4dbf948995e930bc2ed12)) + # [1.3.0-alpha.10](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.3.0-alpha.9...@trustvc/w3c-vc@1.3.0-alpha.10) (2025-09-02) diff --git a/packages/w3c-vc/package.json b/packages/w3c-vc/package.json index d8a4a93f..33ea9ff4 100644 --- a/packages/w3c-vc/package.json +++ b/packages/w3c-vc/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c-vc", - "version": "1.3.0-alpha.10", + "version": "1.3.0-alpha.11", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", @@ -35,8 +35,8 @@ "@digitalbazaar/ecdsa-multikey": "^1.8.0", "@digitalbazaar/ecdsa-sd-2023-cryptosuite": "^3.4.1", "@mattrglobal/jsonld-signatures-bbs": "^1.2.0", - "@trustvc/w3c-credential-status": "^1.3.0-alpha.9", - "@trustvc/w3c-issuer": "^1.3.0-alpha.7", + "@trustvc/w3c-credential-status": "^1.3.0-alpha.10", + "@trustvc/w3c-issuer": "^1.3.0-alpha.8", "base64url-universal": "^2.0.0", "cbor": "^9.0.2", "did-resolver": "^4.1.0", From 4365761d6fff5270c724c7a857bf088219cca183 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 10 Sep 2025 05:10:10 +0000 Subject: [PATCH 092/122] chore(release): @trustvc/w3c-cli@1.3.0-alpha.11 [skip ci] # [1.3.0-alpha.11](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-cli@1.3.0-alpha.10...@trustvc/w3c-cli@1.3.0-alpha.11) (2025-09-10) ### Bug Fixes * add derivation support for ecdsa bitstring vc ([#81](https://github.com/TrustVC/w3c/issues/81)) ([5130d91](https://github.com/TrustVC/w3c/commit/5130d91079e67c2fc2b4dbf948995e930bc2ed12)) --- apps/w3c-cli/CHANGELOG.md | 7 +++++++ apps/w3c-cli/package.json | 10 +++++----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/apps/w3c-cli/CHANGELOG.md b/apps/w3c-cli/CHANGELOG.md index 8e1e1a72..b553789d 100644 --- a/apps/w3c-cli/CHANGELOG.md +++ b/apps/w3c-cli/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.11](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-cli@1.3.0-alpha.10...@trustvc/w3c-cli@1.3.0-alpha.11) (2025-09-10) + + +### Bug Fixes + +* add derivation support for ecdsa bitstring vc ([#81](https://github.com/TrustVC/w3c/issues/81)) ([5130d91](https://github.com/TrustVC/w3c/commit/5130d91079e67c2fc2b4dbf948995e930bc2ed12)) + # [1.3.0-alpha.10](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-cli@1.3.0-alpha.9...@trustvc/w3c-cli@1.3.0-alpha.10) (2025-09-02) diff --git a/apps/w3c-cli/package.json b/apps/w3c-cli/package.json index b7b62c8c..5a68106a 100644 --- a/apps/w3c-cli/package.json +++ b/apps/w3c-cli/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c-cli", - "version": "1.3.0-alpha.10", + "version": "1.3.0-alpha.11", "description": "CLI for TrustVC W3C", "main": "dist/main.js", "types": "dist/main.d.ts", @@ -34,10 +34,10 @@ }, "dependencies": { "@inquirer/prompts": "^5.3.8", - "@trustvc/w3c-context": "^1.3.0-alpha.9", - "@trustvc/w3c-credential-status": "^1.3.0-alpha.9", - "@trustvc/w3c-vc": "^1.3.0-alpha.10", - "@trustvc/w3c-issuer": "^1.3.0-alpha.7", + "@trustvc/w3c-context": "^1.3.0-alpha.10", + "@trustvc/w3c-credential-status": "^1.3.0-alpha.10", + "@trustvc/w3c-vc": "^1.3.0-alpha.11", + "@trustvc/w3c-issuer": "^1.3.0-alpha.8", "@types/yargs": "^17.0.32", "chalk": "^4.1.2", "inquirer": "^10.0.1", From 07b5fbe06c8895c9f3083b5387887627a7d1426d Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 10 Sep 2025 05:10:41 +0000 Subject: [PATCH 093/122] chore(release): @trustvc/w3c@1.3.0-alpha.11 [skip ci] # [1.3.0-alpha.11](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.3.0-alpha.10...@trustvc/w3c@1.3.0-alpha.11) (2025-09-10) ### Bug Fixes * add derivation support for ecdsa bitstring vc ([#81](https://github.com/TrustVC/w3c/issues/81)) ([5130d91](https://github.com/TrustVC/w3c/commit/5130d91079e67c2fc2b4dbf948995e930bc2ed12)) --- packages/w3c/CHANGELOG.md | 7 +++++++ packages/w3c/package.json | 10 +++++----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/packages/w3c/CHANGELOG.md b/packages/w3c/CHANGELOG.md index b09fc209..ee094333 100644 --- a/packages/w3c/CHANGELOG.md +++ b/packages/w3c/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.11](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.3.0-alpha.10...@trustvc/w3c@1.3.0-alpha.11) (2025-09-10) + + +### Bug Fixes + +* add derivation support for ecdsa bitstring vc ([#81](https://github.com/TrustVC/w3c/issues/81)) ([5130d91](https://github.com/TrustVC/w3c/commit/5130d91079e67c2fc2b4dbf948995e930bc2ed12)) + # [1.3.0-alpha.10](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.3.0-alpha.9...@trustvc/w3c@1.3.0-alpha.10) (2025-09-02) diff --git a/packages/w3c/package.json b/packages/w3c/package.json index 5ca432c7..21cf5a5a 100644 --- a/packages/w3c/package.json +++ b/packages/w3c/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c", - "version": "1.3.0-alpha.10", + "version": "1.3.0-alpha.11", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", @@ -32,10 +32,10 @@ } }, "dependencies": { - "@trustvc/w3c-context": "^1.3.0-alpha.9", - "@trustvc/w3c-credential-status": "^1.3.0-alpha.9", - "@trustvc/w3c-issuer": "^1.3.0-alpha.7", - "@trustvc/w3c-vc": "^1.3.0-alpha.10" + "@trustvc/w3c-context": "^1.3.0-alpha.10", + "@trustvc/w3c-credential-status": "^1.3.0-alpha.10", + "@trustvc/w3c-issuer": "^1.3.0-alpha.8", + "@trustvc/w3c-vc": "^1.3.0-alpha.11" }, "repository": { "type": "git", From 493a24876ee39500c659a884caf6e8d82d8c4f56 Mon Sep 17 00:00:00 2001 From: Moiz Shaikh <58319530+Moiz47@users.noreply.github.com> Date: Wed, 24 Sep 2025 08:57:12 +0530 Subject: [PATCH 094/122] feat: add resolve, resolveRepresentation and dereference functions (#87) Co-authored-by: moiz-sgtradex --- packages/w3c-issuer/src/did-web/index.ts | 4 +- .../src/did-web/wellKnown/query.test.ts | 156 +++++++++++++++++- .../w3c-issuer/src/did-web/wellKnown/query.ts | 151 ++++++++++++++++- 3 files changed, 307 insertions(+), 4 deletions(-) diff --git a/packages/w3c-issuer/src/did-web/index.ts b/packages/w3c-issuer/src/did-web/index.ts index a5c7ec2d..d4e21575 100644 --- a/packages/w3c-issuer/src/did-web/index.ts +++ b/packages/w3c-issuer/src/did-web/index.ts @@ -1,7 +1,7 @@ import { generateKeyPair } from './keyPair'; import { issueDID } from './wellKnown'; -import { queryDidDocument } from './wellKnown/query'; +import { queryDidDocument, resolve, resolveRepresentation, dereference } from './wellKnown/query'; export * from './keyPair/types'; export * from './wellKnown/types'; -export { generateKeyPair, issueDID, queryDidDocument }; +export { generateKeyPair, issueDID, queryDidDocument, resolve, resolveRepresentation, dereference }; diff --git a/packages/w3c-issuer/src/did-web/wellKnown/query.test.ts b/packages/w3c-issuer/src/did-web/wellKnown/query.test.ts index 1aff72bb..4747245d 100644 --- a/packages/w3c-issuer/src/did-web/wellKnown/query.test.ts +++ b/packages/w3c-issuer/src/did-web/wellKnown/query.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from 'vitest'; -import { queryDidDocument } from './query'; +import { queryDidDocument, resolve, resolveRepresentation, dereference } from './query'; describe('query', () => { describe('queryDidDocument', () => { @@ -33,18 +33,22 @@ describe('query', () => { "assertionMethod": [ "did:web:trustvc.github.io:did:1#keys-1", "did:web:trustvc.github.io:did:1#multikey-1", + "did:web:trustvc.github.io:did:1#multikey-2", ], "authentication": [ "did:web:trustvc.github.io:did:1#keys-1", "did:web:trustvc.github.io:did:1#multikey-1", + "did:web:trustvc.github.io:did:1#multikey-2", ], "capabilityDelegation": [ "did:web:trustvc.github.io:did:1#keys-1", "did:web:trustvc.github.io:did:1#multikey-1", + "did:web:trustvc.github.io:did:1#multikey-2", ], "capabilityInvocation": [ "did:web:trustvc.github.io:did:1#keys-1", "did:web:trustvc.github.io:did:1#multikey-1", + "did:web:trustvc.github.io:did:1#multikey-2", ], "id": "did:web:trustvc.github.io:did:1", "verificationMethod": [ @@ -60,10 +64,160 @@ describe('query', () => { "publicKeyMultibase": "zDnaemDNwi4G5eTzGfRooFFu5Kns3be6yfyVNtiaMhWkZbwtc", "type": "Multikey", }, + { + "controller": "did:web:trustvc.github.io:did:1", + "id": "did:web:trustvc.github.io:did:1#multikey-2", + "publicKeyMultibase": "zUC7HnpncVAkTjtL6B8prX6bQM2WA5sJ7rXFeCqyrvPnrzoFBjYsVUTNwzhhPUazja73tWwPeEBWCUgq5qBSrtrXiYhVvBCgZPTCiWANj7TSiZJ6SnyC3pkt94GiuChhAvmRRbt", + "type": "Multikey", + }, ], } `); expect(did).toBe('did:web:trustvc.github.io:did:1'); }); }); + + describe('resolve', () => { + it('should resolve did', async () => { + const did = 'did:web:trustvc.github.io:did:1'; + const result = await resolve(did); + expect(result.didDocument).toMatchInlineSnapshot(` + { + "@context": [ + "https://www.w3.org/ns/did/v1", + "https://w3id.org/security/suites/bls12381-2020/v1", + "https://w3id.org/security/multikey/v1", + ], + "assertionMethod": [ + "did:web:trustvc.github.io:did:1#keys-1", + "did:web:trustvc.github.io:did:1#multikey-1", + "did:web:trustvc.github.io:did:1#multikey-2", + ], + "authentication": [ + "did:web:trustvc.github.io:did:1#keys-1", + "did:web:trustvc.github.io:did:1#multikey-1", + "did:web:trustvc.github.io:did:1#multikey-2", + ], + "capabilityDelegation": [ + "did:web:trustvc.github.io:did:1#keys-1", + "did:web:trustvc.github.io:did:1#multikey-1", + "did:web:trustvc.github.io:did:1#multikey-2", + ], + "capabilityInvocation": [ + "did:web:trustvc.github.io:did:1#keys-1", + "did:web:trustvc.github.io:did:1#multikey-1", + "did:web:trustvc.github.io:did:1#multikey-2", + ], + "id": "did:web:trustvc.github.io:did:1", + "verificationMethod": [ + { + "controller": "did:web:trustvc.github.io:did:1", + "id": "did:web:trustvc.github.io:did:1#keys-1", + "publicKeyBase58": "oRfEeWFresvhRtXCkihZbxyoi2JER7gHTJ5psXhHsdCoU1MttRMi3Yp9b9fpjmKh7bMgfWKLESiK2YovRd8KGzJsGuamoAXfqDDVhckxuc9nmsJ84skCSTijKeU4pfAcxeJ", + "type": "Bls12381G2Key2020", + }, + { + "controller": "did:web:trustvc.github.io:did:1", + "id": "did:web:trustvc.github.io:did:1#multikey-1", + "publicKeyMultibase": "zDnaemDNwi4G5eTzGfRooFFu5Kns3be6yfyVNtiaMhWkZbwtc", + "type": "Multikey", + }, + { + "controller": "did:web:trustvc.github.io:did:1", + "id": "did:web:trustvc.github.io:did:1#multikey-2", + "publicKeyMultibase": "zUC7HnpncVAkTjtL6B8prX6bQM2WA5sJ7rXFeCqyrvPnrzoFBjYsVUTNwzhhPUazja73tWwPeEBWCUgq5qBSrtrXiYhVvBCgZPTCiWANj7TSiZJ6SnyC3pkt94GiuChhAvmRRbt", + "type": "Multikey", + }, + ], + } + `); + }); + + it('should return notFound error for unresolvable did', async () => { + const did = 'did:web:trustvc2.github.io:did:1'; + const result = await resolve(did); + expect(result.didDocument).toBeNull(); + expect(result.didResolutionMetadata).toHaveProperty('error', 'notFound'); + }); + + it('should return inValidDid error for invalid did', async () => { + const did = 'did:web: trustvc .github.io:did:1'; + const result = await resolve(did); + expect(result.didDocument).toBeNull(); + expect(result.didResolutionMetadata).toHaveProperty('error', 'invalidDid'); + }); + }); + + describe('resolveRepresentation', () => { + it('Should return serialized data for valid did and should contain contentType', async () => { + const did = 'did:web:trustvc.github.io:did:1'; + const result = await resolveRepresentation(did); + + expect(result.didDocumentStream).toBeTruthy(); + expect(typeof result.didDocumentStream).toBe('string'); + const parsedDocument = JSON.parse(result.didDocumentStream); + expect(parsedDocument).toHaveProperty('@context'); + expect(result.didResolutionMetadata).toHaveProperty('contentType', 'application/did+ld+json'); + }); + + it('Should return correct contentType for requested accept value', async () => { + const did = 'did:web:trustvc.github.io:did:1'; + const result = await resolveRepresentation(did, { accept: 'application/did+json' }); + + expect(result.didDocumentStream).toBeTruthy(); + expect(typeof result.didDocumentStream).toBe('string'); + const parsedDocument = JSON.parse(result.didDocumentStream); + expect(parsedDocument).not.toHaveProperty('@context'); + expect(result.didResolutionMetadata).toHaveProperty('contentType', 'application/did+json'); + }); + + it('Should return representationNotSupported error for unsupported accept value', async () => { + const did = 'did:web:trustvc.github.io:did:1'; + const result = await resolveRepresentation(did, { accept: 'application/did+cbor' }); + + expect(result).toEqual({ + didResolutionMetadata: { + error: 'representationNotSupported', + message: 'Content type application/did+cbor is not supported.', + }, + didDocumentStream: '', + didDocumentMetadata: {}, + }); + }); + }); +}); + +describe('dereference', () => { + it('Should return serialized data for valid did', async () => { + const did = 'did:web:trustvc.github.io:did:1'; + const result = await dereference(did); + + expect(result.contentStream).toBeTruthy(); + expect(typeof result.contentStream).toBe('string'); + const parsedDocument = JSON.parse(result.contentStream); + expect(parsedDocument).toHaveProperty('@context'); + expect(result.dereferencingMetadata).toHaveProperty('contentType', 'application/did+ld+json'); + }); + + it('Should return valid verification method for a given fragment', async () => { + const did = 'did:web:trustvc.github.io:did:1#multikey-1'; + const result = await dereference(did); + + expect(result.contentStream).toBe( + '{"id":"did:web:trustvc.github.io:did:1#multikey-1","type":"Multikey","controller":"did:web:trustvc.github.io:did:1","publicKeyMultibase":"zDnaemDNwi4G5eTzGfRooFFu5Kns3be6yfyVNtiaMhWkZbwtc"}', + ); + expect(result.dereferencingMetadata).toHaveProperty('contentType', 'application/did+ld+json'); + }); + + it('Should return notFound for query or path based dereferencing', async () => { + const didWithPath = 'did:web:trustvc.github.io:did:1/path'; + const resultWithPath = await dereference(didWithPath); + expect(resultWithPath.dereferencingMetadata).toHaveProperty('error', 'notFound'); + expect(resultWithPath.contentStream).toBe(''); + + const didWithQuery = 'did:web:trustvc.github.io:did:1?query=param'; + const resultWithQuery = await dereference(didWithQuery); + expect(resultWithQuery.dereferencingMetadata).toHaveProperty('error', 'notFound'); + expect(resultWithQuery.contentStream).toBe(''); + }); }); diff --git a/packages/w3c-issuer/src/did-web/wellKnown/query.ts b/packages/w3c-issuer/src/did-web/wellKnown/query.ts index 30323b96..9c6a009e 100644 --- a/packages/w3c-issuer/src/did-web/wellKnown/query.ts +++ b/packages/w3c-issuer/src/did-web/wellKnown/query.ts @@ -1,8 +1,15 @@ -import { Resolver } from 'did-resolver'; +import { Resolver, DIDResolutionResult, DIDResolutionOptions } from 'did-resolver'; import { getResolver as webGetResolver } from 'web-did-resolver'; import { getDomain } from '../../lib'; import { DidWellKnownDocument, QueryDidDocument, QueryDidDocumentOption } from './types'; +const SUPPORTED_CONTENT_TYPES = ['application/did+json', 'application/did+ld+json']; +const getResolver = (): Resolver => { + return new Resolver({ + ...webGetResolver(), + }); +}; + /** * Query well known DID document based on the domain. * @@ -41,3 +48,145 @@ export const queryDidDocument = async ({ did, }; }; + +/** + * Resolves a DID to a DID Document according to the W3C DID Core specification. + * This function implements the `resolve` operation which returns the DID document as a data model. + * + * @param did - The DID to resolve + * @returns A DID Resolution Result without contentType in the metadata + */ +export const resolve = async (did: string): Promise => { + try { + const resolver = getResolver(); + const doc: DIDResolutionResult = await resolver.resolve(did); + + if (doc.didResolutionMetadata && 'contentType' in doc.didResolutionMetadata) { + delete doc.didResolutionMetadata.contentType; + } + + return doc; + } catch { + throw new Error('Failed to resolve did'); + } +}; + +/** + * Resolves a DID to a DID Document representation according to the W3C DID Core specification. + * This function implements the `resolveRepresentation` operation which returns the DID document as a byte stream. + * + * @param did - The DID to resolve + * @param resolutionOptions - Options for resolution, including accept for content negotiation + * @returns A DID Resolution Result with the document as a string and contentType in the metadata + */ +export const resolveRepresentation = async ( + did: string, + resolutionOptions?: DIDResolutionOptions, +) => { + const { accept } = resolutionOptions || {}; + + if (accept && !SUPPORTED_CONTENT_TYPES.includes(accept)) { + return { + didResolutionMetadata: { + error: 'representationNotSupported', + message: `Content type ${accept} is not supported.`, + }, + didDocumentStream: '', + didDocumentMetadata: {}, + }; + } + + try { + const resolver = getResolver(); + const doc = await resolver.resolve(did, { accept }); + const { didDocument, didResolutionMetadata, ...rest } = doc; + if (didDocument && accept === 'application/did+json') { + delete didDocument['@context']; + } + + const response = { + ...rest, + didDocumentStream: didDocument ? JSON.stringify(didDocument) : '', + didResolutionMetadata, + }; + + if (!didResolutionMetadata.error) { + response.didResolutionMetadata.contentType = accept ?? didResolutionMetadata.contentType; + } + + return response; + } catch { + throw new Error('Failed to resolve did'); + } +}; + +/** + * Dereferences a DID URL to a resource according to the W3C DID Core specification. + * This function handles fragment-based dereferencing to retrieve verification methods. + * + * @param did - The DID URL to dereference (may include a fragment) + * @param dereferenceOptions - Options for dereferencing, including accept for content negotiation + * @returns A DID Dereferencing Result with the resource as a string + */ +export const dereference = async (did: string, dereferenceOptions?: DIDResolutionOptions) => { + const { accept } = dereferenceOptions || {}; + + const isInvalidRequest = + (accept && !SUPPORTED_CONTENT_TYPES.includes(accept)) || did.includes('?') || did.includes('/'); + + if (isInvalidRequest) { + return { + dereferencingMetadata: { error: 'notFound' }, + contentStream: '', + contentMetadata: {}, + }; + } + + try { + const resolver = getResolver(); + const { + didDocument, + didResolutionMetadata: dereferencingMetadata, + didDocumentMetadata: contentMetadata, + } = await resolver.resolve(did, { accept }); + + if (dereferencingMetadata.error) { + const error = + dereferencingMetadata.error === 'invalidDid' + ? 'invalidDidUrl' + : dereferencingMetadata.error; + + return { + dereferencingMetadata: { ...dereferencingMetadata, error }, + contentStream: '', + contentMetadata, + }; + } + + dereferencingMetadata.contentType = accept ?? dereferencingMetadata.contentType; + + if (did.includes('#')) { + const verificationMethod = didDocument.verificationMethod?.find((vm) => vm.id === did); + if (verificationMethod) { + return { + contentStream: JSON.stringify(verificationMethod), + contentMetadata, + dereferencingMetadata, + }; + } + } + + const documentToReturn = { ...didDocument }; + if (documentToReturn && accept === 'application/did+json') { + delete documentToReturn['@context']; + } + + return { + contentStream: JSON.stringify(documentToReturn), + contentMetadata, + dereferencingMetadata, + }; + } catch { + throw new Error('Failed to dereference did'); + } +}; From 4302feb821833be3a4aa21d8384b6f2c4d371679 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 24 Sep 2025 03:29:57 +0000 Subject: [PATCH 095/122] chore(release): @trustvc/w3c-issuer@1.3.0-alpha.9 [skip ci] # [1.3.0-alpha.9](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-issuer@1.3.0-alpha.8...@trustvc/w3c-issuer@1.3.0-alpha.9) (2025-09-24) ### Features * add resolve, resolveRepresentation and dereference functions ([#87](https://github.com/TrustVC/w3c/issues/87)) ([493a248](https://github.com/TrustVC/w3c/commit/493a24876ee39500c659a884caf6e8d82d8c4f56)) --- packages/w3c-issuer/CHANGELOG.md | 7 +++++++ packages/w3c-issuer/package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/w3c-issuer/CHANGELOG.md b/packages/w3c-issuer/CHANGELOG.md index 195c7ed7..44105e12 100644 --- a/packages/w3c-issuer/CHANGELOG.md +++ b/packages/w3c-issuer/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.9](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-issuer@1.3.0-alpha.8...@trustvc/w3c-issuer@1.3.0-alpha.9) (2025-09-24) + + +### Features + +* add resolve, resolveRepresentation and dereference functions ([#87](https://github.com/TrustVC/w3c/issues/87)) ([493a248](https://github.com/TrustVC/w3c/commit/493a24876ee39500c659a884caf6e8d82d8c4f56)) + # [1.3.0-alpha.8](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-issuer@1.3.0-alpha.7...@trustvc/w3c-issuer@1.3.0-alpha.8) (2025-09-10) diff --git a/packages/w3c-issuer/package.json b/packages/w3c-issuer/package.json index eeebc934..96bfec66 100644 --- a/packages/w3c-issuer/package.json +++ b/packages/w3c-issuer/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c-issuer", - "version": "1.3.0-alpha.8", + "version": "1.3.0-alpha.9", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", From 7887d06ba8c7982bf97a8320069359ff07181b9d Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 24 Sep 2025 03:30:36 +0000 Subject: [PATCH 096/122] chore(release): @trustvc/w3c-context@1.3.0-alpha.11 [skip ci] # [1.3.0-alpha.11](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-context@1.3.0-alpha.10...@trustvc/w3c-context@1.3.0-alpha.11) (2025-09-24) ### Features * add resolve, resolveRepresentation and dereference functions ([#87](https://github.com/TrustVC/w3c/issues/87)) ([493a248](https://github.com/TrustVC/w3c/commit/493a24876ee39500c659a884caf6e8d82d8c4f56)) --- packages/w3c-context/CHANGELOG.md | 7 +++++++ packages/w3c-context/package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/w3c-context/CHANGELOG.md b/packages/w3c-context/CHANGELOG.md index faf7a84d..63b91485 100644 --- a/packages/w3c-context/CHANGELOG.md +++ b/packages/w3c-context/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.11](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-context@1.3.0-alpha.10...@trustvc/w3c-context@1.3.0-alpha.11) (2025-09-24) + + +### Features + +* add resolve, resolveRepresentation and dereference functions ([#87](https://github.com/TrustVC/w3c/issues/87)) ([493a248](https://github.com/TrustVC/w3c/commit/493a24876ee39500c659a884caf6e8d82d8c4f56)) + # [1.3.0-alpha.10](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-context@1.3.0-alpha.9...@trustvc/w3c-context@1.3.0-alpha.10) (2025-09-10) diff --git a/packages/w3c-context/package.json b/packages/w3c-context/package.json index c1d7e6ea..dfd8d5e0 100644 --- a/packages/w3c-context/package.json +++ b/packages/w3c-context/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c-context", - "version": "1.3.0-alpha.10", + "version": "1.3.0-alpha.11", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", From ccfd5a8ccb52ea564a5de38f4b735a6bb1f6f435 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 24 Sep 2025 03:31:17 +0000 Subject: [PATCH 097/122] chore(release): @trustvc/w3c-credential-status@1.3.0-alpha.11 [skip ci] # [1.3.0-alpha.11](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-credential-status@1.3.0-alpha.10...@trustvc/w3c-credential-status@1.3.0-alpha.11) (2025-09-24) ### Features * add resolve, resolveRepresentation and dereference functions ([#87](https://github.com/TrustVC/w3c/issues/87)) ([493a248](https://github.com/TrustVC/w3c/commit/493a24876ee39500c659a884caf6e8d82d8c4f56)) --- packages/w3c-credential-status/CHANGELOG.md | 7 +++++++ packages/w3c-credential-status/package.json | 6 +++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/packages/w3c-credential-status/CHANGELOG.md b/packages/w3c-credential-status/CHANGELOG.md index 619f1469..6a703376 100644 --- a/packages/w3c-credential-status/CHANGELOG.md +++ b/packages/w3c-credential-status/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.11](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-credential-status@1.3.0-alpha.10...@trustvc/w3c-credential-status@1.3.0-alpha.11) (2025-09-24) + + +### Features + +* add resolve, resolveRepresentation and dereference functions ([#87](https://github.com/TrustVC/w3c/issues/87)) ([493a248](https://github.com/TrustVC/w3c/commit/493a24876ee39500c659a884caf6e8d82d8c4f56)) + # [1.3.0-alpha.10](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-credential-status@1.3.0-alpha.9...@trustvc/w3c-credential-status@1.3.0-alpha.10) (2025-09-10) diff --git a/packages/w3c-credential-status/package.json b/packages/w3c-credential-status/package.json index 44e1c031..3e14219a 100644 --- a/packages/w3c-credential-status/package.json +++ b/packages/w3c-credential-status/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c-credential-status", - "version": "1.3.0-alpha.10", + "version": "1.3.0-alpha.11", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", @@ -29,8 +29,8 @@ } }, "dependencies": { - "@trustvc/w3c-context": "^1.3.0-alpha.10", - "@trustvc/w3c-issuer": "^1.3.0-alpha.8", + "@trustvc/w3c-context": "^1.3.0-alpha.11", + "@trustvc/w3c-issuer": "^1.3.0-alpha.9", "base64url-universal": "^2.0.0", "pako": "^2.1.0" }, From 2363530ca750de8d8358ef79c9fb583cc5503f30 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 24 Sep 2025 03:31:59 +0000 Subject: [PATCH 098/122] chore(release): @trustvc/w3c-vc@1.3.0-alpha.12 [skip ci] # [1.3.0-alpha.12](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.3.0-alpha.11...@trustvc/w3c-vc@1.3.0-alpha.12) (2025-09-24) ### Features * add resolve, resolveRepresentation and dereference functions ([#87](https://github.com/TrustVC/w3c/issues/87)) ([493a248](https://github.com/TrustVC/w3c/commit/493a24876ee39500c659a884caf6e8d82d8c4f56)) --- packages/w3c-vc/CHANGELOG.md | 7 +++++++ packages/w3c-vc/package.json | 6 +++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/packages/w3c-vc/CHANGELOG.md b/packages/w3c-vc/CHANGELOG.md index 4b41703e..6bcd41f8 100644 --- a/packages/w3c-vc/CHANGELOG.md +++ b/packages/w3c-vc/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.12](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.3.0-alpha.11...@trustvc/w3c-vc@1.3.0-alpha.12) (2025-09-24) + + +### Features + +* add resolve, resolveRepresentation and dereference functions ([#87](https://github.com/TrustVC/w3c/issues/87)) ([493a248](https://github.com/TrustVC/w3c/commit/493a24876ee39500c659a884caf6e8d82d8c4f56)) + # [1.3.0-alpha.11](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.3.0-alpha.10...@trustvc/w3c-vc@1.3.0-alpha.11) (2025-09-10) diff --git a/packages/w3c-vc/package.json b/packages/w3c-vc/package.json index 33ea9ff4..608aa22c 100644 --- a/packages/w3c-vc/package.json +++ b/packages/w3c-vc/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c-vc", - "version": "1.3.0-alpha.11", + "version": "1.3.0-alpha.12", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", @@ -35,8 +35,8 @@ "@digitalbazaar/ecdsa-multikey": "^1.8.0", "@digitalbazaar/ecdsa-sd-2023-cryptosuite": "^3.4.1", "@mattrglobal/jsonld-signatures-bbs": "^1.2.0", - "@trustvc/w3c-credential-status": "^1.3.0-alpha.10", - "@trustvc/w3c-issuer": "^1.3.0-alpha.8", + "@trustvc/w3c-credential-status": "^1.3.0-alpha.11", + "@trustvc/w3c-issuer": "^1.3.0-alpha.9", "base64url-universal": "^2.0.0", "cbor": "^9.0.2", "did-resolver": "^4.1.0", From 770ac1a71897bdff81d2c23a5721510ab9bbf7bc Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 24 Sep 2025 03:32:39 +0000 Subject: [PATCH 099/122] chore(release): @trustvc/w3c-cli@1.3.0-alpha.12 [skip ci] # [1.3.0-alpha.12](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-cli@1.3.0-alpha.11...@trustvc/w3c-cli@1.3.0-alpha.12) (2025-09-24) ### Features * add resolve, resolveRepresentation and dereference functions ([#87](https://github.com/TrustVC/w3c/issues/87)) ([493a248](https://github.com/TrustVC/w3c/commit/493a24876ee39500c659a884caf6e8d82d8c4f56)) --- apps/w3c-cli/CHANGELOG.md | 7 +++++++ apps/w3c-cli/package.json | 10 +++++----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/apps/w3c-cli/CHANGELOG.md b/apps/w3c-cli/CHANGELOG.md index b553789d..3047f1a7 100644 --- a/apps/w3c-cli/CHANGELOG.md +++ b/apps/w3c-cli/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.12](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-cli@1.3.0-alpha.11...@trustvc/w3c-cli@1.3.0-alpha.12) (2025-09-24) + + +### Features + +* add resolve, resolveRepresentation and dereference functions ([#87](https://github.com/TrustVC/w3c/issues/87)) ([493a248](https://github.com/TrustVC/w3c/commit/493a24876ee39500c659a884caf6e8d82d8c4f56)) + # [1.3.0-alpha.11](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-cli@1.3.0-alpha.10...@trustvc/w3c-cli@1.3.0-alpha.11) (2025-09-10) diff --git a/apps/w3c-cli/package.json b/apps/w3c-cli/package.json index 5a68106a..f0e7ca27 100644 --- a/apps/w3c-cli/package.json +++ b/apps/w3c-cli/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c-cli", - "version": "1.3.0-alpha.11", + "version": "1.3.0-alpha.12", "description": "CLI for TrustVC W3C", "main": "dist/main.js", "types": "dist/main.d.ts", @@ -34,10 +34,10 @@ }, "dependencies": { "@inquirer/prompts": "^5.3.8", - "@trustvc/w3c-context": "^1.3.0-alpha.10", - "@trustvc/w3c-credential-status": "^1.3.0-alpha.10", - "@trustvc/w3c-vc": "^1.3.0-alpha.11", - "@trustvc/w3c-issuer": "^1.3.0-alpha.8", + "@trustvc/w3c-context": "^1.3.0-alpha.11", + "@trustvc/w3c-credential-status": "^1.3.0-alpha.11", + "@trustvc/w3c-vc": "^1.3.0-alpha.12", + "@trustvc/w3c-issuer": "^1.3.0-alpha.9", "@types/yargs": "^17.0.32", "chalk": "^4.1.2", "inquirer": "^10.0.1", From e54756f1d81feb8aef5ac44836326b6df950991d Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 24 Sep 2025 03:33:19 +0000 Subject: [PATCH 100/122] chore(release): @trustvc/w3c@1.3.0-alpha.12 [skip ci] # [1.3.0-alpha.12](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.3.0-alpha.11...@trustvc/w3c@1.3.0-alpha.12) (2025-09-24) ### Features * add resolve, resolveRepresentation and dereference functions ([#87](https://github.com/TrustVC/w3c/issues/87)) ([493a248](https://github.com/TrustVC/w3c/commit/493a24876ee39500c659a884caf6e8d82d8c4f56)) --- packages/w3c/CHANGELOG.md | 7 +++++++ packages/w3c/package.json | 10 +++++----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/packages/w3c/CHANGELOG.md b/packages/w3c/CHANGELOG.md index ee094333..93c0d4cc 100644 --- a/packages/w3c/CHANGELOG.md +++ b/packages/w3c/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.12](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.3.0-alpha.11...@trustvc/w3c@1.3.0-alpha.12) (2025-09-24) + + +### Features + +* add resolve, resolveRepresentation and dereference functions ([#87](https://github.com/TrustVC/w3c/issues/87)) ([493a248](https://github.com/TrustVC/w3c/commit/493a24876ee39500c659a884caf6e8d82d8c4f56)) + # [1.3.0-alpha.11](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.3.0-alpha.10...@trustvc/w3c@1.3.0-alpha.11) (2025-09-10) diff --git a/packages/w3c/package.json b/packages/w3c/package.json index 21cf5a5a..da5e9aab 100644 --- a/packages/w3c/package.json +++ b/packages/w3c/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c", - "version": "1.3.0-alpha.11", + "version": "1.3.0-alpha.12", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", @@ -32,10 +32,10 @@ } }, "dependencies": { - "@trustvc/w3c-context": "^1.3.0-alpha.10", - "@trustvc/w3c-credential-status": "^1.3.0-alpha.10", - "@trustvc/w3c-issuer": "^1.3.0-alpha.8", - "@trustvc/w3c-vc": "^1.3.0-alpha.11" + "@trustvc/w3c-context": "^1.3.0-alpha.11", + "@trustvc/w3c-credential-status": "^1.3.0-alpha.11", + "@trustvc/w3c-issuer": "^1.3.0-alpha.9", + "@trustvc/w3c-vc": "^1.3.0-alpha.12" }, "repository": { "type": "git", From 082e6f0f1365ee7781816db4c4604e4a10073557 Mon Sep 17 00:00:00 2001 From: rongquan1 <85145303+rongquan1@users.noreply.github.com> Date: Wed, 24 Sep 2025 17:31:39 +0800 Subject: [PATCH 101/122] feat: bbs2023 implementation (#88) * feat: bbs2023 implementation * fix: nxignore * fix: update * docs: mark w3c-cli package as deprecated --- .nxignore | 1 + apps/w3c-cli/README.md | 8 + apps/w3c-cli/package.json | 3 +- .../{project.json => project.json.deprecated} | 4 + nx.json | 3 +- package-lock.json | 53 +- packages/declaration.d.ts | 1 + packages/w3c-vc/README.md | 427 ++++---- packages/w3c-vc/package.json | 2 + .../lib/__fixtures__/bbs2020-credentials.ts | 296 ++++++ .../w3c-vc/src/lib/__fixtures__/key-pairs.ts | 34 + .../lib/__fixtures__/modern-credentials.ts | 126 +++ .../src/lib/__fixtures__/test-scenarios.ts | 85 ++ packages/w3c-vc/src/lib/helper/index.ts | 8 +- packages/w3c-vc/src/lib/w3c-vc.test.ts | 914 ++++++------------ packages/w3c-vc/src/lib/w3c-vc.ts | 230 +++-- 16 files changed, 1318 insertions(+), 877 deletions(-) create mode 100644 .nxignore rename apps/w3c-cli/{project.json => project.json.deprecated} (64%) create mode 100644 packages/w3c-vc/src/lib/__fixtures__/bbs2020-credentials.ts create mode 100644 packages/w3c-vc/src/lib/__fixtures__/key-pairs.ts create mode 100644 packages/w3c-vc/src/lib/__fixtures__/modern-credentials.ts create mode 100644 packages/w3c-vc/src/lib/__fixtures__/test-scenarios.ts diff --git a/.nxignore b/.nxignore new file mode 100644 index 00000000..d01d4b12 --- /dev/null +++ b/.nxignore @@ -0,0 +1 @@ +apps/w3c-cli \ No newline at end of file diff --git a/apps/w3c-cli/README.md b/apps/w3c-cli/README.md index 6fc82ec6..ae75da31 100644 --- a/apps/w3c-cli/README.md +++ b/apps/w3c-cli/README.md @@ -1,5 +1,13 @@ # TrustVC W3C CLI +> **⚠️ DEPRECATED PACKAGE** +> +> This CLI package has been deprecated and is no longer maintained. The CLI was built using legacy BBS+ cryptosuites that have been superseded by modern W3C Data Integrity cryptosuites (ECDSA-SD-2023, BBS-2023). + +--- + +## Legacy Documentation + `w3c-cli` is a command-line interface tool designed to demonstrate how to interact with Verifiable Credentials (VCs) and Decentralized Identifiers (DIDs) using functions from the following repositories: - [`w3c-issuer`](https://github.com/TrustVC/w3c/tree/main/packages/w3c-issuer) diff --git a/apps/w3c-cli/package.json b/apps/w3c-cli/package.json index f0e7ca27..3c82dce9 100644 --- a/apps/w3c-cli/package.json +++ b/apps/w3c-cli/package.json @@ -1,7 +1,8 @@ { "name": "@trustvc/w3c-cli", "version": "1.3.0-alpha.12", - "description": "CLI for TrustVC W3C", + "description": "⚠️ DEPRECATED: CLI for TrustVC W3C - This package is no longer maintained.", + "deprecated": "This CLI package is deprecated due to incompatibility with modern cryptosuites.", "main": "dist/main.js", "types": "dist/main.d.ts", "bin": { diff --git a/apps/w3c-cli/project.json b/apps/w3c-cli/project.json.deprecated similarity index 64% rename from apps/w3c-cli/project.json rename to apps/w3c-cli/project.json.deprecated index 06213e99..9ea5e32e 100644 --- a/apps/w3c-cli/project.json +++ b/apps/w3c-cli/project.json.deprecated @@ -1,3 +1,7 @@ +# DEPRECATED CLI PROJECT CONFIGURATION +# This file has been renamed from project.json to exclude the deprecated CLI from NX builds and tests +# The @trustvc/w3c-cli package is deprecated due to incompatibility with modern cryptosuites + { "name": "@trustvc/w3c-cli", "$schema": "../../node_modules/nx/schemas/project-schema.json", diff --git a/nx.json b/nx.json index 789be7fb..df43802a 100644 --- a/nx.json +++ b/nx.json @@ -50,8 +50,7 @@ "@trustvc/w3c-context", "@trustvc/w3c-credential-status", "@trustvc/w3c-issuer", - "@trustvc/w3c-vc", - "@trustvc/w3c-cli" + "@trustvc/w3c-vc" ], "changelog": { "projectChangelogs": { diff --git a/package-lock.json b/package-lock.json index 8e21a4fb..33f55723 100644 --- a/package-lock.json +++ b/package-lock.json @@ -115,14 +115,15 @@ }, "apps/w3c-cli": { "name": "@trustvc/w3c-cli", - "version": "1.3.0-alpha.10", + "version": "1.3.0-alpha.12", + "deprecated": "This CLI package is deprecated due to incompatibility with modern cryptosuites.", "license": "Apache-2.0", "dependencies": { "@inquirer/prompts": "^5.3.8", - "@trustvc/w3c-context": "^1.3.0-alpha.9", - "@trustvc/w3c-credential-status": "^1.3.0-alpha.9", - "@trustvc/w3c-issuer": "^1.3.0-alpha.7", - "@trustvc/w3c-vc": "^1.3.0-alpha.10", + "@trustvc/w3c-context": "^1.3.0-alpha.11", + "@trustvc/w3c-credential-status": "^1.3.0-alpha.11", + "@trustvc/w3c-issuer": "^1.3.0-alpha.9", + "@trustvc/w3c-vc": "^1.3.0-alpha.12", "@types/yargs": "^17.0.32", "chalk": "^4.1.2", "inquirer": "^10.0.1", @@ -2748,6 +2749,20 @@ "uuid": "dist/bin/uuid" } }, + "node_modules/@digitalbazaar/bbs-2023-cryptosuite": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@digitalbazaar/bbs-2023-cryptosuite/-/bbs-2023-cryptosuite-2.0.1.tgz", + "integrity": "sha512-Uw7aDSuCehLUsiSsTi2ob1hQ8AgVq+jV3OgvPsOzy/AmIh2yG9kg2tNCv6PngWPyOm3VCzolwh+5MzWySASiww==", + "dependencies": { + "@digitalbazaar/bls12-381-multikey": "^2.0.0", + "@digitalbazaar/di-sd-primitives": "^3.0.4", + "base64url-universal": "^2.0.0", + "cborg": "^4.0.5" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/@digitalbazaar/bbs-signatures": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@digitalbazaar/bbs-signatures/-/bbs-signatures-3.0.0.tgz", @@ -32819,13 +32834,13 @@ }, "packages/w3c": { "name": "@trustvc/w3c", - "version": "1.3.0-alpha.10", + "version": "1.3.0-alpha.12", "license": "Apache-2.0", "dependencies": { - "@trustvc/w3c-context": "^1.3.0-alpha.9", - "@trustvc/w3c-credential-status": "^1.3.0-alpha.9", - "@trustvc/w3c-issuer": "^1.3.0-alpha.7", - "@trustvc/w3c-vc": "^1.3.0-alpha.10" + "@trustvc/w3c-context": "^1.3.0-alpha.11", + "@trustvc/w3c-credential-status": "^1.3.0-alpha.11", + "@trustvc/w3c-issuer": "^1.3.0-alpha.9", + "@trustvc/w3c-vc": "^1.3.0-alpha.12" }, "engines": { "node": ">=18.x" @@ -32833,7 +32848,7 @@ }, "packages/w3c-context": { "name": "@trustvc/w3c-context", - "version": "1.3.0-alpha.9", + "version": "1.3.0-alpha.11", "license": "Apache-2.0", "dependencies": { "did-resolver": "^4.1.0", @@ -32925,11 +32940,11 @@ }, "packages/w3c-credential-status": { "name": "@trustvc/w3c-credential-status", - "version": "1.3.0-alpha.9", + "version": "1.3.0-alpha.11", "license": "Apache-2.0", "dependencies": { - "@trustvc/w3c-context": "^1.3.0-alpha.9", - "@trustvc/w3c-issuer": "^1.3.0-alpha.7", + "@trustvc/w3c-context": "^1.3.0-alpha.11", + "@trustvc/w3c-issuer": "^1.3.0-alpha.9", "base64url-universal": "^2.0.0", "pako": "^2.1.0" }, @@ -32939,7 +32954,7 @@ }, "packages/w3c-issuer": { "name": "@trustvc/w3c-issuer", - "version": "1.3.0-alpha.7", + "version": "1.3.0-alpha.9", "license": "Apache-2.0", "dependencies": { "@digitalbazaar/bls12-381-multikey": "^2.1.0", @@ -32956,15 +32971,17 @@ }, "packages/w3c-vc": { "name": "@trustvc/w3c-vc", - "version": "1.3.0-alpha.10", + "version": "1.3.0-alpha.12", "license": "Apache-2.0", "dependencies": { + "@digitalbazaar/bbs-2023-cryptosuite": "^2.0.1", + "@digitalbazaar/bls12-381-multikey": "^2.1.0", "@digitalbazaar/data-integrity": "^2.5.0", "@digitalbazaar/ecdsa-multikey": "^1.8.0", "@digitalbazaar/ecdsa-sd-2023-cryptosuite": "^3.4.1", "@mattrglobal/jsonld-signatures-bbs": "^1.2.0", - "@trustvc/w3c-credential-status": "^1.3.0-alpha.9", - "@trustvc/w3c-issuer": "^1.3.0-alpha.7", + "@trustvc/w3c-credential-status": "^1.3.0-alpha.11", + "@trustvc/w3c-issuer": "^1.3.0-alpha.9", "base64url-universal": "^2.0.0", "cbor": "^9.0.2", "did-resolver": "^4.1.0", diff --git a/packages/declaration.d.ts b/packages/declaration.d.ts index eee0fba4..255d5e5d 100644 --- a/packages/declaration.d.ts +++ b/packages/declaration.d.ts @@ -1,4 +1,5 @@ declare module '@digitalbazaar/bls12-381-multikey'; +declare module '@digitalbazaar/bbs-2023-cryptosuite'; declare module '@digitalbazaar/ecdsa-multikey'; declare module '@digitalbazaar/ecdsa-sd-2023-cryptosuite'; declare module '@digitalbazaar/data-integrity'; diff --git a/packages/w3c-vc/README.md b/packages/w3c-vc/README.md index 9a10c7ca..21837cbb 100644 --- a/packages/w3c-vc/README.md +++ b/packages/w3c-vc/README.md @@ -1,6 +1,20 @@ # TrustVC W3C VC -This repository provides utilities for signing and verifying Verifiable Credentials (VCs) using multiple signature schemes including BBS+ and ECDSA-SD-2023. These functions can be used to ensure the authenticity and integrity of VCs within a W3C-compliant ecosystem. +This repository provides utilities for signing, verifying, and deriving Verifiable Credentials (VCs) using modern cryptographic signature schemes including ECDSA-SD-2023 and BBS-2023, with selective disclosure capabilities. These functions ensure the authenticity and integrity of VCs within a W3C-compliant ecosystem. + +## Table of Contents + +- [Installation](#installation) +- [Features](#features) +- [Supported Cryptosuites](#supported-cryptosuites) +- [Usage](#usage) + - [1. Signing a Credential](#1-signing-a-credential) + - [2. Verifying a Credential](#2-verifying-a-credential) + - [3. Deriving a Credential (Selective Disclosure)](#3-deriving-a-credential-selective-disclosure) + - [4. Schema Validation](#4-schema-validation) +- [Migration from Legacy BbsBlsSignature2020](#migration-from-legacy-bbsblssignature2020) +- [Best Practices](#best-practices) +- [License](#license) ## Installation To install the package, use: @@ -9,19 +23,29 @@ To install the package, use: npm install @trustvc/w3c-vc ``` -## Feature -- Sign and Verify for BBS+ signature for W3C VC -- Sign and Verify for ECDSA-SD-2023 signature for W3C VC with selective disclosure -- Derive a new VC with selective disclosure using BBS+ signature -- Derive a new VC with selective disclosure using ECDSA-SD-2023 signature -- Checks if payload matches W3C VC schema +## Features +- **Modern Cryptosuites**: ECDSA-SD-2023 (default) and BBS-2023 with selective disclosure +- **W3C Compliance**: Support for both W3C VC Data Model v1.1 and v2.0 +- **Selective Disclosure**: Derive credentials with selective field revelation +- **Legacy Support**: Deprecated BbsBlsSignature2020 signature support (verification only) +- **Schema Validation**: Checks if payload matches W3C VC schema +- **Version Detection**: Helper functions to detect credential versions + +## Supported Cryptosuites + +| Cryptosuite | Status | Signing | Verification | Derivation | Notes | +|-------------|--------|---------|--------------|------------|-------| +| `ecdsa-sd-2023` | ✅ Active (Default) | ✅ | ✅ | ✅ | Modern, fast, selective disclosure | +| `bbs-2023` | ✅ Active | ✅ | ✅ | ✅ | Modern BBS with selective disclosure | +| `BbsBlsSignature2020` | ⚠️ Deprecated | ❌ | ✅ | ❌ | Legacy support only | ## Usage + ### 1. Signing a Credential -The signCredential function allows you to sign a Verifiable Credential using either BBS+ or ECDSA-SD-2023 signature schemes. +The `signCredential` function allows you to sign a Verifiable Credential using modern cryptographic signature schemes. **Default cryptosuite is `ecdsa-sd-2023`**. -#### BBS+ Signing (Default) +#### ECDSA-SD-2023 Signing (Default) ```ts import { signCredential } from '@trustvc/w3c-vc'; @@ -30,7 +54,8 @@ import { signCredential } from '@trustvc/w3c-vc'; * Parameters: * - credential (RawVerifiableCredential): The credential to be signed. * - keyPair (PrivateKeyPair): The key pair options for signing. - * - cryptoSuite (string, optional): The cryptosuite to be used for signing. Defaults to "BbsBlsSignature2020". + * - cryptoSuite (CryptoSuiteName, optional): The cryptosuite to be used. Defaults to "ecdsa-sd-2023". + * - options (object, optional): Optional parameters including documentLoader and mandatoryPointers. * * Returns: * - A Promise that resolves to: @@ -38,43 +63,38 @@ import { signCredential } from '@trustvc/w3c-vc'; * - signedCredential.error (string): The error message in case of failure. */ -const keyPair = { - "id": "did:web:trustvc.github.io:did:1#keys-1", - "type": "Bls12381G2Key2020", +const ecdsaKeyPair = { + "id": "did:web:trustvc.github.io:did:1#multikey-1", + "type": "Multikey", "controller": "did:web:trustvc.github.io:did:1", - "seedBase58": "", - "privateKeyBase58": "", - "publicKeyBase58": "oRfEeWFresvhRtXCkihZbxyoi2JER7gHTJ5psXhHsdCoU1MttRMi3Yp9b9fpjmKh7bMgfWKLESiK2YovRd8KGzJsGuamoAXfqDDVhckxuc9nmsJ84skCSTijKeU4pfAcxeJ" + "secretKeyMultibase": "", + "publicKeyMultibase": "" }; const credential = { "@context": [ - "https://www.w3.org/2018/credentials/v1", - "https://w3c-ccg.github.io/citizenship-vocab/contexts/citizenship-v1.jsonld", - "https://w3id.org/security/bbs/v1", - "https://w3id.org/vc/status-list/2021/v1" + "https://www.w3.org/ns/credentials/v2", + "https://w3id.org/security/data-integrity/v2", + "https://w3id.org/citizenship/v2" ], - "credentialStatus": { - "id": "https://trustvc.github.io/did/credentials/statuslist/1#1", - "statusListCredential": "https://trustvc.github.io/did/credentials/statuslist/1", - "statusListIndex": "1", - "statusPurpose": "revocation", - "type": "StatusList2021Entry" - }, - "issuanceDate": "2024-04-01T12:19:52Z", "credentialSubject": { "id": "did:example:b34ca6cd37bbf23", "type": ["Person"], "name": "TrustVC" }, - "expirationDate": "2029-12-03T12:19:52Z", + "validFrom": "2024-04-01T12:19:52Z", + "validUntil": "2029-12-03T12:19:52Z", "issuer": "did:web:trustvc.github.io:did:1", - "type": [ - "VerifiableCredential" - ] + "type": ["VerifiableCredential"] }; -const signedCredential = await signCredential(credential, keyPair); +// Sign with default ECDSA-SD-2023 cryptosuite +const signedCredential = await signCredential(credential, ecdsaKeyPair); + +// Or explicitly specify cryptosuite with mandatory pointers +const signedCredentialWithOptions = await signCredential(credential, ecdsaKeyPair, 'ecdsa-sd-2023', { + mandatoryPointers: ['/credentialSubject/name'] +}); if (signedCredential.signed) { console.log('Signed Credential:', signedCredential.signed); @@ -83,59 +103,75 @@ if (signedCredential.signed) { } ``` -#### ECDSA-SD-2023 Signing +#### BBS-2023 Signing ```ts import { signCredential } from '@trustvc/w3c-vc'; -const ecdsaKeyPair = { - "id": "did:web:trustvc.github.io:did:1#multikey-1", +const bbsKeyPair = { + "id": "did:web:trustvc.github.io:did:1#multikey-2", "type": "Multikey", "controller": "did:web:trustvc.github.io:did:1", "secretKeyMultibase": "", - "publicKeyMultibase": "zDnaekGZTbQBerwcehBSXLqAg6s55hVEBms1zFy89VHXtJSa9" + "publicKeyMultibase": "" }; const credential = { "@context": [ "https://www.w3.org/ns/credentials/v2", - "https://w3id.org/security/data-integrity/v2" + "https://w3id.org/security/data-integrity/v2", + "https://w3id.org/citizenship/v2" ], - "validFrom": "2024-04-01T12:19:52Z", "credentialSubject": { "id": "did:example:b34ca6cd37bbf23", "type": ["Person"], - "name": "TrustVC", - "billOfLadingName": "Acme Corp" + "name": "TrustVC" }, + "validFrom": "2024-04-01T12:19:52Z", "validUntil": "2029-12-03T12:19:52Z", "issuer": "did:web:trustvc.github.io:did:1", "type": ["VerifiableCredential"] }; -// Sign with mandatory pointers (always included in derived credentials) -const signedCredential = await signCredential(credential, ecdsaKeyPair, 'ecdsa-sd-2023', { - mandatoryPointers: ['/credentialSubject/id', '/credentialSubject/type'] +// Sign with BBS-2023 cryptosuite +const signedCredential = await signCredential(credential, bbsKeyPair, 'bbs-2023', { + mandatoryPointers: ['/credentialSubject/name'] }); if (signedCredential.signed) { - console.log('Signed Credential:', signedCredential.signed); + console.log('BBS-2023 Signed Credential:', signedCredential.signed); } else { console.error('Error:', signedCredential.error); } ``` +#### Legacy BbsBlsSignature2020 Signing (Deprecated) + +```ts +import { signCredential } from '@trustvc/w3c-vc'; + +// ⚠️ DEPRECATED: BbsBlsSignature2020 signing is no longer supported +const legacyResult = await signCredential(credential, keyPair, 'BbsBlsSignature2020'); + +// This will return an error: +// { error: "BbsBlsSignature2020 is no longer supported. Please use the latest cryptosuite versions instead." } +``` + ### 2. Verifying a Credential -The verifyCredential function allows you to verify a signed Verifiable Credential using BBS+ or ECDSA-SD-2023 signature schemes. -#### BBS+ Verification +The `verifyCredential` function allows you to verify signed Verifiable Credentials. + +#### Modern Cryptosuite Verification (ECDSA-SD-2023 / BBS-2023) + +> **Important**: For modern cryptosuites (ECDSA-SD-2023, BBS-2023), **base credentials must be derived before verification**. You cannot directly verify the original signed credential. ```ts -import { verifyCredential } from '@trustvc/w3c-vc'; +import { verifyCredential, deriveCredential } from '@trustvc/w3c-vc'; /** * Parameters: * - credential (SignedVerifiableCredential): The credential to be verified. + * - options (object, optional): Optional parameters including documentLoader. * * Returns: * - A Promise that resolves to: @@ -143,93 +179,93 @@ import { verifyCredential } from '@trustvc/w3c-vc'; * - verificationResult.error (string): The error message if the verification failed. */ -const credential = { +const signedCredential = { '@context': [ - 'https://www.w3.org/2018/credentials/v1', - 'https://w3c-ccg.github.io/citizenship-vocab/contexts/citizenship-v1.jsonld', - 'https://w3id.org/security/bbs/v1', - 'https://w3id.org/vc/status-list/2021/v1' + 'https://www.w3.org/ns/credentials/v2', + 'https://w3id.org/security/data-integrity/v2', + "https://w3id.org/citizenship/v2" ], - credentialStatus: { - id: 'https://trustvc.github.io/did/credentials/statuslist/1#1', - statusListCredential: 'https://trustvc.github.io/did/credentials/statuslist/1', - statusListIndex: '1', - statusPurpose: 'revocation', - type: 'StatusList2021Entry' - }, - issuanceDate: '2024-04-01T12:19:52Z', credentialSubject: { id: 'did:example:b34ca6cd37bbf23', - type: [ 'Person' ], + type: ['Person'], name: 'TrustVC' }, - expirationDate: '2029-12-03T12:19:52Z', + validFrom: '2024-04-01T12:19:52Z', + validUntil: '2029-12-03T12:19:52Z', issuer: 'did:web:trustvc.github.io:did:1', - type: [ 'VerifiableCredential' ], + type: ['VerifiableCredential'], proof: { - type: 'BbsBlsSignature2020', + type: 'DataIntegrityProof', + cryptosuite: 'ecdsa-sd-2023', created: '2024-10-02T09:04:07Z', proofPurpose: 'assertionMethod', - proofValue: 'tissP5pJF1q4txCMWNZI5LgwhXMWrLI8675ops8FwlQE/zBUQnVO9Iey505MjkNDD5GdmQmnb6+RUKkLVGEJLIJrKQXlU3Xr4DlMW7ShH/sIpuvZoobGs/0hw/B5agXz8cVWfnDGWtDYciVh0rwQvg==', - verificationMethod: 'did:web:trustvc.github.io:did:1#keys-1' + proofValue: 'z...', + verificationMethod: 'did:web:trustvc.github.io:did:1#multikey-1' } }; -const verificationResult = await verifyCredential(credential); +// ❌ This will fail - base credentials cannot be verified directly +const baseVerification = await verifyCredential(signedCredential); +// Returns: { verified: false, error: "ecdsa-sd-2023 base credentials must be derived before verification. Use deriveCredential() first." } -if (verificationResult.verified) { - console.log('Credential verified successfully.'); -} else { - console.error('Verification failed:', verificationResult.error); +// ✅ Correct approach: Derive first, then verify +const derivedResult = await deriveCredential(signedCredential, ['/credentialSubject/name']); + +if (derivedResult.derived) { + const verificationResult = await verifyCredential(derivedResult.derived); + + if (verificationResult.verified) { + console.log('Credential verified successfully.'); + } else { + console.error('Verification failed:', verificationResult.error); + } } ``` -#### ECDSA-SD-2023 Verification - -> **Note**: For ECDSA-SD-2023 credentials with selective disclosure, you typically need to derive the credential first using `deriveCredential()` before verification. The example below shows verification of a base credential. +#### Legacy BbsBlsSignature2020 Verification ```ts import { verifyCredential } from '@trustvc/w3c-vc'; -const ecdsaCredential = { +// Legacy BbsBlsSignature2020 credentials can be verified directly (both base and derived credentials) +const bbsCredential = { '@context': [ - 'https://www.w3.org/ns/credentials/v2', - 'https://w3id.org/security/data-integrity/v2' + 'https://www.w3.org/2018/credentials/v1', + 'https://w3id.org/security/bbs/v1', + 'https://w3id.org/citizenship/v1' ], - validFrom: '2024-04-01T12:19:52Z', credentialSubject: { id: 'did:example:b34ca6cd37bbf23', type: ['Person'], - name: 'TrustVC', - billOfLadingName: 'Acme Corp' + name: 'TrustVC' }, - validUntil: '2029-12-03T12:19:52Z', + issuanceDate: '2024-04-01T12:19:52Z', + expirationDate: '2029-12-03T12:19:52Z', issuer: 'did:web:trustvc.github.io:did:1', - type: ['VerifiableCredential'], + type: [ 'VerifiableCredential' ], proof: { - type: 'DataIntegrityProof', - cryptosuite: 'ecdsa-sd-2023', + type: 'BbsBlsSignature2020', created: '2024-10-02T09:04:07Z', proofPurpose: 'assertionMethod', - proofValue: 'z...', - verificationMethod: 'did:web:trustvc.github.io:did:1#multikey-1' + proofValue: 'A...', + verificationMethod: 'did:web:trustvc.github.io:did:1#keys-1' } }; -const verificationResult = await verifyCredential(ecdsaCredential); +const verificationResult = await verifyCredential(bbsCredential); if (verificationResult.verified) { - console.log('ECDSA-SD-2023 Credential verified successfully.'); + console.log('Legacy BbsBlsSignature2020 credential verified successfully.'); } else { console.error('Verification failed:', verificationResult.error); } ``` -### 3. Deriving a Credential +### 3. Deriving a Credential (Selective Disclosure) -The deriveCredential function allows you to derive a new credential with selective disclosure using either BBS+ or ECDSA-SD-2023 signature schemes. +The `deriveCredential` function allows you to create selective disclosure from signed credentials. -#### BBS+ Selective Disclosure +#### ECDSA-SD-2023 Selective Disclosure ```ts import { deriveCredential } from '@trustvc/w3c-vc'; @@ -237,141 +273,194 @@ import { deriveCredential } from '@trustvc/w3c-vc'; /** * Parameters: * - credential (SignedVerifiableCredential): The verifiable credential to be selectively disclosed. - * - revealedAttributes (ContextDocument): The attributes from the credential that should be revealed in the derived proof. + * - revealedAttributes (string[]): Array of JSON pointers specifying which fields to reveal. + * - options (object, optional): Optional parameters including documentLoader. * * Returns: * - A Promise that resolves to: - * - derived (DerivedProof): The selectively disclosed credential with the derived proof. + * - derived (SignedVerifiableCredential): The selectively disclosed credential. * - error (string): The error message in case of failure. */ -const credential = { +const signedCredential = { '@context': [ - 'https://www.w3.org/2018/credentials/v1', - 'https://w3c-ccg.github.io/citizenship-vocab/contexts/citizenship-v1.jsonld', - 'https://w3id.org/security/bbs/v1', - 'https://w3id.org/vc/status-list/2021/v1' + 'https://www.w3.org/ns/credentials/v2', + 'https://w3id.org/security/data-integrity/v2', + "https://w3id.org/citizenship/v2" ], - credentialStatus: { - id: 'https://trustvc.github.io/did/credentials/statuslist/1#1', - statusListCredential: 'https://trustvc.github.io/did/credentials/statuslist/1', - statusListIndex: '1', - statusPurpose: 'revocation', - type: 'StatusList2021Entry' - }, - issuanceDate: '2024-04-01T12:19:52Z', credentialSubject: { id: 'did:example:b34ca6cd37bbf23', - type: [ 'Person' ], + type: ['Person'], name: 'TrustVC' }, - expirationDate: '2029-12-03T12:19:52Z', + validFrom: '2024-04-01T12:19:52Z', + validUntil: '2029-12-03T12:19:52Z', issuer: 'did:web:trustvc.github.io:did:1', - type: [ 'VerifiableCredential' ], + type: ['VerifiableCredential'], proof: { - type: 'BbsBlsSignature2020', - created: '2024-10-02T09:04:07Z', - proofPurpose: 'assertionMethod', - proofValue: 'tissP5pJF1q4txCMWNZI5LgwhXMWrLI8675ops8FwlQE/zBUQnVO9Iey505MjkNDD5GdmQmnb6+RUKkLVGEJLIJrKQXlU3Xr4DlMW7ShH/sIpuvZoobGs/0hw/B5agXz8cVWfnDGWtDYciVh0rwQvg==', - verificationMethod: 'did:web:trustvc.github.io:did:1#keys-1' + type: 'DataIntegrityProof', + cryptosuite: 'ecdsa-sd-2023', + // ... proof details } }; -const revealedAttributes = { - '@context': [ - 'https://www.w3.org/2018/credentials/v1', - 'https://w3c-ccg.github.io/citizenship-vocab/contexts/citizenship-v1.jsonld', - 'https://w3id.org/security/bbs/v1', - 'https://w3id.org/vc/status-list/2021/v1' - ], - credentialSubject: { - type: [ 'Person' ], - '@explicit': true - }, - type: [ 'VerifiableCredential' ] -}; +// Reveal only specific fields (mandatory pointers are automatically included) +const selectivePointers = ['/credentialSubject/name']; -const derivedResult = await deriveCredential(credential, revealedAttributes); +const derivedResult = await deriveCredential(signedCredential, selectivePointers); if (derivedResult.derived) { - console.log('Derived Credential:', derivedResult.derived); + console.log('Derived ECDSA-SD-2023 Credential:', derivedResult.derived); } else { console.error('Error:', derivedResult.error); } + +// ❌ Multiple derivation rounds are not supported +const secondDerivation = await deriveCredential(derivedResult.derived, selectivePointers); +// Returns: { error: "ecdsa-sd-2023 derived credentials cannot be further derived. Multiple rounds of derivation are not supported by this cryptosuite." } ``` -#### ECDSA-SD-2023 Selective Disclosure +#### BBS-2023 Selective Disclosure ```ts import { deriveCredential } from '@trustvc/w3c-vc'; -/** - * Parameters: - * - credential (SignedVerifiableCredential): The verifiable credential to be selectively disclosed. - * - revealedAttributes (string[]): Array of JSON pointers specifying which fields to reveal. - * - * Returns: - * - A Promise that resolves to: - * - derived (DerivedProof): The selectively disclosed credential with the derived proof. - * - error (string): The error message in case of failure. - */ - -const ecdsaCredential = { +const bbsSignedCredential = { '@context': [ 'https://www.w3.org/ns/credentials/v2', - 'https://w3id.org/security/data-integrity/v2' + 'https://w3id.org/security/data-integrity/v2', + "https://w3id.org/citizenship/v2" ], - validFrom: '2024-04-01T12:19:52Z', credentialSubject: { id: 'did:example:b34ca6cd37bbf23', type: ['Person'], - name: 'TrustVC', - billOfLadingName: 'Acme Corp' + name: 'TrustVC' }, + validFrom: '2024-04-01T12:19:52Z', validUntil: '2029-12-03T12:19:52Z', issuer: 'did:web:trustvc.github.io:did:1', type: ['VerifiableCredential'], proof: { type: 'DataIntegrityProof', - cryptosuite: 'ecdsa-sd-2023', - created: '2024-10-02T09:04:07Z', - proofPurpose: 'assertionMethod', - proofValue: 'z...', - verificationMethod: 'did:web:trustvc.github.io:did:1#multikey-1' + cryptosuite: 'bbs-2023', + // ... proof details } }; -// Reveal only the billOfLadingName field (mandatory pointers are always included) -const selectivePointers = ['/credentialSubject/billOfLadingName']; +// Reveal only specific fields (mandatory pointers are automatically included) +const selectivePointers = ['/credentialSubject/name']; -const derivedResult = await deriveCredential(ecdsaCredential, selectivePointers); +const derivedResult = await deriveCredential(bbsSignedCredential, selectivePointers); if (derivedResult.derived) { - console.log('Derived ECDSA-SD-2023 Credential:', derivedResult.derived); + console.log('Derived BBS-2023 Credential:', derivedResult.derived); } else { console.error('Error:', derivedResult.error); } ``` -### 4. Validate if payload meets the schema +#### Legacy BbsBlsSignature2020 Derivation (Deprecated) ```ts -import { isRawDocument, isSignedDocument } from '@trustvc/w3c-vc'; +import { deriveCredential } from '@trustvc/w3c-vc'; + +// ⚠️ DEPRECATED: BbsBlsSignature2020 derivation is no longer supported +const legacyDerivation = await deriveCredential(credential, revealedAttributes); + +// This will return an error: +// { error: "BbsBlsSignature2020 is no longer supported for derivation. Please use the latest cryptosuite versions instead." } +``` + +### 4. Schema Validation + +Validate if a document meets W3C VC schema requirements: + +```ts +import { + isRawDocument, + isSignedDocument, + isRawDocumentV1_1, + isRawDocumentV2_0, + isSignedDocumentV1_1, + isSignedDocumentV2_0, + isDerived +} from '@trustvc/w3c-vc'; /** - * Parameters: - * - document (RawVerifiableCredential | SignedVerifiableCredential | unknown): The raw credential to be checked. - * - * Returns: - * - Returns true if the document is a raw credential, false otherwise. + * Available validation functions: + * - isRawDocument(document): Checks if document is a valid raw credential + * - isSignedDocument(document): Checks if document is a valid signed credential + * - isRawDocumentV1_1(document): Checks if document is a valid v1.1 raw credential + * - isRawDocumentV2_0(document): Checks if document is a valid v2.0 raw credential + * - isSignedDocumentV1_1(document): Checks if document is a valid v1.1 signed credential + * - isSignedDocumentV2_0(document): Checks if document is a valid v2.0 signed credential + * - isDerived(document): Checks if document is a derived (selective disclosure) credential */ const document = { - ... -} + "@context": [ + "https://www.w3.org/ns/credentials/v2", + "https://w3id.org/security/data-integrity/v2", + "https://w3id.org/citizenship/v2" + ], + "type": ["VerifiableCredential"], + "issuer": "did:web:example.com", + "validFrom": "2024-01-01T00:00:00Z", + "credentialSubject": { + "id": "did:example:123", + "type": ["Person"], + "name": "John Doe" + } +}; + +// Basic validation +console.log('Is raw document:', isRawDocument(document)); // true +console.log('Is signed document:', isSignedDocument(document)); // false (no proof) + +// Version-specific validation +console.log('Is v1.1 raw document:', isRawDocumentV1_1(document)); // false +console.log('Is v2.0 raw document:', isRawDocumentV2_0(document)); // true + +// Check if credential is derived (selective disclosure) +const signedDocument = { ...document, proof: { /* proof object */ } }; +console.log('Is derived credential:', await isDerived(signedDocument)); +``` + +## Migration from Legacy BbsBlsSignature2020 + +If you're migrating from legacy BbsBlsSignature2020 signatures: + +1. **Update Key Pairs**: Use Multikey format instead of Bls12381G2Key2020 +2. **Change Cryptosuite**: Use 'ecdsa-sd-2023' or 'bbs-2023' instead of 'BbsBlsSignature2020' +3. **Update Contexts**: Use W3C VC Data Model v2.0 contexts +4. **Modify Derivation**: Use JSON pointer arrays instead of ContextDocument format +5. **Update Verification Flow**: Derive credentials before verification for modern cryptosuites + +```ts +// Legacy BbsBlsSignature2020 (deprecated) +const legacyKeyPair = { + type: "Bls12381G2Key2020", + privateKeyBase58: "...", + publicKeyBase58: "..." +}; + +// Modern approach +const modernKeyPair = { + type: "Multikey", + secretKeyMultibase: "...", + publicKeyMultibase: "..." +}; +``` + +## Best Practices + +1. **Use Modern Cryptosuites**: Prefer 'ecdsa-sd-2023' (default) or 'bbs-2023' over legacy BbsBlsSignature2020 +2. **Implement Proper Error Handling**: Always check for errors in function results +3. **Derive Before Verify**: For modern cryptosuites, always derive credentials before verification +4. **Use Mandatory Pointers**: Specify fields that should always be revealed in selective disclosure +5. **Version Detection**: Use helper functions to detect credential versions when needed +6. **Single Derivation**: Remember that modern cryptosuites support only single-round derivation -const result1 = isRawDocument(document); -console.log('isRawDocument', result1); +## License -const result2 = isSignedDocument(document); -console.log('isSignedDocument', result2); +This project is licensed under the Apache 2.0 License. diff --git a/packages/w3c-vc/package.json b/packages/w3c-vc/package.json index 608aa22c..2371ef4e 100644 --- a/packages/w3c-vc/package.json +++ b/packages/w3c-vc/package.json @@ -31,6 +31,8 @@ } }, "dependencies": { + "@digitalbazaar/bls12-381-multikey": "^2.1.0", + "@digitalbazaar/bbs-2023-cryptosuite": "^2.0.1", "@digitalbazaar/data-integrity": "^2.5.0", "@digitalbazaar/ecdsa-multikey": "^1.8.0", "@digitalbazaar/ecdsa-sd-2023-cryptosuite": "^3.4.1", diff --git a/packages/w3c-vc/src/lib/__fixtures__/bbs2020-credentials.ts b/packages/w3c-vc/src/lib/__fixtures__/bbs2020-credentials.ts new file mode 100644 index 00000000..3aa4010f --- /dev/null +++ b/packages/w3c-vc/src/lib/__fixtures__/bbs2020-credentials.ts @@ -0,0 +1,296 @@ +import { SignedVerifiableCredential } from '../types'; + +export const bbs2020CredentialV1_1: SignedVerifiableCredential = { + '@context': [ + 'https://www.w3.org/2018/credentials/v1', + 'https://w3id.org/security/bbs/v1', + 'https://w3id.org/vc/status-list/2021/v1', + 'https://trustvc.io/context/transferable-records-context.json', + 'https://trustvc.io/context/render-method-context.json', + 'https://trustvc.io/context/attachments-context.json', + 'https://trustvc.io/context/qrcode-context.json', + 'https://trustvc.io/context/bill-of-lading.json', + ], + qrCode: { type: 'TrustVCQRCode', uri: 'https://localhost:3000/qrcode' }, + credentialStatus: { + type: 'TransferableRecords', + tokenNetwork: { chain: 'MATIC', chainId: '80001' }, + tokenRegistry: '0xE0a94770B8e969B5D9179d6dA8730B01e19279e2', + tokenId: '0f6cda4d977bae4a92f55133cd64926a8b91d4239984dc1184dc9337463c2687', + }, + credentialSubject: { + billOfLadingName: 'TrustVC Bill of Lading', + scac: 'SGPU', + blNumber: 'SGCNM21566325', + vessel: 'vessel', + voyageNo: 'voyageNo', + portOfLoading: 'Singapore', + portOfDischarge: 'Paris', + carrierName: 'A.P. Moller', + placeOfReceipt: 'Beijing', + placeOfDelivery: 'Singapore', + packages: [ + { packagesDescription: 'package 1', packagesWeight: '10', packagesMeasurement: '20' }, + { packagesDescription: 'package 2', packagesWeight: '10', packagesMeasurement: '20' }, + ], + shipperName: 'Shipper Name', + shipperAddressStreet: '101 ORCHARD ROAD', + shipperAddressCountry: 'SINGAPORE', + consigneeName: 'Consignee name', + notifyPartyName: 'Notify Party Name', + links: 'https://localhost:3000/url', + attachments: [ + { data: 'BASE64_ENCODED_FILE', filename: 'sample1.pdf', mimeType: 'application/pdf' }, + { data: 'BASE64_ENCODED_FILE', filename: 'sample2.pdf', mimeType: 'application/pdf' }, + ], + type: ['BillOfLading'], + }, + renderMethod: [ + { + id: 'https://localhost:3000/renderer', + type: 'EMBEDDED_RENDERER', + templateName: 'BILL_OF_LADING', + }, + ], + expirationDate: '2029-12-03T12:19:52Z', + issuer: 'did:web:trustvc.github.io:did:1', + type: ['VerifiableCredential'], + issuanceDate: '2024-04-01T12:19:52Z', + id: 'urn:bnid:_:01994c0f-c112-7446-b6a9-38a6bfbcfc5a', + proof: { + type: 'BbsBlsSignature2020', + created: '2025-09-15T06:28:45Z', + proofPurpose: 'assertionMethod', + proofValue: + 't43CydjSQLq5cLDxdnBf9c27ijWARBCW98RqoAn5WZzWIVaHhAmhUAhKXVelsIDXBqdyy/7UdRyvqvWX+lMz3n1Jvp+5o/lD1ckOxrWuG2c6vSa3nqU6MAxVvq9dOnUeAgQTrkpXhXuwNoYtR33vFQ==', + verificationMethod: 'did:web:trustvc.github.io:did:1#keys-1', + }, +}; + +export const bbs2020DerivedCredentialV1_1: SignedVerifiableCredential = { + '@context': [ + 'https://www.w3.org/2018/credentials/v1', + 'https://w3id.org/security/bbs/v1', + 'https://w3id.org/vc/status-list/2021/v1', + 'https://trustvc.io/context/transferable-records-context.json', + 'https://trustvc.io/context/render-method-context.json', + 'https://trustvc.io/context/attachments-context.json', + 'https://trustvc.io/context/qrcode-context.json', + 'https://trustvc.io/context/bill-of-lading.json', + ], + id: 'urn:bnid:_:01994c0f-c112-7446-b6a9-38a6bfbcfc5a', + type: 'VerifiableCredential', + qrCode: { + id: 'urn:bnid:_:c14n6', + type: 'TrustVCQRCode', + uri: 'https://localhost:3000/qrcode', + }, + renderMethod: [ + { + '@id': 'urn:bnid:_:c14n2', + id: 'https://localhost:3000/renderer', + templateName: 'BILL_OF_LADING', + type: 'EMBEDDED_RENDERER', + }, + ], + credentialStatus: { + id: 'urn:bnid:_:c14n0', + type: 'TransferableRecords', + tokenId: '0f6cda4d977bae4a92f55133cd64926a8b91d4239984dc1184dc9337463c2687', + tokenNetwork: { id: 'urn:bnid:_:c14n1', chain: 'MATIC', chainId: '80001' }, + tokenRegistry: '0xE0a94770B8e969B5D9179d6dA8730B01e19279e2', + }, + credentialSubject: { + id: 'urn:bnid:_:c14n5', + type: 'BillOfLading', + billOfLadingName: 'TrustVC Bill of Lading', + blNumber: 'SGCNM21566325', + shipperName: 'Shipper Name', + packages: [ + { + id: 'urn:bnid:_:c14n3', + packagesDescription: 'package 1', + packagesMeasurement: '20', + packagesWeight: '10', + }, + { + id: 'urn:bnid:_:c14n8', + packagesDescription: 'package 2', + packagesMeasurement: '20', + packagesWeight: '10', + }, + ], + attachments: [ + { + id: 'urn:bnid:_:c14n4', + data: 'BASE64_ENCODED_FILE', + filename: 'sample2.pdf', + mimeType: 'application/pdf', + }, + { + id: 'urn:bnid:_:c14n7', + data: 'BASE64_ENCODED_FILE', + filename: 'sample1.pdf', + mimeType: 'application/pdf', + }, + ], + }, + expirationDate: '2029-12-03T12:19:52Z', + issuanceDate: '2024-04-01T12:19:52Z', + issuer: 'did:web:trustvc.github.io:did:1', + proof: { + type: 'BbsBlsSignatureProof2020', + created: '2025-09-15T06:28:45Z', + nonce: 'PT3EpqO7oPMhsS3jW8Q8FeEqooe10H00APHM/ub1HMuGYlASd6SdrHvQefjwRSTYRxs=', + proofPurpose: 'assertionMethod', + proofValue: + 'ADgA//IAP////4C4R21VMhthwYh3LFiS2DEM4ZhiK+/0PXiGJdiiH4ezNSPWE72ib2akIxoKCG4KfpNOnAa0fOnxB4NP3+CqOeMCOy+zkw6NoEEwW1rQpZ71nGmx/0zPvultMUvVyyrgVa8XYW2lXuKk0nV7/CNeQB8KRhyVProFTLQTL+/Fi4IbBnGwXDdhkefhnoJXVkWv7QAAAHSja8XIvjo7HnfkXsYJNEejfsJfGeXY5q+/flm4s3evvnD4vLGFYreumGMblT4lGGkAAAACWETb3IlZvmWZcK7Gi0b4wKj2E6xPNw5Kw8FZ6rvKTMEK6ywNvxGMYSx5jR3JmvgOZuykA9nnsfw062F5mZkPspcdx/58XIl/QzKqDly5/5o5Rg16Tjx8noZ4v8+OIpRMs6YFuZx8GKDvElvRh8jvbgAAAA8mO/dQhW8va9SDksr5JlSNZOlQ6/0vMWiR9bRHDqe5eDF6aGrgqbuwcw1AcveclumDy4JqMGB9Qn9mBRZSLhbIGphtQd1h7MvlIC8nMsZQq320I/zjS3btmnwFal3OXLc5nV7AgAOuMlfqtTl8MYSf93kMDjL6unfHMU5gPEd0UwXkLBsfEt0zrv9bRgG++EOMw4OtOjZ96n5GrfhqCRfZbfUnJRBtH/5F/EOeUmAveILJ08TUezJC/Z1vDJ3Moog5jQrxtHJ/U2AKbKvsow1K8BWn6PLDoSwYWYK3M1+Wcyf8DnM0TTZKhdcSPe45ZawktgMg74uIkg4Kbt/lPQFWcX8mwLAzukkuXYT3XhPIF88EzKtcNic/BAHZJFMzzQthNZFPuTX+3GDsDErxyEgZnedeHKZpfQdGzo/u9SoMTzjLmSrDTxeSG8J90eL4Jov0YvW7IcNg+vk56m36OFWHOaDb+SDY3GZGdSODyfWGyrMuwcVd/LG9ArVq2iodstEMhTAW9HS7B6fz5zp5eD0/de6rsORn7XkOHqsW3vj94VXikfUKow3z4MH0nJxTG4W1OPZn2vgxaXuCeQx8Yb/FQwUo+p3t5WTRIRI/Mw7XtFbfGJ6nY5wSDsmRsCvFd94=', + verificationMethod: 'did:web:trustvc.github.io:did:1#keys-1', + }, +}; + +export const bbs2020CredentialV2_0: SignedVerifiableCredential = { + '@context': [ + 'https://www.w3.org/ns/credentials/v2', + 'https://w3id.org/security/bbs/v1', + 'https://trustvc.io/context/transferable-records-context.json', + 'https://trustvc.io/context/render-method-context-v2.json', + 'https://trustvc.io/context/attachments-context.json', + 'https://trustvc.io/context/qrcode-context.json', + 'https://trustvc.io/context/bill-of-lading.json', + ], + qrCode: { type: 'TrustVCQRCode', uri: 'https://localhost:3000/qrcode' }, + credentialStatus: { + type: 'TransferableRecords', + tokenNetwork: { chain: 'MATIC', chainId: '80001' }, + tokenRegistry: '0xE0a94770B8e969B5D9179d6dA8730B01e19279e2', + tokenId: 'f247599c416a3d55423495ef87cb188776e43553e91dcaeae5e60740719a1976', + }, + credentialSubject: { + billOfLadingName: 'TrustVC Bill of Lading', + scac: 'SGPU', + blNumber: 'SGCNM21566325', + vessel: 'vessel', + voyageNo: 'voyageNo', + portOfLoading: 'Singapore', + portOfDischarge: 'Paris', + carrierName: 'A.P. Moller', + placeOfReceipt: 'Beijing', + placeOfDelivery: 'Singapore', + packages: [ + { packagesDescription: 'package 1', packagesWeight: '10', packagesMeasurement: '20' }, + { packagesDescription: 'package 2', packagesWeight: '10', packagesMeasurement: '20' }, + ], + shipperName: 'Shipper Name', + shipperAddressStreet: '101 ORCHARD ROAD', + shipperAddressCountry: 'SINGAPORE', + consigneeName: 'Consignee name', + notifyPartyName: 'Notify Party Name', + links: 'https://localhost:3000/url', + attachments: [ + { data: 'BASE64_ENCODED_FILE', filename: 'sample1.pdf', mimeType: 'application/pdf' }, + { data: 'BASE64_ENCODED_FILE', filename: 'sample2.pdf', mimeType: 'application/pdf' }, + ], + type: ['BillOfLading'], + }, + renderMethod: [ + { + id: 'https://localhost:3000/renderer', + type: 'EMBEDDED_RENDERER', + templateName: 'BILL_OF_LADING', + }, + ], + validUntil: '2029-12-03T12:19:52Z', + issuer: 'did:web:trustvc.github.io:did:1', + type: ['VerifiableCredential'], + validFrom: '2024-04-01T12:19:52Z', + id: 'urn:bnid:_:01995667-2960-722f-9869-959a7fd07150', + proof: { + type: 'BbsBlsSignature2020', + created: '2025-09-17T06:40:25Z', + proofPurpose: 'assertionMethod', + proofValue: + 'p7vUXYbUqm7i5QDQKRoprc/q/yqNNAqNTA6xSa7XjORZ03u4S8APmU+9cIrV4ZMrB0sky130H7U+VSQVJfpFd9LGuZ6XC32nJkR3pbhxPzwdY+b5HaUFcGQQ3NJQAxz5xmqkSKY7WXiPqFKf/Beuaw==', + verificationMethod: 'did:web:trustvc.github.io:did:1#keys-1', + }, +}; + +export const bbs2020DerivedCredentialV2_0: SignedVerifiableCredential = { + '@context': [ + 'https://www.w3.org/ns/credentials/v2', + 'https://w3id.org/security/bbs/v1', + 'https://trustvc.io/context/transferable-records-context.json', + 'https://trustvc.io/context/render-method-context-v2.json', + 'https://trustvc.io/context/attachments-context.json', + 'https://trustvc.io/context/qrcode-context.json', + 'https://trustvc.io/context/bill-of-lading.json', + ], + id: 'urn:bnid:_:01995667-2960-722f-9869-959a7fd07150', + type: 'VerifiableCredential', + qrCode: { + id: 'urn:bnid:_:c14n3', + type: 'TrustVCQRCode', + uri: 'https://localhost:3000/qrcode', + }, + renderMethod: [ + { + id: 'https://localhost:3000/renderer', + templateName: 'BILL_OF_LADING', + type: 'EMBEDDED_RENDERER', + }, + ], + credentialStatus: { + id: 'urn:bnid:_:c14n0', + type: 'TransferableRecords', + tokenId: 'f247599c416a3d55423495ef87cb188776e43553e91dcaeae5e60740719a1976', + tokenNetwork: { id: 'urn:bnid:_:c14n1', chain: 'MATIC', chainId: '80001' }, + tokenRegistry: '0xE0a94770B8e969B5D9179d6dA8730B01e19279e2', + }, + credentialSubject: { + id: 'urn:bnid:_:c14n5', + type: 'BillOfLading', + billOfLadingName: 'TrustVC Bill of Lading', + blNumber: 'SGCNM21566325', + shipperName: 'Shipper Name', + packages: [ + { + id: 'urn:bnid:_:c14n2', + packagesDescription: 'package 1', + packagesMeasurement: '20', + packagesWeight: '10', + }, + { + id: 'urn:bnid:_:c14n7', + packagesDescription: 'package 2', + packagesMeasurement: '20', + packagesWeight: '10', + }, + ], + attachments: [ + { + id: 'urn:bnid:_:c14n4', + data: 'BASE64_ENCODED_FILE', + filename: 'sample2.pdf', + mimeType: 'application/pdf', + }, + { + id: 'urn:bnid:_:c14n6', + data: 'BASE64_ENCODED_FILE', + filename: 'sample1.pdf', + mimeType: 'application/pdf', + }, + ], + }, + validUntil: '2029-12-03T12:19:52Z', + validFrom: '2024-04-01T12:19:52Z', + issuer: 'did:web:trustvc.github.io:did:1', + proof: { + type: 'BbsBlsSignatureProof2020', + created: '2025-09-17T06:40:25Z', + nonce: 'AVF+U0Wv7Un4OLmZ1JdGSh52zkmorNOncBs2MzuFn+BI7HeIVDQdLsusV57u7ghyWOw=', + proofPurpose: 'assertionMethod', + proofValue: + 'ADd/5AB/////qcx//X8Ll0Y76W4/xUFxxfy8RtX7h6IAVyHknG39MSR2sXKJ2HofXrBZU7aKCos0kvT5fUFr2KfuFL2bynKTQWYoXrXs+xLoxw6OvlvSNYuBq43B780lqgaoC0E8fKb+grA5rXOl7bklgLQxyinq9RTQJOKS7i6nBi6Fo0heBHCx6RX43dxdI0rvAg9QYwmPAAAAdJjk71Wh4YYVRZOPUU5CPdFaVXHce4ZuOzoGhTzgxVF+J44ak+JnGpv3FpaGNahX5AAAAAJOEoIWKyJcaQ3FoNnPtrW6XK4Ce2+wHb6vBIhhRaG0fGFjbsPU2SBWcfPXTdr2V60xidu0A3QC+73cN/hW9RfwpaBQ9KhFQijSFjWku5ZpxUxavAcliupG8rLAVeRRueGsfg08gsFcScyrAwrVBYwAAAAADwsnudyX1IcmJGcmO92k9SfTvnln2TQ0zpZE7TFdkaMCXrkAIpjmP0bZLAdsyo2Zi6R1R08MZJDgRoRYgAevhSIwdtRe0XkendSriPpRwCNheCZi1Rkoh5u8LJX+FdfuZ1g+MdxEdDeKzIjHPHJo4E+2bxT2eqSby0ZHDjxLSBkKHvkjjdc7P92zUP397lKSJ7MxlKN7fQ/2YUaygjDaLsIbfD/76sjJQyBJDo2tGXys/GaJ1aasp1FRf3QUGr1VIhNlpl2OA3wsMdFOnvgueEn122aF0GX1VWECxqDQPnkNHHC5WKdexFxxdUyXiVG5agIH+ajApOM0TUgwpKuZUpkd20v3SD5g5gPuaw5gpEbKjJuuBjlauD8jUeb8l6iu2DeDTgCDeuEU0Ie0MHJFWFR06yDR7RkOsLmo4Dqdg7MaIRXEkgvo/MULe4sn5bAwzG4nycQ8Zc0bIz4tKBCm5rE+m4P3RuQ7AONyzf9BpRH0rradIlHVfKpub+g+AnoDKy+OSOd2kTwgfKt5s/R+8NW6WDhdA8Br+poi83QdFwnyGJwiuGHTEx1H2oWTIKLXmAUaKj5VczzkhFv0pPDiacsoKskKjBdtP+/DbMZ1YXN0x8aFlddoLpQbC9m5ng3B/g==', + verificationMethod: 'did:web:trustvc.github.io:did:1#keys-1', + }, +}; diff --git a/packages/w3c-vc/src/lib/__fixtures__/key-pairs.ts b/packages/w3c-vc/src/lib/__fixtures__/key-pairs.ts new file mode 100644 index 00000000..6735f9db --- /dev/null +++ b/packages/w3c-vc/src/lib/__fixtures__/key-pairs.ts @@ -0,0 +1,34 @@ +import { + Bbs2023PrivateKeyPair, + BBSPrivateKeyPair, + EcdsaSd2023PrivateKeyPair, + VerificationType, +} from '@trustvc/w3c-issuer'; + +export const bbs2020KeyPair: BBSPrivateKeyPair = { + id: 'did:web:trustvc.github.io:did:1#keys-1', + controller: 'did:web:trustvc.github.io:did:1', + type: VerificationType.Bls12381G2Key2020, + publicKeyBase58: + 'oRfEeWFresvhRtXCkihZbxyoi2JER7gHTJ5psXhHsdCoU1MttRMi3Yp9b9fpjmKh7bMgfWKLESiK2YovRd8KGzJsGuamoAXfqDDVhckxuc9nmsJ84skCSTijKeU4pfAcxeJ', + privateKeyBase58: '4LDU56PUhA9ZEutnR1qCWQnUhtLtpLu2EHSq4h1o7vtF', +}; + +export const ecdsa2023KeyPair: EcdsaSd2023PrivateKeyPair = { + '@context': 'https://w3id.org/security/multikey/v1', + id: 'did:web:trustvc.github.io:did:1#multikey-1', + type: VerificationType.Multikey, + controller: 'did:web:trustvc.github.io:did:1', + publicKeyMultibase: 'zDnaemDNwi4G5eTzGfRooFFu5Kns3be6yfyVNtiaMhWkZbwtc', + secretKeyMultibase: 'z42tmUXTVn3n9BihE6NhdMpvVBTnFTgmb6fw18o5Ud6puhRW', +}; + +export const bbs2023KeyPair: Bbs2023PrivateKeyPair = { + '@context': 'https://w3id.org/security/multikey/v1', + id: 'did:web:trustvc.github.io:did:1#multikey-2', + type: VerificationType.Multikey, + controller: 'did:web:trustvc.github.io:did:1', + publicKeyMultibase: + 'zUC7HnpncVAkTjtL6B8prX6bQM2WA5sJ7rXFeCqyrvPnrzoFBjYsVUTNwzhhPUazja73tWwPeEBWCUgq5qBSrtrXiYhVvBCgZPTCiWANj7TSiZJ6SnyC3pkt94GiuChhAvmRRbt', + secretKeyMultibase: 'z488ur1KSFDd3Y1L6pXcPrZRjE18PNBhgzwJvMeoSxKPNysj', +}; diff --git a/packages/w3c-vc/src/lib/__fixtures__/modern-credentials.ts b/packages/w3c-vc/src/lib/__fixtures__/modern-credentials.ts new file mode 100644 index 00000000..12854f2f --- /dev/null +++ b/packages/w3c-vc/src/lib/__fixtures__/modern-credentials.ts @@ -0,0 +1,126 @@ +import { VerifiableCredential } from '../types'; + +// Modern credential for v1.1 testing (used by both ECDSA-SD-2023 and BBS-2023) +export const modernCredentialV1_1: VerifiableCredential = { + '@context': [ + 'https://www.w3.org/2018/credentials/v1', + 'https://w3id.org/security/data-integrity/v2', + 'https://w3id.org/vc/status-list/2021/v1', + 'https://trustvc.io/context/transferable-records-context.json', + 'https://trustvc.io/context/render-method-context.json', + 'https://trustvc.io/context/attachments-context.json', + 'https://trustvc.io/context/qrcode-context.json', + 'https://trustvc.io/context/bill-of-lading.json', + ], + qrCode: { + type: 'TrustVCQRCode', + uri: 'https://localhost:3000/qrcode', + }, + credentialStatus: { + type: 'TransferableRecords', + tokenNetwork: { + chain: 'MATIC', + chainId: '80001', + }, + tokenRegistry: '0xE0a94770B8e969B5D9179d6dA8730B01e19279e2', + }, + credentialSubject: { + billOfLadingName: 'TrustVC Bill of Lading', + scac: 'SGPU', + blNumber: 'SGCNM21566325', + vessel: 'vessel', + voyageNo: 'voyageNo', + portOfLoading: 'Singapore', + portOfDischarge: 'Paris', + carrierName: 'A.P. Moller', + placeOfReceipt: 'Beijing', + placeOfDelivery: 'Singapore', + packages: [ + { packagesDescription: 'package 1', packagesWeight: '10', packagesMeasurement: '20' }, + { packagesDescription: 'package 2', packagesWeight: '10', packagesMeasurement: '20' }, + ], + shipperName: 'Shipper Name', + shipperAddressStreet: '101 ORCHARD ROAD', + shipperAddressCountry: 'SINGAPORE', + consigneeName: 'Consignee name', + notifyPartyName: 'Notify Party Name', + links: 'https://localhost:3000/url', + attachments: [ + { data: 'BASE64_ENCODED_FILE', filename: 'sample1.pdf', mimeType: 'application/pdf' }, + { data: 'BASE64_ENCODED_FILE', filename: 'sample2.pdf', mimeType: 'application/pdf' }, + ], + type: ['BillOfLading'], + }, + renderMethod: [ + { + id: 'https://localhost:3000/renderer', + type: 'EMBEDDED_RENDERER', + templateName: 'BILL_OF_LADING', + }, + ], + expirationDate: '2029-12-03T12:19:52Z', + issuer: 'did:web:trustvc.github.io:did:1', + type: ['VerifiableCredential'], +}; + +// Modern credential for v2.0 testing (used by both ECDSA-SD-2023 and BBS-2023) +export const modernCredentialV2_0: VerifiableCredential = { + '@context': [ + 'https://www.w3.org/ns/credentials/v2', + 'https://w3id.org/security/data-integrity/v2', + 'https://trustvc.io/context/transferable-records-context.json', + 'https://trustvc.io/context/render-method-context-v2.json', + 'https://trustvc.io/context/attachments-context.json', + 'https://trustvc.io/context/qrcode-context.json', + 'https://trustvc.io/context/bill-of-lading.json', + ], + qrCode: { + type: 'TrustVCQRCode', + uri: 'https://localhost:3000/qrcode', + }, + credentialStatus: { + type: 'TransferableRecords', + tokenNetwork: { + chain: 'MATIC', + chainId: '80001', + }, + tokenRegistry: '0xE0a94770B8e969B5D9179d6dA8730B01e19279e2', + }, + credentialSubject: { + billOfLadingName: 'TrustVC Bill of Lading', + scac: 'SGPU', + blNumber: 'SGCNM21566325', + vessel: 'vessel', + voyageNo: 'voyageNo', + portOfLoading: 'Singapore', + portOfDischarge: 'Paris', + carrierName: 'A.P. Moller', + placeOfReceipt: 'Beijing', + placeOfDelivery: 'Singapore', + packages: [ + { packagesDescription: 'package 1', packagesWeight: '10', packagesMeasurement: '20' }, + { packagesDescription: 'package 2', packagesWeight: '10', packagesMeasurement: '20' }, + ], + shipperName: 'Shipper Name', + shipperAddressStreet: '101 ORCHARD ROAD', + shipperAddressCountry: 'SINGAPORE', + consigneeName: 'Consignee name', + notifyPartyName: 'Notify Party Name', + links: 'https://localhost:3000/url', + attachments: [ + { data: 'BASE64_ENCODED_FILE', filename: 'sample1.pdf', mimeType: 'application/pdf' }, + { data: 'BASE64_ENCODED_FILE', filename: 'sample2.pdf', mimeType: 'application/pdf' }, + ], + type: ['BillOfLading'], + }, + renderMethod: [ + { + id: 'https://localhost:3000/renderer', + type: 'EMBEDDED_RENDERER', + templateName: 'BILL_OF_LADING', + }, + ], + validUntil: '2029-12-03T12:19:52Z', + issuer: 'did:web:trustvc.github.io:did:1', + type: ['VerifiableCredential'], +}; diff --git a/packages/w3c-vc/src/lib/__fixtures__/test-scenarios.ts b/packages/w3c-vc/src/lib/__fixtures__/test-scenarios.ts new file mode 100644 index 00000000..5001357a --- /dev/null +++ b/packages/w3c-vc/src/lib/__fixtures__/test-scenarios.ts @@ -0,0 +1,85 @@ +import { CryptoSuiteName, SignedVerifiableCredential, VerifiableCredential } from '../types'; +import { bbs2020KeyPair, bbs2023KeyPair, ecdsa2023KeyPair } from './key-pairs'; +import { modernCredentialV1_1, modernCredentialV2_0 } from './modern-credentials'; +import { + bbs2020CredentialV1_1, + bbs2020DerivedCredentialV1_1, + bbs2020CredentialV2_0, + bbs2020DerivedCredentialV2_0, +} from './bbs2020-credentials'; +import { + Bbs2023PrivateKeyPair, + BBSPrivateKeyPair, + EcdsaSd2023PrivateKeyPair, +} from '@trustvc/w3c-issuer'; + +export interface BBS2020TestScenario { + cryptosuite: CryptoSuiteName; + keyPair: BBSPrivateKeyPair; + version: string; + credential: SignedVerifiableCredential; + derivedCredential: SignedVerifiableCredential; +} + +export interface ModernCryptosuiteTestScenario { + cryptosuite: CryptoSuiteName; + keyPair: EcdsaSd2023PrivateKeyPair | Bbs2023PrivateKeyPair; + version: string; + credential: VerifiableCredential; + dateField: string; + dateValue: string; +} + +// Parameterized test data for BBS2020 (legacy cryptosuite) +export const bbs2020TestScenarios: BBS2020TestScenario[] = [ + { + cryptosuite: 'BbsBlsSignature2020' as CryptoSuiteName, + keyPair: bbs2020KeyPair, + version: 'v1.1', + credential: bbs2020CredentialV1_1, + derivedCredential: bbs2020DerivedCredentialV1_1, + }, + { + cryptosuite: 'BbsBlsSignature2020' as CryptoSuiteName, + keyPair: bbs2020KeyPair, + version: 'v2.0', + credential: bbs2020CredentialV2_0, + derivedCredential: bbs2020DerivedCredentialV2_0, + }, +]; + +// Parameterized test data for modern cryptosuites (ECDSA-SD-2023 and BBS-2023) +export const modernCryptosuiteTestScenarios: ModernCryptosuiteTestScenario[] = [ + { + cryptosuite: 'ecdsa-sd-2023' as CryptoSuiteName, + keyPair: ecdsa2023KeyPair, + version: 'v1.1', + credential: modernCredentialV1_1, + dateField: 'issuanceDate', + dateValue: '2024-04-01T12:19:52Z', + }, + { + cryptosuite: 'ecdsa-sd-2023' as CryptoSuiteName, + keyPair: ecdsa2023KeyPair, + version: 'v2.0', + credential: modernCredentialV2_0, + dateField: 'validFrom', + dateValue: '2024-04-01T12:19:52Z', + }, + { + cryptosuite: 'bbs-2023' as CryptoSuiteName, + keyPair: bbs2023KeyPair, + version: 'v1.1', + credential: modernCredentialV1_1, + dateField: 'issuanceDate', + dateValue: '2024-04-01T12:19:52Z', + }, + { + cryptosuite: 'bbs-2023' as CryptoSuiteName, + keyPair: bbs2023KeyPair, + version: 'v2.0', + credential: modernCredentialV2_0, + dateField: 'validFrom', + dateValue: '2024-04-01T12:19:52Z', + }, +]; diff --git a/packages/w3c-vc/src/lib/helper/index.ts b/packages/w3c-vc/src/lib/helper/index.ts index ee36ed8a..1f9e2f35 100644 --- a/packages/w3c-vc/src/lib/helper/index.ts +++ b/packages/w3c-vc/src/lib/helper/index.ts @@ -350,12 +350,12 @@ function _checkCredentialSubjects(credential: VerifiableCredential): void { if (Array.isArray(credential?.credentialSubject)) { credential?.credentialSubject.map((subject: CredentialSubject) => - _checkCredentialSubject({ subject }), + _checkCredentialSubject(subject), ); return; } - _checkCredentialSubject({ subject: credential?.credentialSubject }); + _checkCredentialSubject(credential?.credentialSubject); } /** @@ -483,9 +483,9 @@ export const prefilCredentialId = ( if (credential.id && isStatusListCredential) { // Keep the existing id for status list credentials } else { - // Use proper URI format for ECDSA-SD-2023 + // Use proper URI format for ECDSA-SD-2023 and BBS-2023 // Use blank node format for BBS+ (maintains backward compatibility) - if (cryptoSuite === 'ecdsa-sd-2023') { + if (cryptoSuite === 'ecdsa-sd-2023' || cryptoSuite === 'bbs-2023') { credential.id = `urn:uuid:${uuidv7()}`; } else { credential.id = `urn:bnid:_:${uuidv7()}`; diff --git a/packages/w3c-vc/src/lib/w3c-vc.test.ts b/packages/w3c-vc/src/lib/w3c-vc.test.ts index c232ba08..68a07d13 100644 --- a/packages/w3c-vc/src/lib/w3c-vc.test.ts +++ b/packages/w3c-vc/src/lib/w3c-vc.test.ts @@ -1,613 +1,319 @@ -import { EcdsaSd2023PrivateKeyPair, VerificationType } from '@trustvc/w3c-issuer'; import { describe, expect, it } from 'vitest'; import { deriveCredential, signCredential, verifyCredential } from './w3c-vc'; -import { VerifiableCredential } from './types'; - -const modifiedCredential: any = { - '@context': [ - 'https://www.w3.org/2018/credentials/v1', - 'https://w3id.org/security/bbs/v1', - 'https://w3id.org/vc/status-list/2021/v1', - 'https://trustvc.io/context/transferable-records-context.json', - 'https://trustvc.io/context/render-method-context.json', - 'https://trustvc.io/context/attachments-context.json', - 'https://trustvc.io/context/qrcode-context.json', - 'https://trustvc.io/context/bill-of-lading.json', - ], - qrCode: { - type: 'TrustVCQRCode', - uri: 'https://localhost:3000/qrcode', - }, - credentialStatus: { - type: 'TransferableRecords', - tokenNetwork: { - chain: 'MATIC', - chainId: '80001', - }, - tokenRegistry: '0xE0a94770B8e969B5D9179d6dA8730B01e19279e2', - }, - credentialSubject: { - billOfLadingName: 'TrustVC Bill of Lading', - scac: 'SGPU', - blNumber: 'SGCNM21566325', - vessel: 'vessel', - voyageNo: 'voyageNo', - portOfLoading: 'Singapore', - portOfDischarge: 'Paris', - carrierName: 'A.P. Moller', - placeOfReceipt: 'Beijing', - placeOfDelivery: 'Singapore', - packages: [ - { packagesDescription: 'package 1', packagesWeight: '10', packagesMeasurement: '20' }, - { packagesDescription: 'package 2', packagesWeight: '10', packagesMeasurement: '20' }, - ], - shipperName: 'Shipper Name', - shipperAddressStreet: '101 ORCHARD ROAD', - shipperAddressCountry: 'SINGAPORE', - consigneeName: 'Consignee name', - notifyPartyName: 'Notify Party Name', - links: 'https://localhost:3000/url', - attachments: [ - { data: 'BASE64_ENCODED_FILE', filename: 'sample1.pdf', mimeType: 'application/pdf' }, - { data: 'BASE64_ENCODED_FILE', filename: 'sample2.pdf', mimeType: 'application/pdf' }, - ], - type: ['BillOfLading'], - }, - renderMethod: [ - { - id: 'https://localhost:3000/renderer', - type: 'EMBEDDED_RENDERER', - templateName: 'BILL_OF_LADING', - }, - ], - expirationDate: '2029-12-03T12:19:52Z', - issuer: 'did:web:trustvc.github.io:did:1', - type: ['VerifiableCredential'], -}; - -const revealDocument: any = { - '@context': [ - 'https://www.w3.org/2018/credentials/v1', - 'https://w3id.org/security/bbs/v1', - 'https://w3id.org/vc/status-list/2021/v1', - 'https://trustvc.io/context/transferable-records-context.json', - 'https://trustvc.io/context/render-method-context.json', - 'https://trustvc.io/context/attachments-context.json', - 'https://trustvc.io/context/qrcode-context.json', - 'https://trustvc.io/context/bill-of-lading.json', - ], - credentialSubject: { - type: ['BillOfLading'], - '@explicit': true, - billOfLadingName: {}, - blNumber: {}, - packages: {}, - shipperName: {}, - attachments: {}, - }, - type: ['VerifiableCredential'], -}; - -const modifiedKeyPair: any = { - id: 'did:web:trustvc.github.io:did:1#keys-1', - controller: 'did:web:trustvc.github.io:did:1', - type: VerificationType.Bls12381G2Key2020, - publicKeyBase58: - 'oRfEeWFresvhRtXCkihZbxyoi2JER7gHTJ5psXhHsdCoU1MttRMi3Yp9b9fpjmKh7bMgfWKLESiK2YovRd8KGzJsGuamoAXfqDDVhckxuc9nmsJ84skCSTijKeU4pfAcxeJ', -}; - -// ECDSA-SD-2023 key pair for testing -const ecdsaKeyPair: EcdsaSd2023PrivateKeyPair = { - '@context': 'https://w3id.org/security/multikey/v1', - id: 'did:web:trustvc.github.io:did:1#multikey-1', - type: VerificationType.Multikey, - controller: 'did:web:trustvc.github.io:did:1', - publicKeyMultibase: 'zDnaemDNwi4G5eTzGfRooFFu5Kns3be6yfyVNtiaMhWkZbwtc', - secretKeyMultibase: 'z42tmUXTVn3n9BihE6NhdMpvVBTnFTgmb6fw18o5Ud6puhRW', -}; - -// Modified ECDSA-SD-2023 credential for v1.1 testing -const ecdsaCredentialV1_1: VerifiableCredential = { - '@context': [ - 'https://www.w3.org/2018/credentials/v1', - 'https://w3id.org/security/data-integrity/v2', - 'https://w3id.org/vc/status-list/2021/v1', - 'https://trustvc.io/context/transferable-records-context.json', - 'https://trustvc.io/context/render-method-context.json', - 'https://trustvc.io/context/attachments-context.json', - 'https://trustvc.io/context/qrcode-context.json', - 'https://trustvc.io/context/bill-of-lading.json', - ], - qrCode: { - type: 'TrustVCQRCode', - uri: 'https://localhost:3000/qrcode', - }, - credentialStatus: { - type: 'TransferableRecords', - tokenNetwork: { - chain: 'MATIC', - chainId: '80001', - }, - tokenRegistry: '0xE0a94770B8e969B5D9179d6dA8730B01e19279e2', - }, - credentialSubject: { - billOfLadingName: 'TrustVC Bill of Lading', - scac: 'SGPU', - blNumber: 'SGCNM21566325', - vessel: 'vessel', - voyageNo: 'voyageNo', - portOfLoading: 'Singapore', - portOfDischarge: 'Paris', - carrierName: 'A.P. Moller', - placeOfReceipt: 'Beijing', - placeOfDelivery: 'Singapore', - packages: [ - { packagesDescription: 'package 1', packagesWeight: '10', packagesMeasurement: '20' }, - { packagesDescription: 'package 2', packagesWeight: '10', packagesMeasurement: '20' }, - ], - shipperName: 'Shipper Name', - shipperAddressStreet: '101 ORCHARD ROAD', - shipperAddressCountry: 'SINGAPORE', - consigneeName: 'Consignee name', - notifyPartyName: 'Notify Party Name', - links: 'https://localhost:3000/url', - attachments: [ - { data: 'BASE64_ENCODED_FILE', filename: 'sample1.pdf', mimeType: 'application/pdf' }, - { data: 'BASE64_ENCODED_FILE', filename: 'sample2.pdf', mimeType: 'application/pdf' }, - ], - type: ['BillOfLading'], - }, - renderMethod: [ - { - id: 'https://localhost:3000/renderer', - type: 'EMBEDDED_RENDERER', - templateName: 'BILL_OF_LADING', - }, - ], - expirationDate: '2029-12-03T12:19:52Z', - issuer: 'did:web:trustvc.github.io:did:1', - type: ['VerifiableCredential'], -}; - -// Modified ECDSA-SD-2023 credential for v2.0 testing -const ecdsaCredentialV2_0: VerifiableCredential = { - '@context': [ - 'https://www.w3.org/ns/credentials/v2', - 'https://w3id.org/security/data-integrity/v2', - 'https://w3id.org/vc/status-list/2021/v1', - 'https://trustvc.io/context/transferable-records-context.json', - 'https://trustvc.io/context/render-method-context-v2.json', - 'https://trustvc.io/context/attachments-context.json', - 'https://trustvc.io/context/qrcode-context.json', - 'https://trustvc.io/context/bill-of-lading.json', - ], - qrCode: { - type: 'TrustVCQRCode', - uri: 'https://localhost:3000/qrcode', - }, - credentialStatus: { - type: 'TransferableRecords', - tokenNetwork: { - chain: 'MATIC', - chainId: '80001', - }, - tokenRegistry: '0xE0a94770B8e969B5D9179d6dA8730B01e19279e2', - }, - credentialSubject: { - billOfLadingName: 'TrustVC Bill of Lading', - scac: 'SGPU', - blNumber: 'SGCNM21566325', - vessel: 'vessel', - voyageNo: 'voyageNo', - portOfLoading: 'Singapore', - portOfDischarge: 'Paris', - carrierName: 'A.P. Moller', - placeOfReceipt: 'Beijing', - placeOfDelivery: 'Singapore', - packages: [ - { packagesDescription: 'package 1', packagesWeight: '10', packagesMeasurement: '20' }, - { packagesDescription: 'package 2', packagesWeight: '10', packagesMeasurement: '20' }, - ], - shipperName: 'Shipper Name', - shipperAddressStreet: '101 ORCHARD ROAD', - shipperAddressCountry: 'SINGAPORE', - consigneeName: 'Consignee name', - notifyPartyName: 'Notify Party Name', - links: 'https://localhost:3000/url', - attachments: [ - { data: 'BASE64_ENCODED_FILE', filename: 'sample1.pdf', mimeType: 'application/pdf' }, - { data: 'BASE64_ENCODED_FILE', filename: 'sample2.pdf', mimeType: 'application/pdf' }, - ], - type: ['BillOfLading'], - }, - renderMethod: [ - { - id: 'https://localhost:3000/renderer', - type: 'EMBEDDED_RENDERER', - templateName: 'BILL_OF_LADING', - }, - ], - validUntil: '2029-12-03T12:19:52Z', - issuer: 'did:web:trustvc.github.io:did:1', - type: ['VerifiableCredential'], -}; - -// Parameterized test data for ECDSA-SD-2023 tests -const ecdsaTestScenarios = [ - { - version: 'v1.1', - credential: ecdsaCredentialV1_1, - dateField: 'issuanceDate', - dateValue: '2024-04-01T12:19:52Z', - }, - { - version: 'v2.0', - credential: ecdsaCredentialV2_0, - dateField: 'validFrom', - dateValue: '2024-04-01T12:19:52Z', - }, -]; - -describe('BBS+ v1.1 Credential Signing and Verification', () => { - it('should successfully sign, derive and verify a credential', async () => { - let signingKeyPair = modifiedKeyPair; - signingKeyPair = { - ...signingKeyPair, - privateKeyBase58: '4LDU56PUhA9ZEutnR1qCWQnUhtLtpLu2EHSq4h1o7vtF', - }; - - let credential = modifiedCredential; - credential = { ...credential, issuanceDate: '2024-04-01T12:19:52Z' }; - - const signedCredential = await signCredential(credential, signingKeyPair); - expect(signedCredential.signed).toBeDefined(); - expect(signedCredential.error).toBeUndefined(); - - let verificationResult = await verifyCredential(signedCredential.signed); - expect(verificationResult.verified).toBe(true); - expect(verificationResult.error).toBeUndefined(); - - const derivedCredential = await deriveCredential(signedCredential.signed, revealDocument); - expect(derivedCredential.derived).toBeDefined(); - expect(derivedCredential.error).toBeUndefined(); - - verificationResult = await verifyCredential(derivedCredential.derived); - expect(verificationResult.verified).toBe(true); - expect(verificationResult.error).toBeUndefined(); - }); - - it('should fail to sign if the private key is missing from the key pair', async () => { - let credential = modifiedCredential; - credential = { ...credential, issuanceDate: '2024-04-01T12:19:52Z' }; - - const signedCredential = await signCredential(credential, modifiedKeyPair); - expect(signedCredential.signed).toBeUndefined(); - expect(signedCredential.error).toBeDefined(); - expect(signedCredential.error).equals('"privateKeyBase58" property in keyPair is required.'); - }); - - it('should fail to sign if the id field is present in the credential', async () => { - let signingKeyPair = modifiedKeyPair; - signingKeyPair = { - ...signingKeyPair, - privateKeyBase58: '4LDU56PUhA9ZEutnR1qCWQnUhtLtpLu2EHSq4h1o7vtF', - }; - - let credential = modifiedCredential; - credential = { - ...credential, - issuanceDate: '2024-04-01T12:19:52Z', - id: 'urn:uuid:0192d19c-d82c-7cc7-9431-cb495374f43b', - }; - - const signedCredential = await signCredential(credential, signingKeyPair); - expect(signedCredential.signed).toBeUndefined(); - expect(signedCredential.error).toBeDefined(); - expect(signedCredential.error).equals( - '"id" is a defined field and should not be set by the user.', - ); - }); - - it('should fail to sign if a required property in the credential is missing', async () => { - let signingKeyPair = modifiedKeyPair; - signingKeyPair = { - ...signingKeyPair, - privateKeyBase58: '4LDU56PUhA9ZEutnR1qCWQnUhtLtpLu2EHSq4h1o7vtF', - }; - - const signedCredential = await signCredential(modifiedCredential, signingKeyPair); - expect(signedCredential.signed).toBeUndefined(); - expect(signedCredential.error).toBeDefined(); - expect(signedCredential.error).equals('"issuanceDate" property is required.'); - }); - - it('should fail verification if the signed credential is tampered with', async () => { - let signedCredential = modifiedCredential; - signedCredential = { - ...signedCredential, - id: 'urn:bnid:_:0193b647-66b6-7ffc-ae79-ef9c590f3301', - credentialStatus: { - ...signedCredential.credentialStatus, - tokenId: '398124e7f1ec797a3dea6322e5ce4ff5ee242ab6293c2acf41a95178dfb27dae', +import { + modernCryptosuiteTestScenarios, + bbs2020TestScenarios, +} from './__fixtures__/test-scenarios'; + +/** + * W3C Verifiable Credentials Test Suite + * + * This test suite covers: + * - Modern cryptosuites: ECDSA-SD-2023 and BBS-2023 (full functionality) + * - Legacy BBS2020 cryptosuite (deprecation + verification) + */ +describe('W3C Verifiable Credentials', () => { + describe('Legacy BBS2020 Cryptosuite', () => { + describe.each(bbs2020TestScenarios)( + 'BBS2020 $version Operations (Deprecated)', + ({ cryptosuite, keyPair, credential, derivedCredential }) => { + it('should return deprecation error when signing', async () => { + // Remove proof to get unsigned credential + const { proof: _proof, ...testCredential } = credential; + + // BBS2020 signing should return deprecation error + const signedCredential = await signCredential(testCredential, keyPair, cryptosuite); + expect(signedCredential.signed).toBeUndefined(); + expect(signedCredential.error).toBe( + 'BbsBlsSignature2020 is no longer supported. Please use the latest cryptosuite versions instead.', + ); + }); + + it('should return deprecation error when deriving', async () => { + // BBS2020 derivation should return deprecation error + const revealDocument: any = { + '@context': credential['@context'], + credentialSubject: { + type: ['BillOfLading'], + '@explicit': true, + billOfLadingName: {}, + blNumber: {}, + }, + type: ['VerifiableCredential'], + }; + + const derivedResult = await deriveCredential(credential, revealDocument); + expect(derivedResult.derived).toBeUndefined(); + expect(derivedResult.error).toBe( + 'BbsBlsSignature2020 is no longer supported for derivation. Please use the latest cryptosuite versions instead.', + ); + }); + + it('should still verify existing credentials (backward compatibility)', async () => { + // Should still be able to verify existing BBS2020 credentials + const baseVerificationResult = await verifyCredential(credential); + expect(baseVerificationResult.verified).toBe(true); + expect(baseVerificationResult.error).toBeUndefined(); + + const derivedVerificationResult = await verifyCredential(derivedCredential); + expect(derivedVerificationResult.verified).toBe(true); + expect(derivedVerificationResult.error).toBeUndefined(); + }); + + it('should detect tampered credentials (comprehensive security)', async () => { + // Test tampering with base credential - modify credentialSubject + const tamperedBaseCredential = { + ...credential, + credentialSubject: { + ...credential.credentialSubject, + billOfLadingName: 'TAMPERED Bill of Lading', + }, + }; + + const baseVerificationResult = await verifyCredential(tamperedBaseCredential); + expect(baseVerificationResult.verified).toBe(false); + expect(baseVerificationResult.error).toBeDefined(); + + // Test tampering with base credential proof value + const tamperedProofCredential = { + ...credential, + proof: { + ...credential.proof, + proofValue: credential.proof.proofValue.replace(/A/g, 'B'), + }, + }; + + const proofVerificationResult = await verifyCredential(tamperedProofCredential); + expect(proofVerificationResult.verified).toBe(false); + expect(proofVerificationResult.error).toBeDefined(); + + // Test tampering with derived credential - modify credentialSubject + const tamperedDerivedCredential = { + ...derivedCredential, + credentialSubject: { + ...derivedCredential.credentialSubject, + billOfLadingName: 'TAMPERED Derived Bill of Lading', + }, + }; + + const derivedVerificationResult = await verifyCredential(tamperedDerivedCredential); + expect(derivedVerificationResult.verified).toBe(false); + expect(derivedVerificationResult.error).toBeDefined(); + + // Test tampering with derived credential proof value + const tamperedDerivedProofCredential = { + ...derivedCredential, + proof: { + ...derivedCredential.proof, + proofValue: derivedCredential.proof.proofValue.replace(/A/g, 'B'), + }, + }; + + const derivedProofVerificationResult = await verifyCredential( + tamperedDerivedProofCredential, + ); + expect(derivedProofVerificationResult.verified).toBe(false); + expect(derivedProofVerificationResult.error).toBeDefined(); + }); }, - issuanceDate: '2024-04-01T12:19:53Z', - proof: { - type: 'BbsBlsSignature2020', - created: '2024-08-23T03:08:31Z', - proofPurpose: 'assertionMethod', - proofValue: - 'sHGTYvavHMHVJ3NgyEgiyDDa0IjG3wS9GChizckQHANWzcZRqBjD4uSZjxmS2fGzEgJJB6/JaL7FY9rx42Bkg/SRjvaaUiBVyOwUXeXUZMdlGEIpjzO8GDognziPqN7S9KEZagvnv3MESEx0EwvgEw==', - verificationMethod: 'did:web:trustvc.github.io:did:1#keys-1', - }, - }; - - const verificationResult = await verifyCredential(signedCredential); - expect(verificationResult.verified).toBe(false); - expect(verificationResult.error).equals('Invalid signature.'); - }); - - it('should fail verification if an unsupported signature suite is used', async () => { - let signedCredential = modifiedCredential; - signedCredential = { - ...signedCredential, - issuanceDate: '2024-04-01T12:19:52Z', - proof: { - type: 'Ed25519Signature2020', - created: '2024-08-23T03:08:31Z', - proofPurpose: 'assertionMethod', - proofValue: - 'sHGTYvavHMHVJ3NgyEgiyDDa0IjG3wS9GChizckQHANWzcZRqBjD4uSZjxmS2fGzEgJJB6/JaL7FY9rx42Bkg/SRjvaaUiBVyOwUXeXUZMdlGEIpjzO8GDognziPqN7S9KEZagvnv3MESEx0EwvgEw==', - verificationMethod: 'did:web:trustvc.github.io:did:1#keys-1', - }, - }; - - const verificationResult = await verifyCredential(signedCredential); - expect(verificationResult.verified).toBe(false); - expect(verificationResult.error).equals('"proof" type is not of BbsBlsSignature2020.'); + ); }); - it('should fail verification if the verification method cannot be found', async () => { - let signedCredential = modifiedCredential; - signedCredential = { - ...signedCredential, - id: 'urn:bnid:_:0193b647-66b6-7ffc-ae79-ef9c590f3301', - credentialStatus: { - ...signedCredential.credentialStatus, - tokenId: '398124e7f1ec797a3dea6322e5ce4ff5ee242ab6293c2acf41a95178dfb27dae', - }, - issuanceDate: '2024-04-01T12:19:52Z', - proof: { - type: 'BbsBlsSignature2020', - created: '2024-08-23T03:08:31Z', - proofPurpose: 'assertionMethod', - proofValue: - 'sHGTYvavHMHVJ3NgyEgiyDDa0IjG3wS9GChizckQHANWzcZRqBjD4uSZjxmS2fGzEgJJB6/JaL7FY9rx42Bkg/SRjvaaUiBVyOwUXeXUZMdlGEIpjzO8GDognziPqN7S9KEZagvnv3MESEx0EwvgEw==', - verificationMethod: 'did:web:trustvc.github.io:did:1#keys-2', + describe('Modern Cryptosuites (ECDSA-SD-2023 & BBS-2023)', () => { + describe.each(modernCryptosuiteTestScenarios)( + '$cryptosuite $version Credential Operations', + ({ cryptosuite, keyPair, credential, dateField, dateValue }) => { + it('should successfully sign, derive, and verify credentials', async () => { + const testCredential = { ...credential, [dateField]: dateValue }; + + // Sign the credential + const signedCredential = await signCredential(testCredential, keyPair, cryptosuite); + expect(signedCredential.signed).toBeDefined(); + expect(signedCredential.error).toBeUndefined(); + expect(signedCredential.signed?.proof?.type).toBe('DataIntegrityProof'); + + // Derive the credential with selective disclosure + const selectivePointers = ['/credentialSubject/billOfLadingName']; + const derivedCredential = await deriveCredential( + signedCredential.signed, + selectivePointers, + ); + expect(derivedCredential.derived).toBeDefined(); + expect(derivedCredential.error).toBeUndefined(); + + // Verify core mandatory pointers are included + expect(derivedCredential.derived?.issuer).toBeDefined(); + expect(derivedCredential.derived?.[dateField]).toBeDefined(); + + // Verify selective disclosure works + const credentialSubject = Array.isArray(derivedCredential.derived?.credentialSubject) + ? derivedCredential.derived?.credentialSubject[0] + : derivedCredential.derived?.credentialSubject; + expect(credentialSubject?.billOfLadingName).toBeDefined(); + expect(credentialSubject?.blNumber).toBeUndefined(); + + // Verify the derived credential + const verificationResult = await verifyCredential(derivedCredential.derived); + expect(verificationResult.verified).toBe(true); + expect(verificationResult.error).toBeUndefined(); + }); + + it('should support custom mandatory pointers with selective disclosure', async () => { + const testCredential = { ...credential, [dateField]: dateValue }; + + // Sign with custom mandatory pointers + const customMandatoryPointers = ['/credentialSubject/billOfLadingName']; + const signedCredential = await signCredential(testCredential, keyPair, cryptosuite, { + mandatoryPointers: customMandatoryPointers, + }); + expect(signedCredential.signed).toBeDefined(); + expect(signedCredential.error).toBeUndefined(); + + // Derive with selective disclosure + const selectivePointers = ['/credentialSubject/blNumber']; + const derivedCredential = await deriveCredential( + signedCredential.signed, + selectivePointers, + ); + expect(derivedCredential.derived).toBeDefined(); + expect(derivedCredential.error).toBeUndefined(); + + // Verify mandatory and selective pointers are included + const credentialSubject = Array.isArray(derivedCredential.derived?.credentialSubject) + ? derivedCredential.derived?.credentialSubject[0] + : derivedCredential.derived?.credentialSubject; + expect(credentialSubject?.billOfLadingName).toBeDefined(); // Mandatory + expect(credentialSubject?.blNumber).toBeDefined(); // Selected + expect(credentialSubject?.scac).toBeUndefined(); // Not selected + + // Verify the derived credential + const verificationResult = await verifyCredential(derivedCredential.derived); + expect(verificationResult.verified).toBe(true); + expect(verificationResult.error).toBeUndefined(); + }); + + it('should automatically include entire credentialSubject when no properties selected', async () => { + const testCredential = { ...credential, [dateField]: dateValue }; + + // Sign the credential + const signedCredential = await signCredential(testCredential, keyPair, cryptosuite); + expect(signedCredential.signed).toBeDefined(); + + // Derive with no credentialSubject pointers + const selectivePointers: string[] = []; + const derivedCredential = await deriveCredential( + signedCredential.signed, + selectivePointers, + ); + expect(derivedCredential.derived).toBeDefined(); + + // Verify entire credentialSubject is included + const credentialSubject = Array.isArray(derivedCredential.derived?.credentialSubject) + ? derivedCredential.derived?.credentialSubject[0] + : derivedCredential.derived?.credentialSubject; + expect(credentialSubject?.scac).toBeDefined(); + expect(credentialSubject?.vessel).toBeDefined(); + expect(credentialSubject?.billOfLadingName).toBeDefined(); + expect(credentialSubject?.blNumber).toBeDefined(); + + // Verify the derived credential + const verificationResult = await verifyCredential(derivedCredential.derived); + expect(verificationResult.verified).toBe(true); + expect(verificationResult.error).toBeUndefined(); + }); + + it('should require derivation before verification', async () => { + const testCredential = { ...credential, [dateField]: dateValue }; + + // Sign the credential + const signedCredential = await signCredential(testCredential, keyPair, cryptosuite); + expect(signedCredential.signed).toBeDefined(); + + // Verify original signed credential directly (should fail) + const verificationResult = await verifyCredential(signedCredential.signed); + expect(verificationResult.verified).toBe(false); + expect(verificationResult.error).toBe( + `${cryptosuite} base credentials must be derived before verification. Use deriveCredential() first.`, + ); + }); + + it('should prevent multiple rounds of derivation', async () => { + const testCredential = { ...credential, [dateField]: dateValue }; + + // Sign and first derivation + const signedCredential = await signCredential(testCredential, keyPair, cryptosuite); + const firstDerivedCredential = await deriveCredential(signedCredential.signed, [ + '/credentialSubject/blNumber', + ]); + expect(firstDerivedCredential.derived).toBeDefined(); + + // Attempt second derivation (should fail) + const secondDerivedCredential = await deriveCredential(firstDerivedCredential.derived, [ + '/credentialSubject/billOfLadingName', + ]); + expect(secondDerivedCredential.derived).toBeUndefined(); + expect(secondDerivedCredential.error).toBe( + `${cryptosuite} derived credentials cannot be further derived. Multiple rounds of derivation are not supported by this cryptosuite.`, + ); + }); + + it('should detect tampered credentials', async () => { + const testCredential = { ...credential, [dateField]: dateValue }; + + // Sign and derive credential + const signedCredential = await signCredential(testCredential, keyPair, cryptosuite); + const derivedCredential = await deriveCredential(signedCredential.signed, [ + '/credentialSubject/billOfLadingName', + ]); + + // Tamper with the derived credential + const tamperedCredential = { + ...derivedCredential.derived, + [dateField]: new Date().toISOString(), + }; + + // Verify tampered credential (should fail) + const verificationResult = await verifyCredential(tamperedCredential); + expect(verificationResult.verified).toBe(false); + expect(verificationResult.error).equals('Invalid signature.'); + }); + + it('should validate key pair requirements', async () => { + const testCredential = { ...credential, [dateField]: dateValue }; + + const invalidKeyPair: any = { + id: 'did:web:trustvc.github.io:did:1#multikey-1', + type: 'Multikey', + controller: 'did:web:trustvc.github.io:did:1', + publicKeyMultibase: 'zDnaemDNwi4G5eTzGfRooFFu5Kns3be6yfyVNtiaMhWkZbwtc', + // Missing secretKeyMultibase + }; + + // Sign with invalid key pair (should fail) + const signedCredential = await signCredential( + testCredential, + invalidKeyPair, + cryptosuite, + ); + expect(signedCredential.signed).toBeUndefined(); + expect(signedCredential.error).toBe( + '"secretKeyMultibase" property in keyPair is required.', + ); + }); + + it('should reject unsupported cryptosuites', async () => { + const testCredential = { ...credential, [dateField]: dateValue }; + + // Sign with unsupported cryptosuite (should fail) + const signedCredential = await signCredential( + testCredential, + keyPair, + 'unsupported-suite' as any, + ); + expect(signedCredential.signed).toBeUndefined(); + expect(signedCredential.error).toBe('"unsupported-suite" is not supported.'); + }); }, - }; - - const verificationResult = await verifyCredential(signedCredential); - expect(verificationResult.verified).toBe(false); - expect(verificationResult.error).equals( - 'Verification method did:web:trustvc.github.io:did:1#keys-2 could not be found.', ); }); }); - -describe.each(ecdsaTestScenarios)( - 'ECDSA-SD-2023 $version Credential Signing and Verification', - ({ version, credential, dateField, dateValue }) => { - it(`should successfully sign, derive, and verify a ${version} credential with ECDSA-SD-2023`, async () => { - const testCredential = { ...credential, [dateField]: dateValue }; - - // Sign the credential - const signedCredential = await signCredential(testCredential, ecdsaKeyPair, 'ecdsa-sd-2023'); - expect(signedCredential.signed).toBeDefined(); - expect(signedCredential.error).toBeUndefined(); - expect(signedCredential.signed?.proof?.type).toBe('DataIntegrityProof'); - - // Derive the credential with selective disclosure - const selectivePointers = ['/credentialSubject/billOfLadingName']; - const derivedCredential = await deriveCredential(signedCredential.signed, selectivePointers); - expect(derivedCredential.derived).toBeDefined(); - expect(derivedCredential.error).toBeUndefined(); - - // Verify that mandatory core pointers are always included - expect(derivedCredential.derived?.issuer).toBeDefined(); // Core mandatory: /issuer - expect(derivedCredential.derived?.[dateField]).toBeDefined(); // Core mandatory: date field - - // Verify that selective disclosure works within credentialSubject - const credentialSubject = Array.isArray(derivedCredential.derived?.credentialSubject) - ? derivedCredential.derived?.credentialSubject[0] - : derivedCredential.derived?.credentialSubject; - expect(credentialSubject?.billOfLadingName).toBeDefined(); // Selected field - expect(credentialSubject?.blNumber).toBeUndefined(); // Not selected, should be hidden - - // Verify the derived credential - const verificationResult = await verifyCredential(derivedCredential.derived); - expect(verificationResult.verified).toBe(true); - expect(verificationResult.error).toBeUndefined(); - }); - - it(`should successfully sign ${version} credential with custom mandatory pointers, derive, and verify`, async () => { - const testCredential = { ...credential, [dateField]: dateValue }; - - // Sign with mandatory pointers (core pointers will be added automatically) - const customMandatoryPointers = ['/credentialSubject/billOfLadingName']; - const signedCredential = await signCredential(testCredential, ecdsaKeyPair, 'ecdsa-sd-2023', { - mandatoryPointers: customMandatoryPointers, - }); - expect(signedCredential.signed).toBeDefined(); - expect(signedCredential.error).toBeUndefined(); - expect(signedCredential.signed?.proof?.type).toBe('DataIntegrityProof'); - - // Derive with selective disclosure (only reveal specific fields) - const selectivePointers = ['/credentialSubject/blNumber']; - const derivedCredential = await deriveCredential(signedCredential.signed, selectivePointers); - expect(derivedCredential.derived).toBeDefined(); - expect(derivedCredential.error).toBeUndefined(); - - // Verify that mandatory core pointers are always included (automatically added) - expect(derivedCredential.derived?.issuer).toBeDefined(); // Core mandatory: /issuer - expect(derivedCredential.derived?.[dateField]).toBeDefined(); // Core mandatory: date field - - // Verify that mandatory pointers are always included - const credentialSubject = Array.isArray(derivedCredential.derived?.credentialSubject) - ? derivedCredential.derived?.credentialSubject[0] - : derivedCredential.derived?.credentialSubject; - expect(credentialSubject?.billOfLadingName).toBeDefined(); // Custom mandatory - - // Verify that selective pointers are included - expect(credentialSubject?.blNumber).toBeDefined(); // Selected field - expect(credentialSubject?.scac).toBeUndefined(); // Not selected, should be hidden - - // Verify the derived credential - const verificationResult = await verifyCredential(derivedCredential.derived); - expect(verificationResult.verified).toBe(true); - expect(verificationResult.error).toBeUndefined(); - }); - - it(`should automatically include entire credentialSubject when no credentialSubject properties are selected (${version})`, async () => { - const testCredential = { ...credential, [dateField]: dateValue }; - - // Sign the credential - const signedCredential = await signCredential(testCredential, ecdsaKeyPair, 'ecdsa-sd-2023'); - expect(signedCredential.signed).toBeDefined(); - expect(signedCredential.error).toBeUndefined(); - expect(signedCredential.signed?.proof?.type).toBe('DataIntegrityProof'); - - // Derive with no credentialSubject pointers - should automatically include entire credentialSubject - const selectivePointers: string[] = []; - const derivedCredential = await deriveCredential(signedCredential.signed, selectivePointers); - expect(derivedCredential.derived).toBeDefined(); - expect(derivedCredential.error).toBeUndefined(); - - // Verify that core mandatory pointers are automatically included - expect(derivedCredential.derived?.issuer).toBeDefined(); // Core mandatory: /issuer (auto-added) - expect(derivedCredential.derived?.[dateField]).toBeDefined(); // Core mandatory: date field (auto-added) - - // Verify that entire credentialSubject is included (since no credentialSubject properties were selected) - const credentialSubject = Array.isArray(derivedCredential.derived?.credentialSubject) - ? derivedCredential.derived?.credentialSubject[0] - : derivedCredential.derived?.credentialSubject; - expect(credentialSubject?.scac).toBeDefined(); // All properties should be present - expect(credentialSubject?.vessel).toBeDefined(); // All properties should be present - expect(credentialSubject?.billOfLadingName).toBeDefined(); // All properties should be present - expect(credentialSubject?.blNumber).toBeDefined(); // All properties should be present - - // Verify the derived credential - const verificationResult = await verifyCredential(derivedCredential.derived); - expect(verificationResult.verified).toBe(true); - expect(verificationResult.error).toBeUndefined(); - }); - - it(`should require derivation before verification for ECDSA-SD-2023 ${version} credentials`, async () => { - const testCredential = { ...credential, [dateField]: dateValue }; - - // Sign the credential - const signedCredential = await signCredential(testCredential, ecdsaKeyPair, 'ecdsa-sd-2023'); - expect(signedCredential.signed).toBeDefined(); - expect(signedCredential.error).toBeUndefined(); - - // Verify the original signed credential directly (without derivation) - should fail - // ECDSA-SD-2023 credentials require derivation before verification - const verificationResult = await verifyCredential(signedCredential.signed); - expect(verificationResult.verified).toBe(false); - expect(verificationResult.error).toBeDefined(); - expect(verificationResult.error).toBe( - 'ecdsa-sd-2023 base credentials must be derived before verification. Use deriveCredential() first.', - ); - }); - - it(`should fail when attempting to derive from an already derived ECDSA-SD-2023 ${version} credential`, async () => { - const testCredential = { ...credential, [dateField]: dateValue }; - - // Sign the credential - const signedCredential = await signCredential(testCredential, ecdsaKeyPair, 'ecdsa-sd-2023'); - expect(signedCredential.signed).toBeDefined(); - expect(signedCredential.error).toBeUndefined(); - - // First derivation - should succeed - const selectivePointers = ['/credentialSubject/blNumber']; - const firstDerivedCredential = await deriveCredential( - signedCredential.signed, - selectivePointers, - ); - expect(firstDerivedCredential.derived).toBeDefined(); - expect(firstDerivedCredential.error).toBeUndefined(); - - // Attempt second derivation from the already derived credential - should fail - const secondSelectivePointers = ['/credentialSubject/billOfLadingName']; - const secondDerivedCredential = await deriveCredential( - firstDerivedCredential.derived, - secondSelectivePointers, - ); - expect(secondDerivedCredential.derived).toBeUndefined(); - expect(secondDerivedCredential.error).toBeDefined(); - expect(secondDerivedCredential.error).toBe( - 'ecdsa-sd-2023 derived credentials cannot be further derived. Multiple rounds of derivation are not supported by this cryptosuite.', - ); - }); - - it(`should fail verification if the ${version} credential is tampered with`, async () => { - const testCredential = { ...credential, [dateField]: dateValue }; - - // Sign the credential - const signedCredential = await signCredential(testCredential, ecdsaKeyPair, 'ecdsa-sd-2023'); - expect(signedCredential.signed).toBeDefined(); - expect(signedCredential.error).toBeUndefined(); - - // Derive the credential with selective disclosure - const selectivePointers = ['/credentialSubject/billOfLadingName']; - const derivedCredential = await deriveCredential(signedCredential.signed, selectivePointers); - expect(derivedCredential.derived).toBeDefined(); - expect(derivedCredential.error).toBeUndefined(); - - const tamperedCredential = { - ...derivedCredential.derived, - [dateField]: new Date().toISOString(), - }; - - // Verify the derived credential - should fail - const verificationResult = await verifyCredential(tamperedCredential); - expect(verificationResult.verified).toBe(false); - expect(verificationResult.error).equals('Invalid signature.'); - }); - - it(`should fail to sign with ECDSA-SD-2023 if key pair is missing required properties (${version})`, async () => { - const testCredential = { ...credential, [dateField]: dateValue }; - - const invalidKeyPair: any = { - id: 'did:web:trustvc.github.io:did:1#multikey-1', - type: 'Multikey', - controller: 'did:web:trustvc.github.io:did:1', - publicKeyMultibase: 'zDnaemDNwi4G5eTzGfRooFFu5Kns3be6yfyVNtiaMhWkZbwtc', - // Missing secretKeyMultibase - }; - - // Sign the credential - const signedCredential = await signCredential( - testCredential, - invalidKeyPair, - 'ecdsa-sd-2023', - ); - expect(signedCredential.signed).toBeUndefined(); - expect(signedCredential.error).toBeDefined(); - expect(signedCredential.error).toBe('"secretKeyMultibase" property in keyPair is required.'); - }); - - it(`should fail to sign with unsupported cryptosuite (${version})`, async () => { - const testCredential = { ...credential, [dateField]: dateValue }; - - // Sign the credential - const signedCredential = await signCredential( - testCredential, - ecdsaKeyPair, - 'unsupported-suite' as any, - ); - expect(signedCredential.signed).toBeUndefined(); - expect(signedCredential.error).toBeDefined(); - expect(signedCredential.error).toBe('"unsupported-suite" is not supported.'); - }); - }, -); diff --git a/packages/w3c-vc/src/lib/w3c-vc.ts b/packages/w3c-vc/src/lib/w3c-vc.ts index 968756ef..c53dc034 100644 --- a/packages/w3c-vc/src/lib/w3c-vc.ts +++ b/packages/w3c-vc/src/lib/w3c-vc.ts @@ -1,19 +1,9 @@ -import { KeyPairOptions } from '@mattrglobal/bls12381-key-pair'; -import { - BbsBlsSignature2020, - BbsBlsSignatureProof2020, - Bls12381G2KeyPair, - deriveProof, -} from '@mattrglobal/jsonld-signatures-bbs'; import * as EcdsaMultikey from '@digitalbazaar/ecdsa-multikey'; import * as ecdsaSd2023Cryptosuite from '@digitalbazaar/ecdsa-sd-2023-cryptosuite'; +import * as Bls12381Multikey from '@digitalbazaar/bls12-381-multikey'; +import * as bbs2023Cryptosuite from '@digitalbazaar/bbs-2023-cryptosuite'; import { DataIntegrityProof } from '@digitalbazaar/data-integrity'; -import { - ContextDocument, - CredentialContextVersion, - DocumentLoader, - getDocumentLoader, -} from '@trustvc/w3c-context'; +import { CredentialContextVersion, DocumentLoader, getDocumentLoader } from '@trustvc/w3c-context'; import { PrivateKeyPair } from '@trustvc/w3c-issuer'; import jsonldSignatures from 'jsonld-signatures'; import jsonldSignaturesV7 from 'jsonld-signatures-v7'; @@ -30,8 +20,16 @@ import { VerificationResult, } from './types'; -const { createSignCryptosuite, createDiscloseCryptosuite, createVerifyCryptosuite } = - ecdsaSd2023Cryptosuite; +const { + createSignCryptosuite: createEcdsaSd2023SignCryptosuite, + createDiscloseCryptosuite: createEcdsaSd2023DiscloseCryptosuite, + createVerifyCryptosuite: createEcdsaSd2023VerifyCryptosuite, +} = ecdsaSd2023Cryptosuite; +const { + createSignCryptosuite: createBbs2023SignCryptosuite, + createDiscloseCryptosuite: createBbs2023DiscloseCryptosuite, + createVerifyCryptosuite: createBbs2023VerifyCryptosuite, +} = bbs2023Cryptosuite; const { purposes: { AssertionProofPurpose }, } = jsonldSignatures; @@ -131,6 +129,37 @@ const isEcdsaSdBaseProof = async (proofValue: string): Promise => { } }; +const isBbs2023BaseProof = async (proofValue: string): Promise => { + try { + if (!proofValue || !proofValue.startsWith('u')) { + return false; + } + // @ts-ignore: No types available for base64url-universal + const { decode } = await import('base64url-universal'); + const decoded = decode(proofValue.slice(1)); + // Check if it has the BBS-2023 base proof header (0xd9, 0x5d, and even third byte) + // Base proof headers: 0x02 (baseline), 0x04 (anonymous_holder_binding), 0x06 (pseudonym), 0x08 (holder_binding_pseudonym) + // Derived proof headers: 0x03, 0x05, 0x07 (odd numbers) + // Convert to numbers to handle both Buffer (Node.js) and Uint8Array (browser) environments + if (decoded.length < 3 || Number(decoded[0]) !== 0xd9 || Number(decoded[1]) !== 0x5d) { + return false; + } + + const thirdByte = Number(decoded[2]); + // Base proofs have even third bytes: 0x02, 0x04, 0x06, 0x08 + return thirdByte === 0x02 || thirdByte === 0x04 || thirdByte === 0x06 || thirdByte === 0x08; + } catch { + return false; + } +}; + +const baseProofDetectors = { + 'ecdsa-sd-2023': isEcdsaSdBaseProof, + 'bbs-2023': isBbs2023BaseProof, +} as const; + +type SupportedCryptosuite = keyof typeof baseProofDetectors; + /** * Determines whether a verifiable credential is a derived credential. * @@ -149,10 +178,12 @@ export const isDerived = async (document: SignedVerifiableCredential) => { const proof = jsonld.getValues(document, 'proof')[0]; const cryptosuite = proof.cryptosuite; - // ECDSA Selective Disclosure 2023 cryptosuite - if (cryptosuite === 'ecdsa-sd-2023') { + // ECDSA-SD-2023 and BBS-2023 cryptosuites + if (cryptosuite === 'ecdsa-sd-2023' || cryptosuite === 'bbs-2023') { // Check if this is a base proof (original credential) or derived proof (selective disclosure) - if (await isEcdsaSdBaseProof(proof.proofValue as string)) { + if ( + await baseProofDetectors[cryptosuite as SupportedCryptosuite](proof.proofValue as string) + ) { return false; // Base proof - contains all original claims } else return true; // Derived proof - contains only selected claims } @@ -164,13 +195,23 @@ export const isDerived = async (document: SignedVerifiableCredential) => { }; /** - * Extracts mandatory pointers from an ECDSA-SD-2023 base proof value + * Extracts mandatory pointers from ECDSA-SD-2023 or BBS-2023 base proof values * @param {string} proofValue - The base proof value string + * @param {string} cryptosuite - The cryptosuite type ('ecdsa-sd-2023' or 'bbs-2023') * @returns {Promise} - Array of mandatory pointers, empty array if extraction fails */ -const extractMandatoryPointers = async (proofValue: string): Promise => { +const extractMandatoryPointers = async ( + proofValue: string, + cryptosuite: string, +): Promise => { try { - if (!(await isEcdsaSdBaseProof(proofValue))) { + // Check if this is a base proof for the specified cryptosuite + const isBaseProof = + cryptosuite === 'ecdsa-sd-2023' + ? await isEcdsaSdBaseProof(proofValue) + : await isBbs2023BaseProof(proofValue); + + if (!isBaseProof) { return []; } @@ -181,9 +222,17 @@ const extractMandatoryPointers = async (proofValue: string): Promise = const cbor = await import('cbor'); const components = cbor.decode(decodedProofValue.slice(3)); - // Components array: [baseSignature, publicKey, hmacKey, signatures, mandatoryPointers] - if (Array.isArray(components) && components.length === 5) { - return components[4] || []; + if (cryptosuite === 'ecdsa-sd-2023') { + // ECDSA-SD-2023 components: [baseSignature, publicKey, hmacKey, signatures, mandatoryPointers] + if (Array.isArray(components) && components.length === 5) { + return components[4] || []; + } + } else if (cryptosuite === 'bbs-2023') { + // BBS-2023 components: [baseSignature, publicKey, hmacKey, signatures, mandatoryPointers] + // Note: BBS-2023 has the same structure as ECDSA-SD-2023 for mandatory pointers + if (Array.isArray(components) && components.length === 5) { + return components[4] || []; + } } return []; @@ -194,17 +243,17 @@ const extractMandatoryPointers = async (proofValue: string): Promise = }; /** - * Signs a credential using the specified cryptosuite. Defaults to 'BbsBlsSignature2020'. + * Signs a credential using the specified cryptosuite. Defaults to 'ecdsa-sd-2023'. * @param {object} credential - The credential to be signed. * @param {object} keyPair - The key pair options for signing. - * @param {string} cryptoSuite - The cryptosuite to be used for signing. Defaults to 'BbsBlsSignature2020'. - * @param {object} options - Optional parameters including documentLoader and mandatoryPointers for ECDSA-SD-2023. + * @param {string} cryptoSuite - The cryptosuite to be used for signing. Defaults to 'ecdsa-sd-2023'. + * @param {object} options - Optional parameters including documentLoader and mandatoryPointers. * @returns {Promise} The signed credential or an error message in case of failure. */ export const signCredential = async ( credential: RawVerifiableCredential, keyPair: PrivateKeyPair, - cryptoSuite: CryptoSuiteName = 'BbsBlsSignature2020', + cryptoSuite: CryptoSuiteName = 'ecdsa-sd-2023', options?: { documentLoader?: DocumentLoader; mandatoryPointers?: string[]; @@ -214,27 +263,19 @@ export const signCredential = async ( const documentLoader = options?.documentLoader ?? (await getDocumentLoader()); if (cryptoSuite === 'BbsBlsSignature2020') { - _checkKeyPair(keyPair); - _checkCredential(credential, undefined, 'sign'); - - const key = new Bls12381G2KeyPair(keyPair as KeyPairOptions); - - // This ensures each credential has a distinct, system-generated ID in the UUIDv7 format - credential = prefilCredentialId(credential, cryptoSuite); - - const signed = await jsonldSignaturesV7.sign(credential, { - suite: new BbsBlsSignature2020({ key }), - purpose: new AssertionProofPurposeV7(), - documentLoader, - }); - - return { signed: signed }; - } else if (cryptoSuite === 'ecdsa-sd-2023') { + return { + error: + 'BbsBlsSignature2020 is no longer supported. Please use the latest cryptosuite versions instead.', + }; + } else if (cryptoSuite === 'ecdsa-sd-2023' || cryptoSuite === 'bbs-2023') { _checkKeyPair(keyPair); _checkCredential(credential, undefined, 'sign'); // Import the key pair object into a usable signer instance - const ecdsaKeyPair = await EcdsaMultikey.from({ ...keyPair }); + const keyPairInstance = + cryptoSuite === 'ecdsa-sd-2023' + ? await EcdsaMultikey.from({ ...keyPair }) + : await Bls12381Multikey.from({ ...keyPair }); // Determine required mandatory pointers based on credential format const firstContext = credential['@context'][0]; @@ -261,12 +302,15 @@ export const signCredential = async ( ...userMandatoryPointers.filter((pointer) => !coreMandatoryPointers.includes(pointer)), ]; - // Create the DataIntegrityProof suite using the ECDSA-SD cryptosuite + // Create the DataIntegrityProof suite using the appropriate cryptosuite + const cryptosuiteInstance = + cryptoSuite === 'ecdsa-sd-2023' + ? createEcdsaSd2023SignCryptosuite({ mandatoryPointers }) + : createBbs2023SignCryptosuite({ mandatoryPointers }); + const suite = new DataIntegrityProof({ - signer: ecdsaKeyPair.signer(), - cryptosuite: createSignCryptosuite({ - mandatoryPointers: mandatoryPointers, - }), + signer: keyPairInstance.signer(), + cryptosuite: cryptosuiteInstance, }); // This ensures each credential has a distinct, system-generated ID in the UUIDv7 format @@ -301,8 +345,9 @@ export const signCredential = async ( }; /** - * Verifies a credential using the BBS+ signature scheme or ECDSA-SD-2023. + * Verifies a credential using BBS+ signature scheme, ECDSA-SD-2023, or BBS-2023. * @param {object} credential - The credential to be verified. + * @param {object} options - Optional parameters including documentLoader. * @returns {Promise} The verification result indicating success * or failure, along with an error message if applicable. */ @@ -326,23 +371,38 @@ export const verifyCredential = async ( const proof = jsonld.getValues(credential, 'proof')[0]; const cryptosuite = proof.cryptosuite; - if (cryptosuite === 'ecdsa-sd-2023') { + if (cryptosuite === 'ecdsa-sd-2023' || cryptosuite === 'bbs-2023') { // Check if this is a base credential (non-derived) by examining the proofValue structure - if (await isEcdsaSdBaseProof(proof.proofValue as string)) { - // This is a base proof - ECDSA-SD-2023 base credentials require derivation before verification + const isBaseCredential = await baseProofDetectors[cryptosuite as SupportedCryptosuite]( + proof.proofValue as string, + ); + + if (isBaseCredential) { + // This is a base proof - modern cryptosuites require derivation before verification return { verified: false, error: `${cryptosuite} base credentials must be derived before verification. Use deriveCredential() first.`, }; } + // Create the appropriate verification cryptosuite + const verifyCryptosuite = + cryptosuite === 'ecdsa-sd-2023' + ? createEcdsaSd2023VerifyCryptosuite() + : createBbs2023VerifyCryptosuite(); + verificationResult = await jsonldSignatures.verify(credential, { suite: new DataIntegrityProof({ - cryptosuite: createVerifyCryptosuite(), + cryptosuite: verifyCryptosuite, }), purpose: new AssertionProofPurpose(), documentLoader, }); + } else { + return { + verified: false, + error: `DataIntegrityProof with cryptosuite "${cryptosuite}" is not supported for verification.`, + }; } } else { // For BBS+ proofs, create the suite normally @@ -352,6 +412,11 @@ export const verifyCredential = async ( documentLoader, }); } + } else { + return { + verified: false, + error: `Proof type "${proofType}" is not supported for verification.`, + }; } if (verificationResult.verified) { @@ -393,13 +458,13 @@ export const verifyCredential = async ( /** * Derives a credential with selective disclosure based on revealed attributes. * @param {object} credential - The verifiable credential to be selectively disclosed. - * @param {object|string[]} revealedAttributes - For BBS+: The attributes from the credential that should be revealed. For ECDSA-SD-2023: Array of selective pointers. + * @param {string[]} revealedAttributes - Array of JSON pointers for selective disclosure. * @param {object} options - Optional parameters including documentLoader. * @returns {Promise} A DerivedResult containing the derived proof or an error message. */ export const deriveCredential = async ( credential: SignedVerifiableCredential, - revealedAttributes: ContextDocument | string[], + revealedAttributes: string[], options?: { documentLoader?: DocumentLoader; }, @@ -411,26 +476,17 @@ export const deriveCredential = async ( const proofType = jsonld.getValues(credential, 'proof')[0].type as ProofType; if (proofType === 'BbsBlsSignature2020') { - // For BBS+, use the existing deriveProof function with revealedAttributes - const derivedProof = await deriveProof(credential, revealedAttributes as ContextDocument, { - suite: new BbsBlsSignatureProof2020(), - documentLoader, - }); - return { derived: derivedProof }; + return { + error: + 'BbsBlsSignature2020 is no longer supported for derivation. Please use the latest cryptosuite versions instead.', + }; } else if (proofType === 'DataIntegrityProof') { // Check the cryptosuite to determine the specific proof type const proof = jsonld.getValues(credential, 'proof')[0]; const cryptosuite = proof.cryptosuite; - if (cryptosuite === 'ecdsa-sd-2023') { - // Check if this is already a derived credential by examining the proofValue structure - if (!(await isEcdsaSdBaseProof(proof.proofValue as string))) { - return { - error: `${cryptosuite} derived credentials cannot be further derived. Multiple rounds of derivation are not supported by this cryptosuite.`, - }; - } - - // For ECDSA-SD-2023, use selective pointers (can be empty array for mandatory-only disclosure) + if (cryptosuite === 'ecdsa-sd-2023' || cryptosuite === 'bbs-2023') { + // Modern cryptosuites with selective disclosure (ECDSA-SD-2023 and BBS-2023) if (!Array.isArray(revealedAttributes)) { return { error: `${cryptosuite} requires revealedAttributes to be an array of JSON pointers (string[]).`, @@ -439,8 +495,22 @@ export const deriveCredential = async ( const selectivePointers = revealedAttributes; + // Check if this is already a derived credential by examining the proofValue structure + const isAlreadyDerived = !(await baseProofDetectors[cryptosuite as SupportedCryptosuite]( + proof.proofValue as string, + )); + + if (isAlreadyDerived) { + return { + error: `${cryptosuite} derived credentials cannot be further derived. Multiple rounds of derivation are not supported by this cryptosuite.`, + }; + } + // Extract mandatory pointers from the base proof - const mandatoryPointers = await extractMandatoryPointers(proof.proofValue as string); + const mandatoryPointers = await extractMandatoryPointers( + proof.proofValue as string, + cryptosuite, + ); // Check if credentialSubject is already in mandatory pointers or selective pointers const hasCredentialSubjectInMandatory = mandatoryPointers.some((pointer) => @@ -450,19 +520,21 @@ export const deriveCredential = async ( pointer.startsWith('/credentialSubject'), ); - let finalSelectivePointers = selectivePointers; if (!hasCredentialSubjectInMandatory && !hasCredentialSubjectInSelective) { // Only add /credentialSubject if it's not already in mandatory pointers // and no credentialSubject properties are selected // This ensures the derived credential remains valid per W3C VC specification - finalSelectivePointers = [...selectivePointers, '/credentialSubject']; + selectivePointers.push('/credentialSubject'); } - // Create the DataIntegrityProof suite for disclosure + // Create the DataIntegrityProof suite for disclosure using appropriate cryptosuite + const cryptosuiteInstance = + cryptosuite === 'ecdsa-sd-2023' + ? createEcdsaSd2023DiscloseCryptosuite({ selectivePointers }) + : createBbs2023DiscloseCryptosuite({ selectivePointers }); + const suite = new DataIntegrityProof({ - cryptosuite: createDiscloseCryptosuite({ - selectivePointers: finalSelectivePointers, - }), + cryptosuite: cryptosuiteInstance, }); // Derive the selectively disclosed credential From 47e3727209f7d74aa490a27d4e87ca09e43d06bf Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 24 Sep 2025 09:34:33 +0000 Subject: [PATCH 102/122] chore(release): @trustvc/w3c-issuer@1.3.0-alpha.10 [skip ci] # [1.3.0-alpha.10](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-issuer@1.3.0-alpha.9...@trustvc/w3c-issuer@1.3.0-alpha.10) (2025-09-24) ### Features * bbs2023 implementation ([#88](https://github.com/TrustVC/w3c/issues/88)) ([082e6f0](https://github.com/TrustVC/w3c/commit/082e6f0f1365ee7781816db4c4604e4a10073557)) --- packages/w3c-issuer/CHANGELOG.md | 7 +++++++ packages/w3c-issuer/package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/w3c-issuer/CHANGELOG.md b/packages/w3c-issuer/CHANGELOG.md index 44105e12..5a0df279 100644 --- a/packages/w3c-issuer/CHANGELOG.md +++ b/packages/w3c-issuer/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.10](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-issuer@1.3.0-alpha.9...@trustvc/w3c-issuer@1.3.0-alpha.10) (2025-09-24) + + +### Features + +* bbs2023 implementation ([#88](https://github.com/TrustVC/w3c/issues/88)) ([082e6f0](https://github.com/TrustVC/w3c/commit/082e6f0f1365ee7781816db4c4604e4a10073557)) + # [1.3.0-alpha.9](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-issuer@1.3.0-alpha.8...@trustvc/w3c-issuer@1.3.0-alpha.9) (2025-09-24) diff --git a/packages/w3c-issuer/package.json b/packages/w3c-issuer/package.json index 96bfec66..ec75adc7 100644 --- a/packages/w3c-issuer/package.json +++ b/packages/w3c-issuer/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c-issuer", - "version": "1.3.0-alpha.9", + "version": "1.3.0-alpha.10", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", From 6a5a8a2ed6d198fac6275fcb3212b14eb9c5acb7 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 24 Sep 2025 09:35:05 +0000 Subject: [PATCH 103/122] chore(release): @trustvc/w3c-context@1.3.0-alpha.12 [skip ci] # [1.3.0-alpha.12](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-context@1.3.0-alpha.11...@trustvc/w3c-context@1.3.0-alpha.12) (2025-09-24) ### Features * bbs2023 implementation ([#88](https://github.com/TrustVC/w3c/issues/88)) ([082e6f0](https://github.com/TrustVC/w3c/commit/082e6f0f1365ee7781816db4c4604e4a10073557)) --- packages/w3c-context/CHANGELOG.md | 7 +++++++ packages/w3c-context/package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/w3c-context/CHANGELOG.md b/packages/w3c-context/CHANGELOG.md index 63b91485..3f80c470 100644 --- a/packages/w3c-context/CHANGELOG.md +++ b/packages/w3c-context/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.12](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-context@1.3.0-alpha.11...@trustvc/w3c-context@1.3.0-alpha.12) (2025-09-24) + + +### Features + +* bbs2023 implementation ([#88](https://github.com/TrustVC/w3c/issues/88)) ([082e6f0](https://github.com/TrustVC/w3c/commit/082e6f0f1365ee7781816db4c4604e4a10073557)) + # [1.3.0-alpha.11](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-context@1.3.0-alpha.10...@trustvc/w3c-context@1.3.0-alpha.11) (2025-09-24) diff --git a/packages/w3c-context/package.json b/packages/w3c-context/package.json index dfd8d5e0..f4bb459b 100644 --- a/packages/w3c-context/package.json +++ b/packages/w3c-context/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c-context", - "version": "1.3.0-alpha.11", + "version": "1.3.0-alpha.12", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", From 4be49b446160e77d93274203173bc3d7333a6bc5 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 24 Sep 2025 09:35:40 +0000 Subject: [PATCH 104/122] chore(release): @trustvc/w3c-credential-status@1.3.0-alpha.12 [skip ci] # [1.3.0-alpha.12](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-credential-status@1.3.0-alpha.11...@trustvc/w3c-credential-status@1.3.0-alpha.12) (2025-09-24) ### Features * bbs2023 implementation ([#88](https://github.com/TrustVC/w3c/issues/88)) ([082e6f0](https://github.com/TrustVC/w3c/commit/082e6f0f1365ee7781816db4c4604e4a10073557)) --- packages/w3c-credential-status/CHANGELOG.md | 7 +++++++ packages/w3c-credential-status/package.json | 6 +++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/packages/w3c-credential-status/CHANGELOG.md b/packages/w3c-credential-status/CHANGELOG.md index 6a703376..22667cf1 100644 --- a/packages/w3c-credential-status/CHANGELOG.md +++ b/packages/w3c-credential-status/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.12](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-credential-status@1.3.0-alpha.11...@trustvc/w3c-credential-status@1.3.0-alpha.12) (2025-09-24) + + +### Features + +* bbs2023 implementation ([#88](https://github.com/TrustVC/w3c/issues/88)) ([082e6f0](https://github.com/TrustVC/w3c/commit/082e6f0f1365ee7781816db4c4604e4a10073557)) + # [1.3.0-alpha.11](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-credential-status@1.3.0-alpha.10...@trustvc/w3c-credential-status@1.3.0-alpha.11) (2025-09-24) diff --git a/packages/w3c-credential-status/package.json b/packages/w3c-credential-status/package.json index 3e14219a..420e2a20 100644 --- a/packages/w3c-credential-status/package.json +++ b/packages/w3c-credential-status/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c-credential-status", - "version": "1.3.0-alpha.11", + "version": "1.3.0-alpha.12", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", @@ -29,8 +29,8 @@ } }, "dependencies": { - "@trustvc/w3c-context": "^1.3.0-alpha.11", - "@trustvc/w3c-issuer": "^1.3.0-alpha.9", + "@trustvc/w3c-context": "^1.3.0-alpha.12", + "@trustvc/w3c-issuer": "^1.3.0-alpha.10", "base64url-universal": "^2.0.0", "pako": "^2.1.0" }, From bad14478c285e3e72e9690b04f692cbd1e3c4ad3 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 24 Sep 2025 09:36:16 +0000 Subject: [PATCH 105/122] chore(release): @trustvc/w3c-vc@1.3.0-alpha.13 [skip ci] # [1.3.0-alpha.13](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.3.0-alpha.12...@trustvc/w3c-vc@1.3.0-alpha.13) (2025-09-24) ### Features * bbs2023 implementation ([#88](https://github.com/TrustVC/w3c/issues/88)) ([082e6f0](https://github.com/TrustVC/w3c/commit/082e6f0f1365ee7781816db4c4604e4a10073557)) --- packages/w3c-vc/CHANGELOG.md | 7 +++++++ packages/w3c-vc/package.json | 6 +++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/packages/w3c-vc/CHANGELOG.md b/packages/w3c-vc/CHANGELOG.md index 6bcd41f8..bb1ad1e1 100644 --- a/packages/w3c-vc/CHANGELOG.md +++ b/packages/w3c-vc/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.13](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.3.0-alpha.12...@trustvc/w3c-vc@1.3.0-alpha.13) (2025-09-24) + + +### Features + +* bbs2023 implementation ([#88](https://github.com/TrustVC/w3c/issues/88)) ([082e6f0](https://github.com/TrustVC/w3c/commit/082e6f0f1365ee7781816db4c4604e4a10073557)) + # [1.3.0-alpha.12](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.3.0-alpha.11...@trustvc/w3c-vc@1.3.0-alpha.12) (2025-09-24) diff --git a/packages/w3c-vc/package.json b/packages/w3c-vc/package.json index 2371ef4e..c0496fab 100644 --- a/packages/w3c-vc/package.json +++ b/packages/w3c-vc/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c-vc", - "version": "1.3.0-alpha.12", + "version": "1.3.0-alpha.13", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", @@ -37,8 +37,8 @@ "@digitalbazaar/ecdsa-multikey": "^1.8.0", "@digitalbazaar/ecdsa-sd-2023-cryptosuite": "^3.4.1", "@mattrglobal/jsonld-signatures-bbs": "^1.2.0", - "@trustvc/w3c-credential-status": "^1.3.0-alpha.11", - "@trustvc/w3c-issuer": "^1.3.0-alpha.9", + "@trustvc/w3c-credential-status": "^1.3.0-alpha.12", + "@trustvc/w3c-issuer": "^1.3.0-alpha.10", "base64url-universal": "^2.0.0", "cbor": "^9.0.2", "did-resolver": "^4.1.0", From d7bade6986585e95cc170981e85f442338d76b56 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 24 Sep 2025 09:36:50 +0000 Subject: [PATCH 106/122] chore(release): @trustvc/w3c@1.3.0-alpha.13 [skip ci] # [1.3.0-alpha.13](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.3.0-alpha.12...@trustvc/w3c@1.3.0-alpha.13) (2025-09-24) ### Features * bbs2023 implementation ([#88](https://github.com/TrustVC/w3c/issues/88)) ([082e6f0](https://github.com/TrustVC/w3c/commit/082e6f0f1365ee7781816db4c4604e4a10073557)) --- packages/w3c/CHANGELOG.md | 7 +++++++ packages/w3c/package.json | 10 +++++----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/packages/w3c/CHANGELOG.md b/packages/w3c/CHANGELOG.md index 93c0d4cc..956ddc8e 100644 --- a/packages/w3c/CHANGELOG.md +++ b/packages/w3c/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.13](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.3.0-alpha.12...@trustvc/w3c@1.3.0-alpha.13) (2025-09-24) + + +### Features + +* bbs2023 implementation ([#88](https://github.com/TrustVC/w3c/issues/88)) ([082e6f0](https://github.com/TrustVC/w3c/commit/082e6f0f1365ee7781816db4c4604e4a10073557)) + # [1.3.0-alpha.12](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.3.0-alpha.11...@trustvc/w3c@1.3.0-alpha.12) (2025-09-24) diff --git a/packages/w3c/package.json b/packages/w3c/package.json index da5e9aab..7c17a96f 100644 --- a/packages/w3c/package.json +++ b/packages/w3c/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c", - "version": "1.3.0-alpha.12", + "version": "1.3.0-alpha.13", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", @@ -32,10 +32,10 @@ } }, "dependencies": { - "@trustvc/w3c-context": "^1.3.0-alpha.11", - "@trustvc/w3c-credential-status": "^1.3.0-alpha.11", - "@trustvc/w3c-issuer": "^1.3.0-alpha.9", - "@trustvc/w3c-vc": "^1.3.0-alpha.12" + "@trustvc/w3c-context": "^1.3.0-alpha.12", + "@trustvc/w3c-credential-status": "^1.3.0-alpha.12", + "@trustvc/w3c-issuer": "^1.3.0-alpha.10", + "@trustvc/w3c-vc": "^1.3.0-alpha.13" }, "repository": { "type": "git", From 01a316bf3ea860bb9743ecec5361cb78ee02842e Mon Sep 17 00:00:00 2001 From: Moiz Shaikh <58319530+Moiz47@users.noreply.github.com> Date: Mon, 6 Oct 2025 11:58:18 +0530 Subject: [PATCH 107/122] fix: update proof type (#90) Co-authored-by: moiz-sgtradex --- packages/w3c-vc/src/lib/types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/w3c-vc/src/lib/types.ts b/packages/w3c-vc/src/lib/types.ts index 0fcf798b..22bc37c9 100644 --- a/packages/w3c-vc/src/lib/types.ts +++ b/packages/w3c-vc/src/lib/types.ts @@ -30,7 +30,7 @@ export type CredentialSubjects = CredentialSubject | CredentialSubject[]; export type Proof = { type: string; - created: string; + created?: string; proofPurpose: string; verificationMethod: string; proofValue: string; From acf356ebac65369a02ef965ccb62f32dcad8a721 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Mon, 6 Oct 2025 06:32:04 +0000 Subject: [PATCH 108/122] chore(release): @trustvc/w3c-vc@1.3.0-alpha.14 [skip ci] # [1.3.0-alpha.14](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.3.0-alpha.13...@trustvc/w3c-vc@1.3.0-alpha.14) (2025-10-06) ### Bug Fixes * update proof type ([#90](https://github.com/TrustVC/w3c/issues/90)) ([01a316b](https://github.com/TrustVC/w3c/commit/01a316bf3ea860bb9743ecec5361cb78ee02842e)) --- packages/w3c-vc/CHANGELOG.md | 7 +++++++ packages/w3c-vc/package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/w3c-vc/CHANGELOG.md b/packages/w3c-vc/CHANGELOG.md index bb1ad1e1..28013f24 100644 --- a/packages/w3c-vc/CHANGELOG.md +++ b/packages/w3c-vc/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.14](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.3.0-alpha.13...@trustvc/w3c-vc@1.3.0-alpha.14) (2025-10-06) + + +### Bug Fixes + +* update proof type ([#90](https://github.com/TrustVC/w3c/issues/90)) ([01a316b](https://github.com/TrustVC/w3c/commit/01a316bf3ea860bb9743ecec5361cb78ee02842e)) + # [1.3.0-alpha.13](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.3.0-alpha.12...@trustvc/w3c-vc@1.3.0-alpha.13) (2025-09-24) diff --git a/packages/w3c-vc/package.json b/packages/w3c-vc/package.json index c0496fab..a9196b96 100644 --- a/packages/w3c-vc/package.json +++ b/packages/w3c-vc/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c-vc", - "version": "1.3.0-alpha.13", + "version": "1.3.0-alpha.14", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", From 82d1862b8d5dbc44f950aa29a3958d601a301fe6 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Mon, 6 Oct 2025 06:32:36 +0000 Subject: [PATCH 109/122] chore(release): @trustvc/w3c@1.3.0-alpha.14 [skip ci] # [1.3.0-alpha.14](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.3.0-alpha.13...@trustvc/w3c@1.3.0-alpha.14) (2025-10-06) ### Bug Fixes * update proof type ([#90](https://github.com/TrustVC/w3c/issues/90)) ([01a316b](https://github.com/TrustVC/w3c/commit/01a316bf3ea860bb9743ecec5361cb78ee02842e)) --- packages/w3c/CHANGELOG.md | 7 +++++++ packages/w3c/package.json | 4 ++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/packages/w3c/CHANGELOG.md b/packages/w3c/CHANGELOG.md index 956ddc8e..8cfb76c1 100644 --- a/packages/w3c/CHANGELOG.md +++ b/packages/w3c/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.14](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.3.0-alpha.13...@trustvc/w3c@1.3.0-alpha.14) (2025-10-06) + + +### Bug Fixes + +* update proof type ([#90](https://github.com/TrustVC/w3c/issues/90)) ([01a316b](https://github.com/TrustVC/w3c/commit/01a316bf3ea860bb9743ecec5361cb78ee02842e)) + # [1.3.0-alpha.13](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.3.0-alpha.12...@trustvc/w3c@1.3.0-alpha.13) (2025-09-24) diff --git a/packages/w3c/package.json b/packages/w3c/package.json index 7c17a96f..72a12c5e 100644 --- a/packages/w3c/package.json +++ b/packages/w3c/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c", - "version": "1.3.0-alpha.13", + "version": "1.3.0-alpha.14", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", @@ -35,7 +35,7 @@ "@trustvc/w3c-context": "^1.3.0-alpha.12", "@trustvc/w3c-credential-status": "^1.3.0-alpha.12", "@trustvc/w3c-issuer": "^1.3.0-alpha.10", - "@trustvc/w3c-vc": "^1.3.0-alpha.13" + "@trustvc/w3c-vc": "^1.3.0-alpha.14" }, "repository": { "type": "git", From 3e965d42de6378605b81f951eb6ae7478e981544 Mon Sep 17 00:00:00 2001 From: RishabhS7 <59636880+RishabhS7@users.noreply.github.com> Date: Tue, 7 Oct 2025 17:08:32 +0530 Subject: [PATCH 110/122] fix: type checks (#91) * fix: type checks for test suits * fix: remove tt files * fix: test cases --- packages/w3c-vc/src/lib/helper/index.ts | 2 +- packages/w3c-vc/src/lib/types.ts | 31 ++++++++++++++++++++++++- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/packages/w3c-vc/src/lib/helper/index.ts b/packages/w3c-vc/src/lib/helper/index.ts index 1f9e2f35..da47e5f2 100644 --- a/packages/w3c-vc/src/lib/helper/index.ts +++ b/packages/w3c-vc/src/lib/helper/index.ts @@ -82,7 +82,7 @@ function _getId(obj: T | string): string | undefined // These properties of a Verifiable Credential (VC) must be objects containing a type field // if they are present in the VC. -const mustHaveType = ['proof', 'credentialStatus']; +const mustHaveType = ['proof', 'credentialStatus', 'termsOfUse', 'refreshService']; // Regular expression to validate date-time format according to XML schema. // Z and T must be uppercase diff --git a/packages/w3c-vc/src/lib/types.ts b/packages/w3c-vc/src/lib/types.ts index 22bc37c9..77ae9863 100644 --- a/packages/w3c-vc/src/lib/types.ts +++ b/packages/w3c-vc/src/lib/types.ts @@ -24,10 +24,34 @@ export type CredentialStatus = { type: string; } & Record; export type CredentialStatuses = CredentialStatus | CredentialStatus[]; - +export type CredentialSchema = { + id: string; + type: string; +} & Record; +export type CredentialSchemas = CredentialSchema | CredentialSchema[]; export type CredentialSubject = Record; export type CredentialSubjects = CredentialSubject | CredentialSubject[]; +export type TermsOfUse = { + type: string; +} & Record; +export type TermsOfUses = TermsOfUse | TermsOfUse[]; + +export type RelatedResource = { + type: string; +} & Record; +export type RelatedResources = RelatedResource | RelatedResource[]; + +export type RefreshService = { + type: string; +} & Record; +export type RefreshServices = RefreshService | RefreshService[]; + +export type Evidence = { + type: string; +} & Record; +export type Evidences = Evidence | Evidence[]; + export type Proof = { type: string; created?: string; @@ -50,6 +74,11 @@ export type SignedVerifiableCredential = { expirationDate?: string; credentialStatus?: CredentialStatuses; credentialSubject: CredentialSubjects; + credentialSchema?: CredentialSchemas; + termsOfUse?: TermsOfUses; + evidence?: Evidences; + relatedResource?: RelatedResources; + refreshService?: RefreshServices; renderMethod?: Record; qrCode?: Record; proof?: Proof; From b1220b1a9519df7c090543460189f78bb145527f Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Tue, 7 Oct 2025 11:53:03 +0000 Subject: [PATCH 111/122] chore(release): @trustvc/w3c-vc@1.3.0-alpha.15 [skip ci] # [1.3.0-alpha.15](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.3.0-alpha.14...@trustvc/w3c-vc@1.3.0-alpha.15) (2025-10-07) ### Bug Fixes * type checks ([#91](https://github.com/TrustVC/w3c/issues/91)) ([3e965d4](https://github.com/TrustVC/w3c/commit/3e965d42de6378605b81f951eb6ae7478e981544)) --- packages/w3c-vc/CHANGELOG.md | 7 +++++++ packages/w3c-vc/package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/w3c-vc/CHANGELOG.md b/packages/w3c-vc/CHANGELOG.md index 28013f24..9063a323 100644 --- a/packages/w3c-vc/CHANGELOG.md +++ b/packages/w3c-vc/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.15](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.3.0-alpha.14...@trustvc/w3c-vc@1.3.0-alpha.15) (2025-10-07) + + +### Bug Fixes + +* type checks ([#91](https://github.com/TrustVC/w3c/issues/91)) ([3e965d4](https://github.com/TrustVC/w3c/commit/3e965d42de6378605b81f951eb6ae7478e981544)) + # [1.3.0-alpha.14](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.3.0-alpha.13...@trustvc/w3c-vc@1.3.0-alpha.14) (2025-10-06) diff --git a/packages/w3c-vc/package.json b/packages/w3c-vc/package.json index a9196b96..34c87ab2 100644 --- a/packages/w3c-vc/package.json +++ b/packages/w3c-vc/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c-vc", - "version": "1.3.0-alpha.14", + "version": "1.3.0-alpha.15", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", From e833bfb10ee3094e9bc29fad186df306b4981e54 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Tue, 7 Oct 2025 11:53:37 +0000 Subject: [PATCH 112/122] chore(release): @trustvc/w3c@1.3.0-alpha.15 [skip ci] # [1.3.0-alpha.15](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.3.0-alpha.14...@trustvc/w3c@1.3.0-alpha.15) (2025-10-07) ### Bug Fixes * type checks ([#91](https://github.com/TrustVC/w3c/issues/91)) ([3e965d4](https://github.com/TrustVC/w3c/commit/3e965d42de6378605b81f951eb6ae7478e981544)) --- packages/w3c/CHANGELOG.md | 7 +++++++ packages/w3c/package.json | 4 ++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/packages/w3c/CHANGELOG.md b/packages/w3c/CHANGELOG.md index 8cfb76c1..de3baf53 100644 --- a/packages/w3c/CHANGELOG.md +++ b/packages/w3c/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.15](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.3.0-alpha.14...@trustvc/w3c@1.3.0-alpha.15) (2025-10-07) + + +### Bug Fixes + +* type checks ([#91](https://github.com/TrustVC/w3c/issues/91)) ([3e965d4](https://github.com/TrustVC/w3c/commit/3e965d42de6378605b81f951eb6ae7478e981544)) + # [1.3.0-alpha.14](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.3.0-alpha.13...@trustvc/w3c@1.3.0-alpha.14) (2025-10-06) diff --git a/packages/w3c/package.json b/packages/w3c/package.json index 72a12c5e..56e95c32 100644 --- a/packages/w3c/package.json +++ b/packages/w3c/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c", - "version": "1.3.0-alpha.14", + "version": "1.3.0-alpha.15", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", @@ -35,7 +35,7 @@ "@trustvc/w3c-context": "^1.3.0-alpha.12", "@trustvc/w3c-credential-status": "^1.3.0-alpha.12", "@trustvc/w3c-issuer": "^1.3.0-alpha.10", - "@trustvc/w3c-vc": "^1.3.0-alpha.14" + "@trustvc/w3c-vc": "^1.3.0-alpha.15" }, "repository": { "type": "git", From c49bbfe0c61eb99993aefa44951b2dbc98aaac0f Mon Sep 17 00:00:00 2001 From: Moiz Shaikh <58319530+Moiz47@users.noreply.github.com> Date: Wed, 8 Oct 2025 07:31:57 +0530 Subject: [PATCH 113/122] feat: status list update for bbs and v2.0 (#89) * feat: status list update for bbs and v2.0 * feat: remove bbsbls2020 support for statuslist * feat: removed used imports * feat: updated readme * feat: update test cases --------- Co-authored-by: moiz-sgtradex --- packages/w3c-credential-status/README.md | 115 ++++++++++-------- .../src/lib/index.test.ts | 67 +++++++--- .../w3c-credential-status/src/lib/index.ts | 23 ++-- 3 files changed, 124 insertions(+), 81 deletions(-) diff --git a/packages/w3c-credential-status/README.md b/packages/w3c-credential-status/README.md index 593ed883..e3a0a0c6 100644 --- a/packages/w3c-credential-status/README.md +++ b/packages/w3c-credential-status/README.md @@ -23,7 +23,7 @@ The revocation or suspension of Verifiable Credentials is achieved by changing t - Credential status type: `BitstringStatusListEntry` - Credential subject type: `BitstringStatusList` -This module provides functionality to create/update a signed Verifiable Credential (VC) for credential status, using a specified cryptographic suite and key pair. It supports both legacy BBS+ signatures and modern ECDSA-SD-2023 cryptosuites. +This module provides functionality to create/update a signed Verifiable Credential (VC) for credential status, using a specified cryptographic suite and key pair. It supports modern ECDSA-SD-2023 and BBS-2023 cryptosuites. ## Table of Contents @@ -63,8 +63,8 @@ npm install @trustvc/w3c-credential-status ## Features -- **Dual Version Support**: Compatible with both W3C VC Data Model v1.1 and v2.0 -- **Multiple Cryptosuites**: Supports BBS+ (legacy) and ECDSA-SD-2023 (modern) signatures +- **Version Support**: Compatible with both W3C VC Data Model v1.1 and v2.0 +- **Multiple Cryptosuites**: Supports modern signatures ECDSA-SD-2023 and BBS2023 - **Flexible Status Types**: Create both `StatusList2021Credential` and `BitstringStatusListCredential` - **Backward Compatibility**: Existing v1.1 implementations continue to work - Create Credential Status Verifiable Credentials with various cryptographic suites @@ -160,30 +160,13 @@ import { PrivateKeyPair } from '@trustvc/w3c-issuer'; * - type (VCCredentialStatusType): The type of the credential status VC. * Options: 'StatusList2021Credential' (v1.1) or 'BitstringStatusListCredential' (v2.0) * - cryptoSuite (string): The cryptosuite to be used for signing. - * Options: 'BbsBlsSignature2020' (legacy) or 'ecdsa-sd-2023' (modern) + * Options: 'ecdsa-sd-2023', or 'bbs-2023' * * Returns: * - A Promise that resolves to: * - RawCredentialStatusVC: The signed credential status Verifiable Credential. */ -// Example for W3C VC Data Model v1.1 (legacy) -const optionsV1 = { - id: hostingUrl, - credentialSubject: { - id: `${hostingUrl}#list`, - type: 'StatusList2021', // v1.1 credential subject type - statusPurpose: purpose, - encodedList, - }; -} - -const credentialStatusVCV1 = await createCredentialStatusPayload( - optionsV1, - keyPair, - 'StatusList2021Credential', // v1.1 credential type - 'BbsBlsSignature2020' // legacy cryptosuite -); // Example for W3C VC Data Model v2.0 (modern) const optionsV2 = { @@ -193,18 +176,46 @@ const optionsV2 = { type: 'BitstringStatusList', // v2.0 credential subject type statusPurpose: purpose, encodedList, - }; -} + }, +}; -const credentialStatusVCV2 = await createCredentialStatusPayload( +// Example with ECDSA-SD-2023 +const credentialStatusVCV2_ECDSA = await createCredentialStatusPayload( optionsV2, keyPair, 'BitstringStatusListCredential', // v2.0 credential type 'ecdsa-sd-2023' // modern cryptosuite ); -console.log('Credential Status VC:', credentialStatusVCV2); +// Example with BBS-2023 +const credentialStatusVCV2_BBS = await createCredentialStatusPayload( + optionsV2, + keyPair, + 'BitstringStatusListCredential', // v2.0 credential type, + 'bbs-2023' // modern cryptosuite +); + +console.log('Credential Status VC (ECDSA):', credentialStatusVCV2_ECDSA); +console.log('Credential Status VC (BBS):', credentialStatusVCV2_BBS); + +// Example for W3C VC Data Model v1.1 (legacy) +const optionsV1 = { + id: hostingUrl, + credentialSubject: { + id: `${hostingUrl}#list`, + type: 'StatusList2021', // v1.1 credential subject type + statusPurpose: purpose, + encodedList, + }, +}; + +const credentialStatusVCV1 = await createCredentialStatusPayload( + optionsV1, + keyPair, + 'StatusList2021Credential', // v1.1 credential type + 'BbsBlsSignature2020' // ⚠️ DEPRECATED - this will result in error. Use modern cryptosuites +); // Sign the credential status payload const { signed, error } = await signCredential(credentialStatusPayload, keypairData); @@ -217,38 +228,37 @@ const signedCredentialStatusVC = signed; ```
- signCredential Result (v1.1 with BBS+) + signCredential Result (v2.0 with ECDSA-SD-2023) ```js Signed Credential: { '@context': [ - 'https://www.w3.org/2018/credentials/v1', - 'https://w3c-ccg.github.io/citizenship-vocab/contexts/citizenship-v1.jsonld', - 'https://w3id.org/security/bbs/v1', - 'https://w3id.org/vc/status-list/2021/v1' + 'https://www.w3.org/ns/credentials/v2', + 'https://w3id.org/security/data-integrity/v2' ], credentialStatus: { id: 'https://trustvc.github.io/did/credentials/statuslist/1#1', statusListCredential: 'https://trustvc.github.io/did/credentials/statuslist/1', statusListIndex: '1', statusPurpose: 'revocation', - type: 'StatusList2021Entry' + type: 'BitstringStatusListEntry' }, - issuanceDate: '2024-04-01T12:19:52Z', + validFrom: '2024-04-01T12:19:52Z', credentialSubject: { id: 'did:example:b34ca6cd37bbf23', type: [ 'Person' ], name: 'TrustVC' }, - expirationDate: '2029-12-03T12:19:52Z', + validUntil: '2029-12-03T12:19:52Z', issuer: 'did:web:trustvc.github.io:did:1', type: [ 'VerifiableCredential' ], proof: { - type: 'BbsBlsSignature2020', + type: 'DataIntegrityProof', + cryptosuite: 'ecdsa-sd-2023', created: '2024-10-02T09:04:07Z', proofPurpose: 'assertionMethod', - proofValue: 'tissP5pJF1q4txCMWNZI5LgwhXMWrLI8675ops8FwlQE/zBUQnVO9Iey505MjkNDD5GdmQmnb6+RUKkLVGEJLIJrKQXlU3Xr4DlMW7ShH/sIpuvZoobGs/0hw/B5agXz8cVWfnDGWtDYciVh0rwQvg==', - verificationMethod: 'did:web:trustvc.github.io:did:1#keys-1' + proofValue: 'u2V0AhVhAip...', + verificationMethod: 'did:web:trustvc.github.io:did:1#multikey-1' } } ``` @@ -256,7 +266,7 @@ Signed Credential: {
- signCredential Result (v2.0 with ECDSA-SD-2023) + signCredential Result (v2.0 with BBS-2023) ```js Signed Credential: { @@ -266,10 +276,10 @@ Signed Credential: { ], credentialStatus: { id: 'https://trustvc.github.io/did/credentials/statuslist/1#1', - statusListCredential: 'https://trustvc.github.io/did/credentials/statuslist/1', - statusListIndex: '1', + type: 'BitstringStatusListEntry', statusPurpose: 'revocation', - type: 'BitstringStatusListEntry' + statusListIndex: '10', + statusListCredential: 'https://trustvc.github.io/did/credentials/statuslist/1' }, validFrom: '2024-04-01T12:19:52Z', credentialSubject: { @@ -282,11 +292,10 @@ Signed Credential: { type: [ 'VerifiableCredential' ], proof: { type: 'DataIntegrityProof', - cryptosuite: 'ecdsa-sd-2023', - created: '2024-10-02T09:04:07Z', + cryptosuite: 'bbs-2023', proofPurpose: 'assertionMethod', - proofValue: 'u2V0AhVhAip...', - verificationMethod: 'did:web:trustvc.github.io:did:1#multikey-1' + proofValue: 'u2V0ChVhQi0FELn9kYULQF...', + verificationMethod: 'did:web:trustvc.github.io:did:1#multikey-2' } } ``` @@ -356,20 +365,19 @@ After updating the status list, encode it and create a signed credential status // Encode the updated status list const encodedList = await statusList.encode(); -// Create the credential status payload (v1.1 example) const credentialStatusPayload = await createCredentialStatusPayload( { id: hostingUrl, credentialSubject: { id: `${hostingUrl}#list`, - type: 'StatusList2021', // Use 'BitstringStatusList' for v2.0 + type: 'BitstringStatusList', statusPurpose: purpose, encodedList, }, }, keypairData, // Your key pair data - 'StatusList2021Credential', // Use 'BitstringStatusListCredential' for v2.0 - 'BbsBlsSignature2020' // Use 'ecdsa-sd-2023' for modern cryptosuite + 'BitstringStatusListCredential', + 'ecdsa-sd-2023' // Use 'ecdsa-sd-2023' or 'bbs-2023' ); // Sign the credential status payload @@ -388,7 +396,7 @@ const signedCredentialStatusVC = signed; ### `createCredentialStatusPayload` -> Creates a credential status payload for both W3C VC Data Model v1.1 and v2.0. +> Creates a credential status payload for both W3C VC Data Model v1.1 and v2.0. > > #### Parameters: > @@ -397,12 +405,13 @@ const signedCredentialStatusVC = signed; > `keypairData (object)`: The key pair data used for signing. > > `credentialType (VCCredentialStatusType)`: The type of credential. Options: -> - `'StatusList2021Credential'` (v1.1 legacy) > - `'BitstringStatusListCredential'` (v2.0 modern) +> - `'StatusList2021Credential'` (v1.1 legacy) > > `cryptoSuite (CryptoSuiteName)`: The cryptosuite for signing. Options: -> - `'BbsBlsSignature2020'` (legacy BBS+ signatures) > - `'ecdsa-sd-2023'` (modern ECDSA-SD-2023 signatures) +> - `'bbs-2023'` (modern BBS-2023 signatures) +> - `'BbsBlsSignature2020'` (⚠️ DEPRECATED: legacy BBS+ signatures, use `'ecdsa-sd-2023'` or `'bbs-2023'` instead) ### `signCredential` @@ -474,10 +483,10 @@ To migrate from W3C VC Data Model v1.1 to v2.0: - `StatusList2021` → `BitstringStatusList` 2. **Update cryptosuite:** - - `BbsBlsSignature2020` → `ecdsa-sd-2023` + - `BbsBlsSignature2020` → `ecdsa-sd-2023` or `bbs-2023` 3. **Update key pair format:** - - Legacy BLS keys → Modern ECDSA multikey format + - Legacy BLS keys → Modern multikey format (ECDSA or BBS2023) 4. **Update contexts:** - v1.1 contexts → v2.0 contexts (handled automatically) diff --git a/packages/w3c-credential-status/src/lib/index.test.ts b/packages/w3c-credential-status/src/lib/index.test.ts index 846f8088..670d17e7 100644 --- a/packages/w3c-credential-status/src/lib/index.test.ts +++ b/packages/w3c-credential-status/src/lib/index.test.ts @@ -1,6 +1,7 @@ import { BBSPrivateKeyPair, EcdsaSd2023PrivateKeyPair, + Bbs2023PrivateKeyPair, VerificationType, } from '@trustvc/w3c-issuer'; import { describe, expect, it } from 'vitest'; @@ -11,7 +12,7 @@ const BLS_KEY_PAIR: BBSPrivateKeyPair = { type: VerificationType.Bls12381G2Key2020, controller: 'did:web:trustvc.github.io:did:1', seedBase58: 'GWP69tmSWJjqC1RoJ27FehcVqkVyeYAz6h5ABwoNSNdS', - privateKeyBase58: '4LDU56PUhA9ZEutnR1qCWQnUhtLtpLu2EHSq4h1o7vtF', + privateKeyBase58: 'privateKeyBase58', publicKeyBase58: 'oRfEeWFresvhRtXCkihZbxyoi2JER7gHTJ5psXhHsdCoU1MttRMi3Yp9b9fpjmKh7bMgfWKLESiK2YovRd8KGzJsGuamoAXfqDDVhckxuc9nmsJ84skCSTijKeU4pfAcxeJ', }; @@ -22,12 +23,43 @@ const ECDSA_SD_KEY_PAIR: EcdsaSd2023PrivateKeyPair = { type: VerificationType.Multikey, controller: 'did:web:trustvc.github.io:did:1', publicKeyMultibase: 'zDnaemDNwi4G5eTzGfRooFFu5Kns3be6yfyVNtiaMhWkZbwtc', - secretKeyMultibase: 'z42tmUXTVn3n9BihE6NhdMpvVBTnFTgmb6fw18o5Ud6puhRW', + secretKeyMultibase: 'secretKeyMultibase', +}; + +const BBS2023_KEY_PAIR: Bbs2023PrivateKeyPair = { + '@context': 'https://w3id.org/security/multikey/v1', + id: 'did:web:trustvc.github.io:did:1#multikey-2', + type: VerificationType.Multikey, + controller: 'did:web:trustvc.github.io:did:1', + publicKeyMultibase: + 'zUC75kRac7BdtjawFUxowfgD6mzqnRHFxAfMDaBynebdYgakviQkPS1KNJEw7uGWqj91H3hSE4pTERb3EZKLgKXjpqHWrN8dyE8SKyPBE3k7kUGjBNAqJoNGgUzqUW3DSaWrcNr', + secretKeyMultibase: 'secretKeyMultibase', }; describe('w3c-credential-status', () => { describe('createCredentialStatusVC', () => { - it('should create a credential status VC successfully with BLS cryptosuite', async () => { + it('Should throw error when trying to create new VC with BLS cryptosuite', async () => { + await expect( + createCredentialStatusPayload( + { + id: 'https://example.com/credentials/3732', + credentialSubject: { + type: 'BitstringStatusList', + id: 'https://example.com/credentials/status/3#list', + statusPurpose: 'revocation', + encodedList: 'encodedList', + }, + }, + BLS_KEY_PAIR, + 'BitstringStatusListCredential', + 'BbsBlsSignature2020', + ), + ).rejects.toThrowError( + 'BbsBlsSignature2020 is no longer supported. Please use the latest cryptosuite versions instead.', + ); + }); + + it('should create a credential status VC with ECDSA-SD-2023 and v1.1 context', async () => { const credentialStatusPayload = await createCredentialStatusPayload( { id: 'https://example.com/credentials/3732', @@ -38,13 +70,15 @@ describe('w3c-credential-status', () => { encodedList: 'encodedList', }, }, - BLS_KEY_PAIR, + ECDSA_SD_KEY_PAIR, + 'StatusList2021Credential', + 'ecdsa-sd-2023', ); expect(credentialStatusPayload).toMatchObject({ '@context': [ 'https://www.w3.org/2018/credentials/v1', - 'https://w3id.org/security/bbs/v1', + 'https://w3id.org/security/data-integrity/v2', 'https://w3id.org/vc/status-list/2021/v1', ], credentialSubject: { @@ -60,42 +94,43 @@ describe('w3c-credential-status', () => { }); }); - it('should create a credential status VC with ECDSA-SD-2023 and v1.1 context', async () => { + it('should create a credential status VC with ECDSA-SD-2023 and v2.0 context', async () => { const credentialStatusPayload = await createCredentialStatusPayload( { id: 'https://example.com/credentials/3732', credentialSubject: { - type: 'StatusList2021', + type: 'BitstringStatusList', id: 'https://example.com/credentials/status/3#list', statusPurpose: 'revocation', encodedList: 'encodedList', }, }, ECDSA_SD_KEY_PAIR, - 'StatusList2021Credential', + 'BitstringStatusListCredential', 'ecdsa-sd-2023', ); expect(credentialStatusPayload).toMatchObject({ '@context': [ - 'https://www.w3.org/2018/credentials/v1', + 'https://www.w3.org/ns/credentials/v2', 'https://w3id.org/security/data-integrity/v2', - 'https://w3id.org/vc/status-list/2021/v1', ], credentialSubject: { encodedList: 'encodedList', id: 'https://example.com/credentials/status/3#list', statusPurpose: 'revocation', - type: 'StatusList2021', + type: 'BitstringStatusList', }, - issuanceDate: expect.any(String), issuer: 'did:web:trustvc.github.io:did:1', - type: ['VerifiableCredential', 'StatusList2021Credential'], + type: ['VerifiableCredential', 'BitstringStatusListCredential'], validFrom: expect.any(String), }); + + // Explicitly verify that issuanceDate is not present in v2.0 + expect(credentialStatusPayload).not.toHaveProperty('issuanceDate'); }); - it('should create a credential status VC with ECDSA-SD-2023 and v2.0 context', async () => { + it('should create a credential status VC with BBS-2023 and v2.0 context', async () => { const credentialStatusPayload = await createCredentialStatusPayload( { id: 'https://example.com/credentials/3732', @@ -106,9 +141,9 @@ describe('w3c-credential-status', () => { encodedList: 'encodedList', }, }, - ECDSA_SD_KEY_PAIR, + BBS2023_KEY_PAIR, 'BitstringStatusListCredential', - 'ecdsa-sd-2023', + 'bbs-2023', ); expect(credentialStatusPayload).toMatchObject({ diff --git a/packages/w3c-credential-status/src/lib/index.ts b/packages/w3c-credential-status/src/lib/index.ts index eb8af9d2..da4e993c 100644 --- a/packages/w3c-credential-status/src/lib/index.ts +++ b/packages/w3c-credential-status/src/lib/index.ts @@ -1,5 +1,4 @@ import { - BBS_V1_URL, CredentialContextVersion, DATA_INTEGRITY_V2_URL, STATUS_LIST_2021_CREDENTIAL_URL, @@ -38,19 +37,25 @@ export const VCCredentialStatusTypeToVCCredentialSubjectType: Record< * @param {string} options.id - The ID of the credential. * @param {object} options.credentialSubject - The credential subject. * @param {PrivateKeyPair} keyPair - The key pair options for signing. - * @param {VCCredentialStatusType} type - The type of the credential status VC. Defaults to 'StatusList2021Credential'. - * @param {CryptoSuiteName} cryptoSuite - The cryptosuite to be used for signing. Defaults to 'BbsBlsSignature2020'. + * @param {VCCredentialStatusType} type - The type of the credential status VC. Defaults to 'BitstringStatusListCredential'. + * @param {CryptoSuiteName} cryptoSuite - The cryptosuite to be used for signing. Defaults to 'ecdsa-sd-2023'. * @returns {Promise} */ export const createCredentialStatusPayload = async ( options: CreateVCCredentialStatusOptions, keyPair: PrivateKeyPair, - type: VCCredentialStatusType = 'StatusList2021Credential', - cryptoSuite: CryptoSuiteName = 'BbsBlsSignature2020', + type: VCCredentialStatusType = 'BitstringStatusListCredential', + cryptoSuite: CryptoSuiteName = 'ecdsa-sd-2023', ): Promise => { try { const { id, credentialSubject } = options; + if (cryptoSuite === 'BbsBlsSignature2020') { + throw new Error( + 'BbsBlsSignature2020 is no longer supported. Please use the latest cryptosuite versions instead.', + ); + } + switch (type) { case 'StatusList2021Credential': _checkCredentialSubjectForStatusList2021Credential(credentialSubject); @@ -69,13 +74,7 @@ export const createCredentialStatusPayload = async ( // Determine version based on credential type const isV2 = type === 'BitstringStatusListCredential'; const context = [isV2 ? CredentialContextVersion.v2 : CredentialContextVersion.v1]; - - // Add cryptosuite-specific contexts - if (cryptoSuite === 'BbsBlsSignature2020') { - context.push(BBS_V1_URL); - } else { - context.push(DATA_INTEGRITY_V2_URL); - } + context.push(DATA_INTEGRITY_V2_URL); // Add status list context only for v1.1 (v2.0 has it built-in) if (type === 'StatusList2021Credential') { From 8cca2578b6a70e9310e8c47f505ef9f2d4defffe Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 8 Oct 2025 02:05:46 +0000 Subject: [PATCH 114/122] chore(release): @trustvc/w3c-credential-status@1.3.0-alpha.13 [skip ci] # [1.3.0-alpha.13](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-credential-status@1.3.0-alpha.12...@trustvc/w3c-credential-status@1.3.0-alpha.13) (2025-10-08) ### Features * status list update for bbs and v2.0 ([#89](https://github.com/TrustVC/w3c/issues/89)) ([c49bbfe](https://github.com/TrustVC/w3c/commit/c49bbfe0c61eb99993aefa44951b2dbc98aaac0f)) --- packages/w3c-credential-status/CHANGELOG.md | 7 +++++++ packages/w3c-credential-status/package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/w3c-credential-status/CHANGELOG.md b/packages/w3c-credential-status/CHANGELOG.md index 22667cf1..e83004c4 100644 --- a/packages/w3c-credential-status/CHANGELOG.md +++ b/packages/w3c-credential-status/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.13](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-credential-status@1.3.0-alpha.12...@trustvc/w3c-credential-status@1.3.0-alpha.13) (2025-10-08) + + +### Features + +* status list update for bbs and v2.0 ([#89](https://github.com/TrustVC/w3c/issues/89)) ([c49bbfe](https://github.com/TrustVC/w3c/commit/c49bbfe0c61eb99993aefa44951b2dbc98aaac0f)) + # [1.3.0-alpha.12](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-credential-status@1.3.0-alpha.11...@trustvc/w3c-credential-status@1.3.0-alpha.12) (2025-09-24) diff --git a/packages/w3c-credential-status/package.json b/packages/w3c-credential-status/package.json index 420e2a20..ec2b6a96 100644 --- a/packages/w3c-credential-status/package.json +++ b/packages/w3c-credential-status/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c-credential-status", - "version": "1.3.0-alpha.12", + "version": "1.3.0-alpha.13", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", From c8de122379403bcec7632ee10ac5b70904eb9bd2 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 8 Oct 2025 02:06:27 +0000 Subject: [PATCH 115/122] chore(release): @trustvc/w3c-vc@1.3.0-alpha.16 [skip ci] # [1.3.0-alpha.16](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.3.0-alpha.15...@trustvc/w3c-vc@1.3.0-alpha.16) (2025-10-08) ### Features * status list update for bbs and v2.0 ([#89](https://github.com/TrustVC/w3c/issues/89)) ([c49bbfe](https://github.com/TrustVC/w3c/commit/c49bbfe0c61eb99993aefa44951b2dbc98aaac0f)) --- packages/w3c-vc/CHANGELOG.md | 7 +++++++ packages/w3c-vc/package.json | 4 ++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/packages/w3c-vc/CHANGELOG.md b/packages/w3c-vc/CHANGELOG.md index 9063a323..967f9c64 100644 --- a/packages/w3c-vc/CHANGELOG.md +++ b/packages/w3c-vc/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.16](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.3.0-alpha.15...@trustvc/w3c-vc@1.3.0-alpha.16) (2025-10-08) + + +### Features + +* status list update for bbs and v2.0 ([#89](https://github.com/TrustVC/w3c/issues/89)) ([c49bbfe](https://github.com/TrustVC/w3c/commit/c49bbfe0c61eb99993aefa44951b2dbc98aaac0f)) + # [1.3.0-alpha.15](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.3.0-alpha.14...@trustvc/w3c-vc@1.3.0-alpha.15) (2025-10-07) diff --git a/packages/w3c-vc/package.json b/packages/w3c-vc/package.json index 34c87ab2..36e7e24d 100644 --- a/packages/w3c-vc/package.json +++ b/packages/w3c-vc/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c-vc", - "version": "1.3.0-alpha.15", + "version": "1.3.0-alpha.16", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", @@ -37,7 +37,7 @@ "@digitalbazaar/ecdsa-multikey": "^1.8.0", "@digitalbazaar/ecdsa-sd-2023-cryptosuite": "^3.4.1", "@mattrglobal/jsonld-signatures-bbs": "^1.2.0", - "@trustvc/w3c-credential-status": "^1.3.0-alpha.12", + "@trustvc/w3c-credential-status": "^1.3.0-alpha.13", "@trustvc/w3c-issuer": "^1.3.0-alpha.10", "base64url-universal": "^2.0.0", "cbor": "^9.0.2", From 42de1a29702bf411bbe05876c66d3730ddc6ee6b Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 8 Oct 2025 02:07:05 +0000 Subject: [PATCH 116/122] chore(release): @trustvc/w3c@1.3.0-alpha.16 [skip ci] # [1.3.0-alpha.16](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.3.0-alpha.15...@trustvc/w3c@1.3.0-alpha.16) (2025-10-08) ### Features * status list update for bbs and v2.0 ([#89](https://github.com/TrustVC/w3c/issues/89)) ([c49bbfe](https://github.com/TrustVC/w3c/commit/c49bbfe0c61eb99993aefa44951b2dbc98aaac0f)) --- packages/w3c/CHANGELOG.md | 7 +++++++ packages/w3c/package.json | 6 +++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/packages/w3c/CHANGELOG.md b/packages/w3c/CHANGELOG.md index de3baf53..25d62515 100644 --- a/packages/w3c/CHANGELOG.md +++ b/packages/w3c/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.16](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.3.0-alpha.15...@trustvc/w3c@1.3.0-alpha.16) (2025-10-08) + + +### Features + +* status list update for bbs and v2.0 ([#89](https://github.com/TrustVC/w3c/issues/89)) ([c49bbfe](https://github.com/TrustVC/w3c/commit/c49bbfe0c61eb99993aefa44951b2dbc98aaac0f)) + # [1.3.0-alpha.15](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.3.0-alpha.14...@trustvc/w3c@1.3.0-alpha.15) (2025-10-07) diff --git a/packages/w3c/package.json b/packages/w3c/package.json index 56e95c32..eb327237 100644 --- a/packages/w3c/package.json +++ b/packages/w3c/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c", - "version": "1.3.0-alpha.15", + "version": "1.3.0-alpha.16", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", @@ -33,9 +33,9 @@ }, "dependencies": { "@trustvc/w3c-context": "^1.3.0-alpha.12", - "@trustvc/w3c-credential-status": "^1.3.0-alpha.12", + "@trustvc/w3c-credential-status": "^1.3.0-alpha.13", "@trustvc/w3c-issuer": "^1.3.0-alpha.10", - "@trustvc/w3c-vc": "^1.3.0-alpha.15" + "@trustvc/w3c-vc": "^1.3.0-alpha.16" }, "repository": { "type": "git", From 87e1075f77f926728f75ef2bdd150644412af5bb Mon Sep 17 00:00:00 2001 From: RishabhS7 <59636880+RishabhS7@users.noreply.github.com> Date: Thu, 9 Oct 2025 13:25:24 +0530 Subject: [PATCH 117/122] fix: update check credential function (#92) * fix: type checks for test suits * fix: remove tt files * fix: test cases * fix: update checkCredential function --- packages/w3c-vc/src/lib/helper/index.ts | 71 ++++++++++++++++++++++++- packages/w3c-vc/src/lib/types.ts | 11 ++-- 2 files changed, 78 insertions(+), 4 deletions(-) diff --git a/packages/w3c-vc/src/lib/helper/index.ts b/packages/w3c-vc/src/lib/helper/index.ts index da47e5f2..71c7751e 100644 --- a/packages/w3c-vc/src/lib/helper/index.ts +++ b/packages/w3c-vc/src/lib/helper/index.ts @@ -25,6 +25,7 @@ import { proofTypeMapping, RawVerifiableCredential, VerifiableCredential, + CredentialSchema, } from '../types'; /** @@ -82,7 +83,14 @@ function _getId(obj: T | string): string | undefined // These properties of a Verifiable Credential (VC) must be objects containing a type field // if they are present in the VC. -const mustHaveType = ['proof', 'credentialStatus', 'termsOfUse', 'refreshService']; +const mustHaveType = [ + 'proof', + 'credentialStatus', + 'credentialSchema', + 'termsOfUse', + 'refreshService', + 'evidence', +]; // Regular expression to validate date-time format according to XML schema. // Z and T must be uppercase @@ -202,6 +210,8 @@ export function _checkCredential( const isV2 = firstContext === CredentialContextVersion.v2; if (isV2) { + _checkCredentialSchemas(credential); + // v2.0 format: validFrom is optional, validUntil is optional if ('validFrom' in credential) { assertDateString({ credential, prop: 'validFrom' }); @@ -223,6 +233,15 @@ export function _checkCredential( } } } + // Validate temporal relationship between validFrom and validUntil + if ('validFrom' in credential && 'validUntil' in credential) { + const validFromDate = new Date(credential.validFrom); + const validUntilDate = new Date(credential.validUntil); + + if (validFromDate > validUntilDate) { + throw new Error('validFrom must be temporally the same or earlier than validUntil'); + } + } // Check if the current date is before the validFrom date during verification if (mode === 'verify' && credential.validFrom) { @@ -380,6 +399,56 @@ function _checkCredentialSubject(subject: CredentialSubject): void { }); } } +/** + * Validates the credentialSchema field in a Verifiable Credential. + * Throws an error if the field is missing or invalid. + * + * @param {VerifiableCredential} credential - The Verifiable Credential object. + * @throws {Error} If the credentialSchema field is missing or invalid. + */ +function _checkCredentialSchemas(credential: VerifiableCredential): void { + if ('credentialSchema' in credential) { + const schemas = Array.isArray(credential.credentialSchema) + ? credential.credentialSchema + : [credential.credentialSchema]; + + for (const schema of schemas) { + _checkCredentialSchema(schema); + } + } +} + +/** + * Validates a credential schema object to ensure it contains valid properties. + * Throws an error if the credential schema is not valid. + * + * @param {CredentialSchema} schema - The credential schema object to validate. + * @throws {Error} If the credential schema is invalid. + */ +function _checkCredentialSchema(schema: CredentialSchema): void { + // Validate credentialSchema if present + + if (typeof schema !== 'object' || schema === null) { + throw new Error('credentialSchema must be an object'); + } + + if (!schema.id) { + throw new Error( + 'credentialSchema objects must have an id property that is a URL identifying the schema file', + ); + } + + if (typeof schema.id !== 'string') { + throw new Error('credentialSchema id property must be a URL string'); + } + + // Basic URL validation for schema id + try { + new URL(schema.id); + } catch (e) { + throw new Error('credentialSchema id property must be a valid URL'); + } +} /** * Checks if the provided value is a valid object. diff --git a/packages/w3c-vc/src/lib/types.ts b/packages/w3c-vc/src/lib/types.ts index 77ae9863..97f5ba46 100644 --- a/packages/w3c-vc/src/lib/types.ts +++ b/packages/w3c-vc/src/lib/types.ts @@ -37,9 +37,14 @@ export type TermsOfUse = { } & Record; export type TermsOfUses = TermsOfUse | TermsOfUse[]; -export type RelatedResource = { - type: string; -} & Record; +type RelatedResource = { + id: string; + mediaType?: string; +} & ( + | { digestSRI: string; digestMultibase?: string } + | { digestSRI?: string; digestMultibase: string } +) & + Record; export type RelatedResources = RelatedResource | RelatedResource[]; export type RefreshService = { From 12ef3d315e711b9b15a92ddc5d1a0b7bfdbe34a1 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Thu, 9 Oct 2025 07:58:54 +0000 Subject: [PATCH 118/122] chore(release): @trustvc/w3c-vc@1.3.0-alpha.17 [skip ci] # [1.3.0-alpha.17](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.3.0-alpha.16...@trustvc/w3c-vc@1.3.0-alpha.17) (2025-10-09) ### Bug Fixes * update check credential function ([#92](https://github.com/TrustVC/w3c/issues/92)) ([87e1075](https://github.com/TrustVC/w3c/commit/87e1075f77f926728f75ef2bdd150644412af5bb)) --- packages/w3c-vc/CHANGELOG.md | 7 +++++++ packages/w3c-vc/package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/w3c-vc/CHANGELOG.md b/packages/w3c-vc/CHANGELOG.md index 967f9c64..007d59cb 100644 --- a/packages/w3c-vc/CHANGELOG.md +++ b/packages/w3c-vc/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.17](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.3.0-alpha.16...@trustvc/w3c-vc@1.3.0-alpha.17) (2025-10-09) + + +### Bug Fixes + +* update check credential function ([#92](https://github.com/TrustVC/w3c/issues/92)) ([87e1075](https://github.com/TrustVC/w3c/commit/87e1075f77f926728f75ef2bdd150644412af5bb)) + # [1.3.0-alpha.16](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@1.3.0-alpha.15...@trustvc/w3c-vc@1.3.0-alpha.16) (2025-10-08) diff --git a/packages/w3c-vc/package.json b/packages/w3c-vc/package.json index 36e7e24d..2e7176e4 100644 --- a/packages/w3c-vc/package.json +++ b/packages/w3c-vc/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c-vc", - "version": "1.3.0-alpha.16", + "version": "1.3.0-alpha.17", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", From 8bc94ebcf83c192aa473f0af7fcde5711e278258 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Thu, 9 Oct 2025 07:59:24 +0000 Subject: [PATCH 119/122] chore(release): @trustvc/w3c@1.3.0-alpha.17 [skip ci] # [1.3.0-alpha.17](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.3.0-alpha.16...@trustvc/w3c@1.3.0-alpha.17) (2025-10-09) ### Bug Fixes * update check credential function ([#92](https://github.com/TrustVC/w3c/issues/92)) ([87e1075](https://github.com/TrustVC/w3c/commit/87e1075f77f926728f75ef2bdd150644412af5bb)) --- packages/w3c/CHANGELOG.md | 7 +++++++ packages/w3c/package.json | 4 ++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/packages/w3c/CHANGELOG.md b/packages/w3c/CHANGELOG.md index 25d62515..e3618286 100644 --- a/packages/w3c/CHANGELOG.md +++ b/packages/w3c/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.3.0-alpha.17](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.3.0-alpha.16...@trustvc/w3c@1.3.0-alpha.17) (2025-10-09) + + +### Bug Fixes + +* update check credential function ([#92](https://github.com/TrustVC/w3c/issues/92)) ([87e1075](https://github.com/TrustVC/w3c/commit/87e1075f77f926728f75ef2bdd150644412af5bb)) + # [1.3.0-alpha.16](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@1.3.0-alpha.15...@trustvc/w3c@1.3.0-alpha.16) (2025-10-08) diff --git a/packages/w3c/package.json b/packages/w3c/package.json index eb327237..4b06e373 100644 --- a/packages/w3c/package.json +++ b/packages/w3c/package.json @@ -1,6 +1,6 @@ { "name": "@trustvc/w3c", - "version": "1.3.0-alpha.16", + "version": "1.3.0-alpha.17", "description": "", "main": "dist/index.js", "module": "dist/esm/index.js", @@ -35,7 +35,7 @@ "@trustvc/w3c-context": "^1.3.0-alpha.12", "@trustvc/w3c-credential-status": "^1.3.0-alpha.13", "@trustvc/w3c-issuer": "^1.3.0-alpha.10", - "@trustvc/w3c-vc": "^1.3.0-alpha.16" + "@trustvc/w3c-vc": "^1.3.0-alpha.17" }, "repository": { "type": "git", From 18802f213243dde78a33b07dac6c310962241d60 Mon Sep 17 00:00:00 2001 From: Moiz Shaikh <58319530+Moiz47@users.noreply.github.com> Date: Wed, 22 Oct 2025 08:44:17 +0530 Subject: [PATCH 120/122] docs: w3c issuer readme update (#93) Co-authored-by: moiz-sgtradex --- packages/w3c-issuer/README.md | 72 ++++++++++++++++++----------------- 1 file changed, 38 insertions(+), 34 deletions(-) diff --git a/packages/w3c-issuer/README.md b/packages/w3c-issuer/README.md index 59dbadc5..6fb47e66 100644 --- a/packages/w3c-issuer/README.md +++ b/packages/w3c-issuer/README.md @@ -10,7 +10,7 @@ npm install @trustvc/w3c-issuer ``` ## Features -- Create private key pairs for specific [Signature Suites](https://w3c-ccg.github.io/ld-cryptosuite-registry/) used for signing Verifiable Credentials (e.g., BBS). +- Create private key pairs for specific signature suites used for signing Verifiable Credentials: [ECDSA-SD-2023](https://w3c.github.io/vc-di-ecdsa/#ecdsa-sd-2023), [BBS-2023](https://w3c.github.io/vc-di-bbs/#bbs-2023), and [legacy suites](https://w3c-ccg.github.io/ld-cryptosuite-registry/). - Generate DID private key pairs and DID documents.
@@ -23,26 +23,30 @@ ________________________________ `generateKeyPair` function helps to generate a signature Key Pair. ```ts -import { generateKeyPair, VerificationType } from '@trustvc/w3c-issuer'; +import { generateKeyPair, CryptoSuite } from '@trustvc/w3c-issuer'; /** * Parameters: * - options (GenerateKeyPairOptions) - * - options.type (VerificationType): Key Pair algo type for Signature + * - options.type (CryptoSuite | VerificationType): Key Pair algo type for Signature * - options.seedBase58? (string): 32 byte base58 encoded seed (e.g. FVj12jBiBUqYFaEUkTuwAD73p9Hx5NzCJBge74nTguQN) (optional) * - options.privateKeyBase58? (string): private key value (optional) * - options.publicKeyBase58? (string): public key value (optional) + * - options.secretKeyMultibase? (string): private key value in multibase format (optional) + * - options.publicKeyMultibase? (string): public key value in multibase format (optional) * * Returns: * - A Promise that resolves to: - * - generatedKeyPair.type (VerificationType): Key Pair algo. - * - generatedKeyPair.seedBase58 (string): 32 byte base58 encoded seed - * - generatedKeyPair.privateKeyBase58 (string): Derieve private key from seed - * - generatedKeyPair.publicKeyBase58 (string): Detrieve public key from seed + * - generatedKeyPair.type (CryptoSuite | VerificationType): Key Pair algo. + * - generatedKeyPair.secretKeyMultibase (string): Private key in multibase format (for modern cryptosuites) + * - generatedKeyPair.publicKeyMultibase (string): Public key in multibase format (for modern cryptosuites) + * - generatedKeyPair.seedBase58 (string): 32 byte base58 encoded seed (for legacy types only) + * - generatedKeyPair.privateKeyBase58 (string): Private key in base58 format (for legacy types only) + * - generatedKeyPair.publicKeyBase58 (string): Public key in base58 format (for legacy types only) */ const options = { - type: VerificationType.Bls12381G2Key2020, + type: CryptoSuite.EcdsaSd2023, seedBase58: undefined } @@ -55,10 +59,9 @@ console.log('generatedKeyPair: ', generatedKeyPair) ```js generatedKeyPair: { - type: 'Bls12381G2Key2020', - seedBase58: '', - privateKeyBase58: '', + publicKeyMultibase: '' } ```
@@ -74,16 +77,18 @@ console.log('generatedKeyPair: ', generatedKeyPair) *Read [here]() for more signing instructions.* ```ts -import { VerificationType, issueDID } from '@trustvc/w3c-issuer'; +import { CryptoSuite, issueDID } from '@trustvc/w3c-issuer'; /** * Parameters: * - options (IssuedDIDOption) * - options.domain (string): URL where the DID Document will be located - * - options.type (VerificationType): Key Pair algo. - * - options.seedBase58? (string): 32 byte base58 encoded seed (optional) - * - options.privateKeyBase58? (string): Derieved private key from seed (optional) - * - options.publicKeyBase58? (string): Detrieved public key from seed (optional) + * - options.type (CryptoSuite | VerificationType): Key Pair algo. + * - options.secretKeyMultibase? (string): Private key in multibase format (optional, for modern cryptosuites) + * - options.publicKeyMultibase? (string): Public key in multibase format (optional, for modern cryptosuites) + * - options.seedBase58? (string): 32 byte base58 encoded seed (optional, for legacy types) + * - options.privateKeyBase58? (string): Private key in base58 format (optional, for legacy types) + * - options.publicKeyBase58? (string): Public key in base58 format (optional, for legacy types) * * Returns: * - A Promise that resolves to: @@ -93,10 +98,9 @@ import { VerificationType, issueDID } from '@trustvc/w3c-issuer'; const options = { domain: 'https://example.com/.well-known/did.json', - type: VerificationType.Bls12381G2Key2020, - seedBase58: '', - privateKeyBase58: '', - publicKeyBase58: 'oRfEeWFresvhRtXCkihZbxyoi2JER7gHTJ5psXhHsdCoU1MttRMi3Yp9b9fpjmKh7bMgfWKLESiK2YovRd8KGzJsGuamoAXfqDDVhckxuc9nmsJ84skCSTijKeU4pfAcxeJ' + type: CryptoSuite.EcdsaSd2023, + secretKeyMultibase: '', + publicKeyMultibase: '' } const issuedDID = await issueDID(options); @@ -113,28 +117,28 @@ console.log("didKeyPairs:", didKeyPairs) id: 'did:web:example.com', verificationMethod: [ { - type: 'Bls12381G2Key2020', - id: 'did:web:example.com#keys-1', + type: 'Multikey', + id: 'did:web:example.com#multikey-1', controller: 'did:web:example.com', - publicKeyBase58: 'oRfEeWFresvhRtXCkihZbxyoi2JER7gHTJ5psXhHsdCoU1MttRMi3Yp9b9fpjmKh7bMgfWKLESiK2YovRd8KGzJsGuamoAXfqDDVhckxuc9nmsJ84skCSTijKeU4pfAcxeJ' + publicKeyMultibase: '' } ], '@context': [ 'https://www.w3.org/ns/did/v1', - 'https://w3id.org/security/suites/bls12381-2020/v1' + 'https://w3id.org/security/multikey/v1' ], - authentication: [ 'did:web:example.com#keys-1' ], - assertionMethod: [ 'did:web:example.com#keys-1' ], - capabilityInvocation: [ 'did:web:example.com#keys-1' ], - capabilityDelegation: [ 'did:web:example.com#keys-1' ] + authentication: [ 'did:web:example.com#multikey-1' ], + assertionMethod: [ 'did:web:example.com#multikey-1' ], + capabilityInvocation: [ 'did:web:example.com#multikey-1' ], + capabilityDelegation: [ 'did:web:example.com#multikey-1' ] } didKeyPairs: { - id: 'did:web:example.com#keys-1', - type: 'Bls12381G2Key2020', + '@context': 'https://w3id.org/security/multikey/v1', + id: 'did:web:example.com#multikey-1', + type: 'Multikey', controller: 'did:web:example.com', - seedBase58: '', - privateKeyBase58: '', - publicKeyBase58: 'oRfEeWFresvhRtXCkihZbxyoi2JER7gHTJ5psXhHsdCoU1MttRMi3Yp9b9fpjmKh7bMgfWKLESiK2YovRd8KGzJsGuamoAXfqDDVhckxuc9nmsJ84skCSTijKeU4pfAcxeJ' + secretKeyMultibase: '', + publicKeyMultibase: '' } ``` From 2938a2a4b4fa89be4a0e73135554a4e0b1da3e77 Mon Sep 17 00:00:00 2001 From: moiz-sgtradex Date: Mon, 10 Nov 2025 16:23:42 +0530 Subject: [PATCH 121/122] feat: modern crypto suites BBS2020 depreciation and other bug fixes BREAKING CHANGE --- package-lock.json | 282 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 269 insertions(+), 13 deletions(-) diff --git a/package-lock.json b/package-lock.json index 33f55723..f30c7a93 100644 --- a/package-lock.json +++ b/package-lock.json @@ -136,6 +136,134 @@ "node": ">=18.x" } }, + "apps/w3c-cli/node_modules/@trustvc/w3c-vc": { + "version": "1.3.0-alpha.17", + "resolved": "https://registry.npmjs.org/@trustvc/w3c-vc/-/w3c-vc-1.3.0-alpha.17.tgz", + "integrity": "sha512-aQXiu8xQ3fIN262h1KCoWkWRH0AeeTzN/68NbDqv3DdbA/iAnQoerwoSd//7oFoithr0yySCbcViulqlMZ8kHg==", + "license": "Apache-2.0", + "dependencies": { + "@digitalbazaar/bbs-2023-cryptosuite": "^2.0.1", + "@digitalbazaar/bls12-381-multikey": "^2.1.0", + "@digitalbazaar/data-integrity": "^2.5.0", + "@digitalbazaar/ecdsa-multikey": "^1.8.0", + "@digitalbazaar/ecdsa-sd-2023-cryptosuite": "^3.4.1", + "@mattrglobal/jsonld-signatures-bbs": "^1.2.0", + "@trustvc/w3c-credential-status": "^1.3.0-alpha.13", + "@trustvc/w3c-issuer": "^1.3.0-alpha.10", + "base64url-universal": "^2.0.0", + "cbor": "^9.0.2", + "did-resolver": "^4.1.0", + "jsonld": "^6.0.0", + "jsonld-signatures": "^11.5.0", + "jsonld-signatures-v7": "npm:jsonld-signatures@7.0.0", + "uuid": "^10.0.0" + }, + "engines": { + "node": ">=18.x" + }, + "peerDependencies": { + "jsonld": "^6.0.0" + } + }, + "apps/w3c-cli/node_modules/jsonld-signatures": { + "version": "11.5.0", + "resolved": "https://registry.npmjs.org/jsonld-signatures/-/jsonld-signatures-11.5.0.tgz", + "integrity": "sha512-Kdto+e8uvY/5u3HYkmAbpy52bplWX9uqS8fmqdCv6oxnCFwCTM0hMt6r4rWqlhw5/aHoCHJIRxwYb4QKGC69Jw==", + "license": "BSD-3-Clause", + "dependencies": { + "@digitalbazaar/security-context": "^1.0.0", + "jsonld": "^8.0.0", + "rdf-canonize": "^4.0.1", + "serialize-error": "^8.1.0" + }, + "engines": { + "node": ">=18" + } + }, + "apps/w3c-cli/node_modules/jsonld-signatures/node_modules/jsonld": { + "version": "8.3.3", + "resolved": "https://registry.npmjs.org/jsonld/-/jsonld-8.3.3.tgz", + "integrity": "sha512-9YcilrF+dLfg9NTEof/mJLMtbdX1RJ8dbWtJgE00cMOIohb1lIyJl710vFiTaiHTl6ZYODJuBd32xFvUhmv3kg==", + "license": "BSD-3-Clause", + "dependencies": { + "@digitalbazaar/http-client": "^3.4.1", + "canonicalize": "^1.0.1", + "lru-cache": "^6.0.0", + "rdf-canonize": "^3.4.0" + }, + "engines": { + "node": ">=14" + } + }, + "apps/w3c-cli/node_modules/jsonld-signatures/node_modules/jsonld/node_modules/rdf-canonize": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/rdf-canonize/-/rdf-canonize-3.4.0.tgz", + "integrity": "sha512-fUeWjrkOO0t1rg7B2fdyDTvngj+9RlUyL92vOdiB7c0FPguWVsniIMjEtHH+meLBO9rzkUlUzBVXgWrjI8P9LA==", + "license": "BSD-3-Clause", + "dependencies": { + "setimmediate": "^1.0.5" + }, + "engines": { + "node": ">=12" + } + }, + "apps/w3c-cli/node_modules/jsonld-signatures/node_modules/rdf-canonize": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/rdf-canonize/-/rdf-canonize-4.0.1.tgz", + "integrity": "sha512-B5ynHt4sasbUafzrvYI2GFARgeFcD8Sx9yXPbg7gEyT2EH76rlCv84kyO6tnxzVbxUN/uJDbK1S/MXh+DsnuTA==", + "license": "BSD-3-Clause", + "dependencies": { + "setimmediate": "^1.0.5" + }, + "engines": { + "node": ">=18" + } + }, + "apps/w3c-cli/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "apps/w3c-cli/node_modules/serialize-error": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-8.1.0.tgz", + "integrity": "sha512-3NnuWfM6vBYoy5gZFvHiYsVbafvI9vZv/+jlIigFn4oP4zjNPK3LhcY0xSCgeb1a5L8jO71Mit9LlNoi2UfDDQ==", + "license": "MIT", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "apps/w3c-cli/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "apps/w3c-cli/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "license": "ISC" + }, "node_modules/@adraffy/ens-normalize": { "version": "1.10.1", "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.10.1.tgz", @@ -32834,13 +32962,13 @@ }, "packages/w3c": { "name": "@trustvc/w3c", - "version": "1.3.0-alpha.12", + "version": "1.3.0-alpha.17", "license": "Apache-2.0", "dependencies": { - "@trustvc/w3c-context": "^1.3.0-alpha.11", - "@trustvc/w3c-credential-status": "^1.3.0-alpha.11", - "@trustvc/w3c-issuer": "^1.3.0-alpha.9", - "@trustvc/w3c-vc": "^1.3.0-alpha.12" + "@trustvc/w3c-context": "^1.3.0-alpha.12", + "@trustvc/w3c-credential-status": "^1.3.0-alpha.13", + "@trustvc/w3c-issuer": "^1.3.0-alpha.10", + "@trustvc/w3c-vc": "^1.3.0-alpha.17" }, "engines": { "node": ">=18.x" @@ -32848,7 +32976,7 @@ }, "packages/w3c-context": { "name": "@trustvc/w3c-context", - "version": "1.3.0-alpha.11", + "version": "1.3.0-alpha.12", "license": "Apache-2.0", "dependencies": { "did-resolver": "^4.1.0", @@ -32940,11 +33068,11 @@ }, "packages/w3c-credential-status": { "name": "@trustvc/w3c-credential-status", - "version": "1.3.0-alpha.11", + "version": "1.3.0-alpha.13", "license": "Apache-2.0", "dependencies": { - "@trustvc/w3c-context": "^1.3.0-alpha.11", - "@trustvc/w3c-issuer": "^1.3.0-alpha.9", + "@trustvc/w3c-context": "^1.3.0-alpha.12", + "@trustvc/w3c-issuer": "^1.3.0-alpha.10", "base64url-universal": "^2.0.0", "pako": "^2.1.0" }, @@ -32954,7 +33082,7 @@ }, "packages/w3c-issuer": { "name": "@trustvc/w3c-issuer", - "version": "1.3.0-alpha.9", + "version": "1.3.0-alpha.10", "license": "Apache-2.0", "dependencies": { "@digitalbazaar/bls12-381-multikey": "^2.1.0", @@ -32971,7 +33099,7 @@ }, "packages/w3c-vc": { "name": "@trustvc/w3c-vc", - "version": "1.3.0-alpha.12", + "version": "1.2.17", "license": "Apache-2.0", "dependencies": { "@digitalbazaar/bbs-2023-cryptosuite": "^2.0.1", @@ -32980,8 +33108,8 @@ "@digitalbazaar/ecdsa-multikey": "^1.8.0", "@digitalbazaar/ecdsa-sd-2023-cryptosuite": "^3.4.1", "@mattrglobal/jsonld-signatures-bbs": "^1.2.0", - "@trustvc/w3c-credential-status": "^1.3.0-alpha.11", - "@trustvc/w3c-issuer": "^1.3.0-alpha.9", + "@trustvc/w3c-credential-status": "^1.3.0-alpha.13", + "@trustvc/w3c-issuer": "^1.3.0-alpha.10", "base64url-universal": "^2.0.0", "cbor": "^9.0.2", "did-resolver": "^4.1.0", @@ -33090,6 +33218,134 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "packages/w3c/node_modules/@trustvc/w3c-vc": { + "version": "1.3.0-alpha.17", + "resolved": "https://registry.npmjs.org/@trustvc/w3c-vc/-/w3c-vc-1.3.0-alpha.17.tgz", + "integrity": "sha512-aQXiu8xQ3fIN262h1KCoWkWRH0AeeTzN/68NbDqv3DdbA/iAnQoerwoSd//7oFoithr0yySCbcViulqlMZ8kHg==", + "license": "Apache-2.0", + "dependencies": { + "@digitalbazaar/bbs-2023-cryptosuite": "^2.0.1", + "@digitalbazaar/bls12-381-multikey": "^2.1.0", + "@digitalbazaar/data-integrity": "^2.5.0", + "@digitalbazaar/ecdsa-multikey": "^1.8.0", + "@digitalbazaar/ecdsa-sd-2023-cryptosuite": "^3.4.1", + "@mattrglobal/jsonld-signatures-bbs": "^1.2.0", + "@trustvc/w3c-credential-status": "^1.3.0-alpha.13", + "@trustvc/w3c-issuer": "^1.3.0-alpha.10", + "base64url-universal": "^2.0.0", + "cbor": "^9.0.2", + "did-resolver": "^4.1.0", + "jsonld": "^6.0.0", + "jsonld-signatures": "^11.5.0", + "jsonld-signatures-v7": "npm:jsonld-signatures@7.0.0", + "uuid": "^10.0.0" + }, + "engines": { + "node": ">=18.x" + }, + "peerDependencies": { + "jsonld": "^6.0.0" + } + }, + "packages/w3c/node_modules/jsonld-signatures": { + "version": "11.5.0", + "resolved": "https://registry.npmjs.org/jsonld-signatures/-/jsonld-signatures-11.5.0.tgz", + "integrity": "sha512-Kdto+e8uvY/5u3HYkmAbpy52bplWX9uqS8fmqdCv6oxnCFwCTM0hMt6r4rWqlhw5/aHoCHJIRxwYb4QKGC69Jw==", + "license": "BSD-3-Clause", + "dependencies": { + "@digitalbazaar/security-context": "^1.0.0", + "jsonld": "^8.0.0", + "rdf-canonize": "^4.0.1", + "serialize-error": "^8.1.0" + }, + "engines": { + "node": ">=18" + } + }, + "packages/w3c/node_modules/jsonld-signatures/node_modules/jsonld": { + "version": "8.3.3", + "resolved": "https://registry.npmjs.org/jsonld/-/jsonld-8.3.3.tgz", + "integrity": "sha512-9YcilrF+dLfg9NTEof/mJLMtbdX1RJ8dbWtJgE00cMOIohb1lIyJl710vFiTaiHTl6ZYODJuBd32xFvUhmv3kg==", + "license": "BSD-3-Clause", + "dependencies": { + "@digitalbazaar/http-client": "^3.4.1", + "canonicalize": "^1.0.1", + "lru-cache": "^6.0.0", + "rdf-canonize": "^3.4.0" + }, + "engines": { + "node": ">=14" + } + }, + "packages/w3c/node_modules/jsonld-signatures/node_modules/jsonld/node_modules/rdf-canonize": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/rdf-canonize/-/rdf-canonize-3.4.0.tgz", + "integrity": "sha512-fUeWjrkOO0t1rg7B2fdyDTvngj+9RlUyL92vOdiB7c0FPguWVsniIMjEtHH+meLBO9rzkUlUzBVXgWrjI8P9LA==", + "license": "BSD-3-Clause", + "dependencies": { + "setimmediate": "^1.0.5" + }, + "engines": { + "node": ">=12" + } + }, + "packages/w3c/node_modules/jsonld-signatures/node_modules/rdf-canonize": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/rdf-canonize/-/rdf-canonize-4.0.1.tgz", + "integrity": "sha512-B5ynHt4sasbUafzrvYI2GFARgeFcD8Sx9yXPbg7gEyT2EH76rlCv84kyO6tnxzVbxUN/uJDbK1S/MXh+DsnuTA==", + "license": "BSD-3-Clause", + "dependencies": { + "setimmediate": "^1.0.5" + }, + "engines": { + "node": ">=18" + } + }, + "packages/w3c/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "packages/w3c/node_modules/serialize-error": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-8.1.0.tgz", + "integrity": "sha512-3NnuWfM6vBYoy5gZFvHiYsVbafvI9vZv/+jlIigFn4oP4zjNPK3LhcY0xSCgeb1a5L8jO71Mit9LlNoi2UfDDQ==", + "license": "MIT", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "packages/w3c/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "packages/w3c/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "license": "ISC" } } } From 2ff11f7d7af2a381164945e272df7252dd561b23 Mon Sep 17 00:00:00 2001 From: moiz-sgtradex Date: Mon, 10 Nov 2025 16:35:55 +0530 Subject: [PATCH 122/122] feat: removed duplicate --- packages/w3c-credential-status/src/lib/utils.ts | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/packages/w3c-credential-status/src/lib/utils.ts b/packages/w3c-credential-status/src/lib/utils.ts index 2fafd9cb..983a0e64 100644 --- a/packages/w3c-credential-status/src/lib/utils.ts +++ b/packages/w3c-credential-status/src/lib/utils.ts @@ -44,19 +44,6 @@ export const assertCredentialStatusStatusListType = (type: T): void => { } }; -/** - * Asserts the type of the credential status statusList. - * @param type - The type of the credential status. - * @throws {Error} - Throws an error if the type is not supported. - */ -export const assertCredentialStatusStatusListType = (type: T): void => { - const supportedTypes: T[] = ['StatusList2021Entry'] as T[]; - - if (!supportedTypes.includes(type)) { - throw new Error(`Unsupported type: ${type}`); - } -}; - /** * Asserts the statusListIndex is a valid number. * @param statusListIndex - The index of the statusList in the statusListCredential.