diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 06c3297..4aa9aa3 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -8,7 +8,7 @@ jobs: timeout-minutes: 10 strategy: matrix: - node-version: [16.x] + node-version: [18.x] steps: - uses: actions/checkout@v2 - name: Use Node.js ${{ matrix.node-version }} diff --git a/.knownDidRegistries.ts b/.knownDidRegistries.ts new file mode 100644 index 0000000..ed44cb4 --- /dev/null +++ b/.knownDidRegistries.ts @@ -0,0 +1,19 @@ +export const knownDidRegistries = [ + { + name: 'DCC Pilot Registry', + url: 'https://digitalcredentials.github.io/issuer-registry/registry.json' + }, + { + name: 'DCC Sandbox Registry', + url: 'https://digitalcredentials.github.io/sandbox-registry/registry.json' + }, + { + name: 'DCC Community Registry', + url: 'https://digitalcredentials.github.io/community-registry/registry.json' + }, + { + name: 'DCC Registry', + url: 'https://digitalcredentials.github.io/dcc-registry/registry.json' + } +] + diff --git a/CHANGELOG.md b/CHANGELOG.md index cdf18c2..2312d23 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # isomorphic-lib-template Changelog -## 1.0.0 - TBD +## 0.0.1 - TBD ### Added diff --git a/LICENSE.md b/LICENSE.md index 6d9b390..10ea4ba 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2022 Digital Credentials Consortium +Copyright (c) 2025 Digital Credentials Consortium Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 51429f3..c813e8b 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ -# Example Isomorphic TS/JS Lib Template _(@digitalcredentials/isomorphic-lib-template)_ +# verifier-core _(@digitalcredentials/verifier-core)_ -[![Build status](https://img.shields.io/github/actions/workflow/status/digitalcredentials/isomorphic-lib-template/main.yml?branch=main)](https://github.com/digitalcredentials/isomorphic-lib-template/actions?query=workflow%3A%22Node.js+CI%22) -[![NPM Version](https://img.shields.io/npm/v/@digitalcredentials/isomorphic-lib-template.svg)](https://npm.im/@digitalcredentials/isomorphic-lib-template) +[![Build status](https://img.shields.io/github/actions/workflow/status/digitalcredentials/verifier-core/main.yml?branch=main)](https://github.com/digitalcredentials/verifier-core/actions?query=workflow%3A%22Node.js+CI%22) +[![NPM Version](https://img.shields.io/npm/v/@digitalcredentials/verifier-core.svg)](https://npm.im/@digitalcredentials/verifier-core) -> A Typescript/Javascript isomorphic library template, for use in the browser, Node.js, and React Native. +> For verifying Verifiable Credentials in the browser, Node.js, and React Native. ## Table of Contents @@ -16,7 +16,7 @@ ## Background -TBD +The Digital Credentials Consortium has a few applications that verify credentials in essentially the same way, with consequent code duplication. This package extracts that common functionality to a single shared package to make ongoing maintenance easier. ## Security @@ -24,14 +24,14 @@ TBD ## Install -- Node.js 16+ is recommended. +- Node.js 18+ is recommended. ### NPM To install via NPM: ``` -npm install @digitalcredentials/isomorphic-lib-template +npm install @digitalcredentials/verifier-core ``` ### Development @@ -39,8 +39,8 @@ npm install @digitalcredentials/isomorphic-lib-template To install locally (for development): ``` -git clone https://github.com/digitalcredentials/isomorphic-lib-template.git -cd isomorphic-lib-template +git clone https://github.com/digitalcredentials/verifier-core.git +cd verifier-core npm install ``` @@ -57,4 +57,4 @@ If editing the Readme, please conform to the ## License -[MIT License](LICENSE.md) © 2022 Digital Credentials Consortium. +[MIT License](LICENSE.md) © 2025 Digital Credentials Consortium. diff --git a/package.json b/package.json index 6dab6b5..23b8de3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { - "name": "@digitalcredentials/isomorphic-lib-template", - "description": "A Typescript/Javascript isomorphic library template, for use in the browser, Node.js, and React Native.", + "name": "@digitalcredentials/verifier-core", + "description": "For verifying Verifiable Credentials in the browser, Node.js, and React Native.", "version": "0.0.1", "scripts": { "build": "npm run clear && tsc -d && tsc -p tsconfig.esm.json", @@ -23,6 +23,15 @@ "module": "dist/esm/index.js", "types": "dist/index.d.ts", "dependencies": { + "@digitalbazaar/data-integrity": "^2.5.0", + "@digitalbazaar/eddsa-rdfc-2022-cryptosuite": "^1.2.0", + "@digitalcredentials/ed25519-signature-2020": "^6.0.0", + "@digitalcredentials/issuer-registry-client": "^3.0.0", + "@digitalcredentials/jsonld-signatures": "^12.0.1", + "@digitalcredentials/security-document-loader": "^6.0.1", + "@digitalcredentials/vc": "^9.0.1", + "@digitalcredentials/vc-bitstring-status-list": "^1.0.0", + "@digitalcredentials/vc-status-list": "^9.0.0" }, "devDependencies": { "@types/chai": "^4.3.4", diff --git a/src/Example.ts b/src/Example.ts deleted file mode 100644 index 4e4a5f1..0000000 --- a/src/Example.ts +++ /dev/null @@ -1,8 +0,0 @@ -/*! - * Copyright (c) 2022 Digital Credentials Consortium. All rights reserved. - */ -export class Example { - public hello(): string { - return 'world' - } -} diff --git a/src/Verify.ts b/src/Verify.ts new file mode 100644 index 0000000..3f1dddb --- /dev/null +++ b/src/Verify.ts @@ -0,0 +1,84 @@ +// import '@digitalcredentials/data-integrity-rn'; +import { Ed25519Signature2020 } from '@digitalcredentials/ed25519-signature-2020'; +import * as vc from '@digitalcredentials/vc'; +import { securityLoader } from '@digitalcredentials/security-document-loader'; +import { getCredentialStatusChecker } from './credentialStatus'; +import { addTrustedIssuersToVerificationResponse } from './issuerRegistries'; + +import { Credential } from './types/credential'; + +/* +// the new eddsa-rdfc-2022-cryptosuite +import {DataIntegrityProof} from '@digitalbazaar/data-integrity'; +import {cryptosuite as eddsaRdfc2022CryptoSuite} from '@digitalbazaar/eddsa-rdfc-2022-cryptosuite'; +const suite = new DataIntegrityProof({ + cryptosuite: eddsaRdfc2022CryptoSuite +}); +*/ + +const documentLoader = securityLoader({ fetchRemoteContexts: true }).build(); +const suite = new Ed25519Signature2020(); + +export interface VerificationError { + "message": string, + "isFatal": boolean +} + +export interface Step { + "id": string, + "valid": boolean, + "foundInRegistries"?: string[], +} + +export interface VerificationResponse { + "verified": boolean, + "isFatal": boolean, + "credential": object, + "errors"?: VerificationError[], + "log"?: Step[] +} + +export async function verifyCredential({credential, reloadIssuerRegistry = true}:{credential: Credential, reloadIssuerRegistry: boolean}): Promise { + + const fatalErrorMessage = checkForFatalErrors(credential) + + if (fatalErrorMessage) return {credential, isFatal: true, verified: false, errors: [{message: fatalErrorMessage, isFatal: true}]} + + const verificationResponse = await vc.verifyCredential({ + credential, + suite, + documentLoader, + checkStatus: getCredentialStatusChecker(credential) + }); + + delete verificationResponse.results + delete verificationResponse.statusResult + + const { issuer } = credential + await addTrustedIssuersToVerificationResponse({verificationResponse, reloadIssuerRegistry, issuer}) + verificationResponse.isFatal = false + + return verificationResponse; +} + +function checkForFatalErrors(credential: Credential) : string | null { + + try { + // eslint-disable-next-line no-new + new URL(credential.id as string); + } catch (e) { + return "The credential's id uses an invalid format. It may have been issued as part of an early pilot. Please contact the issuer to get a replacement." + } + + if (!credential.proof) { + return 'This is not a Verifiable Credential - it does not have a digital signature.' + } + + return null +} + + +// import { purposes } from '@digitalcredentials/jsonld-signatures'; +// import { VerifiablePresentation, PresentationError } from './types/presentation'; +// const presentationPurpose = new purposes.AssertionProofPurpose(); +// import { extractCredentialsFrom } from './verifiableObject'; diff --git a/src/credentialStatus.ts b/src/credentialStatus.ts new file mode 100644 index 0000000..793aa4a --- /dev/null +++ b/src/credentialStatus.ts @@ -0,0 +1,39 @@ +import { checkStatus } from '@digitalcredentials/vc-bitstring-status-list'; +import { checkStatus as checkStatusLegacy } from '@digitalcredentials/vc-status-list'; +import { Credential } from './types/credential'; + +export enum StatusPurpose { + Revocation = 'revocation', + Suspension = 'suspension' +} + +export function getCredentialStatusChecker(credential: Credential) : (() => boolean) | null { + if (!credential.credentialStatus) { + return null; + } + const credentialStatuses = Array.isArray(credential.credentialStatus) ? + credential.credentialStatus : + [credential.credentialStatus]; + const [credentialStatus] = credentialStatuses; + switch (credentialStatus.type) { + case 'BitstringStatusListEntry': + return checkStatus; + case 'StatusList2021Entry': + return checkStatusLegacy; + default: + return null; + } +} + +export function hasStatusPurpose( + credential: Credential, + statusPurpose: StatusPurpose +) : boolean { + if (!credential.credentialStatus) { + return false; + } + const credentialStatuses = Array.isArray(credential.credentialStatus) ? + credential.credentialStatus : + [credential.credentialStatus]; + return credentialStatuses.some(s => s.statusPurpose === statusPurpose); +} diff --git a/src/declarations.d.ts b/src/declarations.d.ts index d4dea51..e276bec 100644 --- a/src/declarations.d.ts +++ b/src/declarations.d.ts @@ -1 +1,11 @@ -// declare module 'jsonld' +declare module '@digitalcredentials/did-io'; +declare module '@digitalcredentials/did-method-key'; +declare module '@digitalcredentials/vc'; +declare module '@digitalcredentials/vc-bitstring-status-list'; +declare module '@digitalcredentials/vc-status-list'; +declare module '@digitalcredentials/vpqr'; +declare module '@digitalcredentials/jsonld-signatures'; +declare module '@digitalbazaar/data-integrity'; +declare module '@digitalbazaar/eddsa-rdfc-2022-cryptosuite'; +declare module '@digitalcredentials/ed25519-signature-2020'; +declare module '@digitalcredentials/ed25519-verification-key-2020'; \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index 86d30cb..9d833f2 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,4 +1,5 @@ /*! * Copyright (c) 2022 Digital Credentials Consortium. All rights reserved. */ -export { Example } from './Example' +export { verifyCredential, // verifyPresentation + } from './Verify' diff --git a/src/issuerRegistries.ts b/src/issuerRegistries.ts new file mode 100644 index 0000000..ed9a795 --- /dev/null +++ b/src/issuerRegistries.ts @@ -0,0 +1,46 @@ +import {RegistryClient} from '@digitalcredentials/issuer-registry-client'; +import {knownDidRegistries} from '../.knownDidRegistries' +import { VerificationResponse } from './Verify'; +const registries = new RegistryClient() +const registryNotYetLoaded = true; +/** + * Checks to see if a VC's issuer appears in any of the known DID registries. + * + * @returns A list of the names of the DID registries in which the issuer appears. + */ + +export async function getTrustedRegistryListForIssuer({ issuer, reloadIssuerRegistry = false }: { + issuer: string | any, + reloadIssuerRegistry: boolean | null +}): Promise { + + if (reloadIssuerRegistry ?? registryNotYetLoaded) { + await registries.load({ config: knownDidRegistries }) + } + const issuerDid = typeof issuer === 'string' ? issuer : issuer.id; + const issuerInfo = registries.didEntry(issuerDid); + // See if the issuer DID appears in any of the known registries + // If yes, assemble a list of registries in which it appears + return issuerInfo?.inRegistries + ? Array.from(issuerInfo.inRegistries).map(r => r.name) + : null; +} + +export async function addTrustedIssuersToVerificationResponse( {issuer, reloadIssuerRegistry = false, verificationResponse} :{ + issuer: string | any, + reloadIssuerRegistry: boolean | null + verificationResponse: VerificationResponse +}) : Promise + { + const foundInRegistries = await getTrustedRegistryListForIssuer( {issuer, reloadIssuerRegistry}); + + const registryStep = { + "id": "registered_issuer", + "valid": !!foundInRegistries, + ...(foundInRegistries && { foundInRegistries }) + }; + + (verificationResponse.log ??= []).push(registryStep) + +} + diff --git a/src/test-fixtures/vc.ts b/src/test-fixtures/vc.ts new file mode 100644 index 0000000..7a6bfed --- /dev/null +++ b/src/test-fixtures/vc.ts @@ -0,0 +1,253 @@ +const signedVC1Unrevoked = { + "type": [ + "VerifiableCredential", + "OpenBadgeCredential" + ], + "name": "Teamwork Badge", + "issuer": { + "type": [ + "Profile" + ], + "name": "Example Corp", + "id": "did:key:z6MknNQD1WHLGGraFi6zcbGevuAgkVfdyCdtZnQTGWVVvR5Q" + }, + "@context": [ + "https://www.w3.org/ns/credentials/v2", + "https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.3.json", + "https://w3id.org/security/suites/ed25519-2020/v1" + ], + "validFrom": "2010-01-01T00:00:00Z", + "credentialSubject": { + "type": [ + "AchievementSubject" + ], + "name": "Taylor Tuna", + "achievement": { + "id": "https://example.com/achievements/21st-century-skills/teamwork", + "type": [ + "Achievement" + ], + "name": "Masters", + "criteria": { + "narrative": "Team members are nominated for this badge by their peers and recognized upon review by Example Corp management." + }, + "description": "This badge recognizes the development of the capacity to collaborate within a group environment." + }, + "id": "did:key:z6Mktp8yHRrcEXePJGFhUDsL7X32pwfuuV4TrpaP7dZupdwg" + }, + "id": "urn:uuid:6740bee6b9c3df2a256e144e", + "credentialStatus": { + "id": "https://testing.dcconsortium.org/status/e5WK8CbZ1GjycuPombrj#4", + "type": "BitstringStatusListEntry", + "statusPurpose": "revocation", + "statusListCredential": "https://testing.dcconsortium.org/status/e5WK8CbZ1GjycuPombrj", + "statusListIndex": "4" + }, + "proof": { + "type": "Ed25519Signature2020", + "created": "2024-11-22T17:28:35Z", + "verificationMethod": "did:key:z6MknNQD1WHLGGraFi6zcbGevuAgkVfdyCdtZnQTGWVVvR5Q#z6MknNQD1WHLGGraFi6zcbGevuAgkVfdyCdtZnQTGWVVvR5Q", + "proofPurpose": "assertionMethod", + "proofValue": "z38x1N8hFFXEQgfomjv1MvP32qqtqzx4sGQAyqqfDGXqLBcw39jKBQvcwWeiVJrqtxZJmu8RZ5DPUrrAc36ejoPyE" + } +} + +const signedVC1 = { + '@context': [ + 'https://www.w3.org/2018/credentials/v1', + 'https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.2.json', + 'https://w3id.org/security/suites/ed25519-2020/v1' + ], + id: 'urn:uuid:2fe53dc9-b2ec-4939-9b2c-0d00f6663b6c', + type: ['VerifiableCredential', 'OpenBadgeCredential'], + name: 'DCC Test Credential', + issuer: { + type: ['Profile'], + id: 'did:key:z6MknNQD1WHLGGraFi6zcbGevuAgkVfdyCdtZnQTGWVVvR5Q', + name: 'Digital Credentials Consortium Test Issuer', + url: 'https://dcconsortium.org', + image: + 'https://user-images.githubusercontent.com/752326/230469660-8f80d264-eccf-4edd-8e50-ea634d407778.png' + }, + issuanceDate: '2023-08-02T17:43:32.903Z', + credentialSubject: { + type: ['AchievementSubject'], + achievement: { + id: 'urn:uuid:bd6d9316-f7ae-4073-a1e5-2f7f5bd22922', + type: ['Achievement'], + achievementType: 'Diploma', + name: 'Badge', + description: + 'This is a sample credential issued by the Digital Credentials Consortium to demonstrate the functionality of Verifiable Credentials for wallets and verifiers.', + criteria: { + type: 'Criteria', + narrative: + 'This credential was issued to a student that demonstrated proficiency in the Python programming language that occurred from **February 17, 2023** to **June 12, 2023**.' + }, + image: { + id: 'https://user-images.githubusercontent.com/752326/214947713-15826a3a-b5ac-4fba-8d4a-884b60cb7157.png', + type: 'Image' + } + }, + name: 'Jane Doe' + }, + proof: { + type: 'Ed25519Signature2020', + created: '2023-10-05T11:17:41Z', + verificationMethod: + 'did:key:z6MknNQD1WHLGGraFi6zcbGevuAgkVfdyCdtZnQTGWVVvR5Q#z6MknNQD1WHLGGraFi6zcbGevuAgkVfdyCdtZnQTGWVVvR5Q', + proofPurpose: 'assertionMethod', + proofValue: + 'z5fk6gq9upyZvcFvJdRdeL5KmvHr69jxEkyDEd2HyQdyhk9VnDEonNSmrfLAcLEDT9j4gGdCG24WHhojVHPbRsNER' + } + } + +const usignedVCv2 = { + '@context': [ + 'https://www.w3.org/ns/credentials/v2', + 'https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.3.json', + 'https://w3id.org/security/suites/ed25519-2020/v1' + ], + id: 'urn:uuid:2fe53dc9-b2ec-4939-9b2c-0d00f6663b6c', + type: ['VerifiableCredential', 'OpenBadgeCredential'], + name: 'DCC Test Credential', + issuer: { + type: ['Profile'], + id: 'did:key:z6MkhVTX9BF3NGYX6cc7jWpbNnR7cAjH8LUffabZP8Qu4ysC', + name: 'Digital Credentials Consortium Test Issuer', + url: 'https://dcconsortium.org', + image: + 'https://user-images.githubusercontent.com/752326/230469660-8f80d264-eccf-4edd-8e50-ea634d407778.png' + }, + validFrom: '2023-08-02T17:43:32.903Z', + credentialSubject: { + type: ['AchievementSubject'], + achievement: { + id: 'urn:uuid:bd6d9316-f7ae-4073-a1e5-2f7f5bd22922', + type: ['Achievement'], + achievementType: 'Diploma', + name: 'Badge', + description: + 'This is a sample credential issued by the Digital Credentials Consortium to demonstrate the functionality of Verifiable Credentials for wallets and verifiers.', + criteria: { + type: 'Criteria', + narrative: + 'This credential was issued to a student that demonstrated proficiency in the Python programming language that occurred from **February 17, 2023** to **June 12, 2023**.' + }, + image: { + id: 'https://user-images.githubusercontent.com/752326/214947713-15826a3a-b5ac-4fba-8d4a-884b60cb7157.png', + type: 'Image' + } + }, + name: 'Jane Doe' + } +} +const unsignedVC = { + '@context': [ + 'https://www.w3.org/2018/credentials/v1', + 'https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.3.json', + 'https://w3id.org/vc/status-list/2021/v1', + 'https://w3id.org/security/suites/ed25519-2020/v1' + ], + id: 'urn:uuid:951b475e-b795-43bc-ba8f-a2d01efd2eb1', + type: ['VerifiableCredential', 'OpenBadgeCredential'], + issuer: { + id: 'did:key:z6MkhVTX9BF3NGYX6cc7jWpbNnR7cAjH8LUffabZP8Qu4ysC', + type: 'Profile', + name: 'Izzy the Issuer', + description: 'Issue Issue Issue', + url: 'https://izzy.iz/', + image: { + id: 'https://upload.wikimedia.org/wikipedia/commons/a/ad/Blank_2018.png', + type: 'Image' + } + }, + issuanceDate: '2020-01-01T00:00:00Z', + name: 'Introduction to Digital Credentialing', + credentialSubject: { + type: 'AchievementSubject', + identifier: { + type: 'IdentityObject', + identityHash: 'jc.chartrand@gmail.com', + hashed: 'false' + }, + achievement: { + id: 'http://izzy.iz', + type: 'Achievement', + criteria: { + narrative: 'Completion of a credential.' + }, + description: 'Well done you!', + name: 'Introduction to Digital Credentialing' + } + } +} + +// "credentialStatus": +const credentialStatus = { + id: 'https://digitalcredentials.github.io/credential-status-jc-test/XA5AAK1PV4#16', + type: 'StatusList2021Entry', + statusPurpose: 'revocation', + statusListIndex: 16, + statusListCredential: + 'https://digitalcredentials.github.io/credential-status-jc-test/XA5AAK1PV4' +} + +const credentialStatusBitString = { + id: 'https://digitalcredentials.github.io/credential-status-jc-test/XA5AAK1PV4#16', + type: 'BitstringStatusListEntry', + statusPurpose: 'revocation', + statusListIndex: 16, + statusListCredential: + 'https://digitalcredentials.github.io/credential-status-jc-test/XA5AAK1PV4' +} + +const getUnsignedVC = (): any => JSON.parse(JSON.stringify(unsignedVC)) + +const getUnsignedVCv2 = (): any => JSON.parse(JSON.stringify(usignedVCv2)) + +const getUnsignedVCWithoutSuiteContext = (): any => { + const vcCopy = JSON.parse(JSON.stringify(unsignedVC)) + const index = vcCopy['@context'].indexOf(ed25519SuiteContext) + if (index > -1) { + vcCopy['@context'].splice(index, 1) + } + return vcCopy +} +const getCredentialStatus = (): any => JSON.parse(JSON.stringify(credentialStatus)) +const getCredentialStatusBitString = (): any => + JSON.parse(JSON.stringify(credentialStatusBitString)) + +const getUnsignedVCWithStatus = (): any => { + const unsignedVCWithStatus = getUnsignedVC() + unsignedVCWithStatus.credentialStatus = getCredentialStatus() + return unsignedVCWithStatus +} + +const getUnsignedVC2WithStatus = (): any => { + const unsignedVC2WithStatus = getUnsignedVCv2() + unsignedVC2WithStatus.credentialStatus = getCredentialStatusBitString() + return unsignedVC2WithStatus +} + +const ed25519SuiteContext = + 'https://w3id.org/security/suites/ed25519-2020/v1' + +const getSignedVC = (): any => { + return signedVC1 +} + +const getSignedUnrevokedVC2 = (): any => { + return signedVC1Unrevoked +} +export { + getSignedUnrevokedVC2, + getSignedVC, + getUnsignedVC, + getUnsignedVCWithoutSuiteContext, + getCredentialStatus, + getCredentialStatusBitString, + getUnsignedVCWithStatus, + getUnsignedVC2WithStatus, + ed25519SuiteContext +} diff --git a/test/Example.spec.ts b/test/Example.spec.ts deleted file mode 100644 index 3bf5e63..0000000 --- a/test/Example.spec.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { expect } from 'chai' -import { Example } from '../src' - -describe('Example', () => { - it('calls function', async () => { - const ex = new Example() - expect(ex.hello()).to.equal('world') - }) -}) diff --git a/test/Verify.spec.ts b/test/Verify.spec.ts new file mode 100644 index 0000000..542765e --- /dev/null +++ b/test/Verify.spec.ts @@ -0,0 +1,16 @@ +//import { expect } from 'chai' +import { strict as assert } from 'assert'; +import { verifyCredential } from '../src/Verify' +import { getSignedUnrevokedVC2 } from '../src/test-fixtures/vc' + +describe('Verify', () => { + it('calls function', async () => { + //const signedVC : any = getSignedVC() + const signedVC2Unrevoked : any = getSignedUnrevokedVC2() + const result = await verifyCredential({credential: signedVC2Unrevoked, reloadIssuerRegistry: true}) + console.log("result returned from verifyCredential call:") + console.log(JSON.stringify(result,null,2)) + assert.ok(result.verified); + //expect(result.verified).to.be.true + }) +})