@bedrock/vc-verifier 22.0.0 → 22.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/config.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Copyright (c) 2019-2024 Digital Bazaar, Inc. All rights reserved.
2
+ * Copyright (c) 2019-2025 Digital Bazaar, Inc. All rights reserved.
3
3
  */
4
4
  import {config} from '@bedrock/core';
5
5
  import '@bedrock/app-identity';
@@ -35,7 +35,8 @@ cfg.supportedSuites = [
35
35
  'eddsa-rdfc-2022',
36
36
  'ecdsa-jcs-2019',
37
37
  'eddsa-jcs-2022',
38
- 'ecdsa-sd-2023'
38
+ 'ecdsa-sd-2023',
39
+ 'ecdsa-xi-2023'
39
40
  ];
40
41
 
41
42
  cfg.routes = {
package/lib/di.js CHANGED
@@ -1,14 +1,16 @@
1
1
  /*!
2
- * Copyright (c) 2018-2024 Digital Bazaar, Inc. All rights reserved.
2
+ * Copyright (c) 2018-2025 Digital Bazaar, Inc. All rights reserved.
3
3
  */
4
4
  import * as vc from '@digitalbazaar/vc';
5
5
  import {checkStatus as _checkStatus} from './status.js';
6
6
  import {createDocumentLoader} from './documentLoader.js';
7
7
  import {createSuites} from './suites.js';
8
8
 
9
- export async function verifyCredential({config, credential, checks} = {}) {
9
+ export async function verifyCredential({
10
+ config, credential, options, checks
11
+ } = {}) {
10
12
  const documentLoader = await createDocumentLoader({config});
11
- const suite = createSuites();
13
+ const suite = createSuites({options});
12
14
 
13
15
  // only check credential status when option is set
14
16
  const checkStatus = checks.includes('credentialStatus') ?
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Copyright (c) 2019-2024 Digital Bazaar, Inc. All rights reserved.
2
+ * Copyright (c) 2019-2025 Digital Bazaar, Inc. All rights reserved.
3
3
  */
4
4
  import * as bedrock from '@bedrock/core';
5
5
  import {
@@ -9,13 +9,13 @@ import {
9
9
  } from '@bedrock/jsonld-document-loader';
10
10
  import {createContextDocumentLoader} from '@bedrock/service-context-store';
11
11
  import {didIo} from '@bedrock/did-io';
12
- import {klona} from 'klona';
13
12
  import '@bedrock/credentials-context';
14
13
  import '@bedrock/data-integrity-context';
15
14
  import '@bedrock/did-context';
16
15
  import '@bedrock/did-io';
17
16
  import '@bedrock/multikey-context';
18
17
  import '@bedrock/security-context';
18
+ import '@bedrock/vc-barcodes-context';
19
19
  import '@bedrock/vc-revocation-list-context';
20
20
  import '@bedrock/vc-status-list-context';
21
21
  import '@bedrock/veres-one-context';
@@ -151,7 +151,7 @@ function _getNode({didDocument, id}) {
151
151
  }
152
152
 
153
153
  return {
154
- '@context': klona(didDocument['@context']),
155
- ...klona(match)
154
+ '@context': structuredClone(didDocument['@context']),
155
+ ...structuredClone(match)
156
156
  };
157
157
  }
package/lib/envelopes.js CHANGED
@@ -1,30 +1,55 @@
1
1
  /*
2
- * Copyright (c) 2019-2024 Digital Bazaar, Inc. All rights reserved.
2
+ * Copyright (c) 2019-2025 Digital Bazaar, Inc. All rights reserved.
3
3
  */
4
4
  import * as bedrock from '@bedrock/core';
5
+ import * as vcb from './vcb.js';
5
6
  import * as vcjwt from './vcjwt.js';
6
7
 
7
8
  const {util: {BedrockError}} = bedrock;
8
9
 
9
- export async function verifyEnvelopedCredential({envelopedCredential} = {}) {
10
+ export async function verifyEnvelopedCredential({
11
+ config, envelopedCredential, checks
12
+ } = {}) {
13
+ let format;
10
14
  try {
11
- const {contents: jwt} = _parseEnvelope({
12
- envelope: envelopedCredential
13
- });
14
- return vcjwt.verifyEnvelopedCredential({jwt});
15
+ const parseResult = _parseEnvelope({envelope: envelopedCredential});
16
+ const {contents} = parseResult;
17
+ format = parseResult.format;
18
+
19
+ let result;
20
+ if(format.typeAndSubType === 'application/jwt') {
21
+ result = await vcjwt.verifyEnvelopedCredential({jwt: contents});
22
+ } else if(format.typeAndSubType === 'application/vcb') {
23
+ result = await vcb.verifyEnvelopedCredential({
24
+ config, contents, format, checks
25
+ });
26
+ } else {
27
+ _throwUnknownFormat(format);
28
+ }
29
+ return {...result, format};
15
30
  } catch(error) {
16
- return {verified: false, error};
31
+ return {verified: false, error, format};
17
32
  }
18
33
  }
19
34
 
20
35
  export async function verifyEnvelopedPresentation({
21
36
  envelopedPresentation, challenge, domain
22
37
  } = {}) {
38
+ let format;
23
39
  try {
24
- const {contents: jwt} = _parseEnvelope({
25
- envelope: envelopedPresentation
26
- });
27
- return vcjwt.verifyEnvelopedPresentation({jwt, challenge, domain});
40
+ const parseResult = _parseEnvelope({envelope: envelopedPresentation});
41
+ const {contents} = parseResult;
42
+ format = parseResult.format;
43
+
44
+ let result;
45
+ if(format.typeAndSubType === 'application/jwt') {
46
+ result = await vcjwt.verifyEnvelopedPresentation({
47
+ jwt: contents, challenge, domain
48
+ });
49
+ } else {
50
+ _throwUnknownFormat(format);
51
+ }
52
+ return {...result, format};
28
53
  } catch(error) {
29
54
  return {verified: false, error};
30
55
  }
@@ -32,20 +57,28 @@ export async function verifyEnvelopedPresentation({
32
57
 
33
58
  function _parseEnvelope({envelope}) {
34
59
  const {id} = envelope;
35
- let format;
60
+ const format = {};
36
61
  const comma = id.indexOf(',');
37
62
  if(id.startsWith('data:') && comma !== -1) {
38
- format = id.slice('data:'.length, comma);
39
- }
40
- if(format !== 'application/jwt') {
41
- throw new BedrockError(
42
- `Unknown envelope format "${format}".`, {
43
- name: 'DataError',
44
- details: {
45
- httpStatusCode: 400,
46
- public: true
47
- },
48
- });
63
+ const mediaType = id.slice('data:'.length, comma);
64
+ const parts = mediaType.split(';');
65
+ format.mediaType = mediaType;
66
+ format.typeAndSubType = parts.shift();
67
+ const [type, subType] = format.typeAndSubType.split('/');
68
+ format.type = type;
69
+ format.subType = subType;
70
+ format.parameters = new Map(parts.map(s => s.trim().split('=')));
49
71
  }
50
72
  return {contents: id.slice(comma + 1), format};
51
73
  }
74
+
75
+ function _throwUnknownFormat(format) {
76
+ throw new BedrockError(
77
+ `Unknown envelope format "${format.mediaType}".`, {
78
+ name: 'DataError',
79
+ details: {
80
+ httpStatusCode: 400,
81
+ public: true
82
+ },
83
+ });
84
+ }
package/lib/index.js CHANGED
@@ -1,14 +1,13 @@
1
1
  /*!
2
- * Copyright (c) 2021-2024 Digital Bazaar, Inc. All rights reserved.
2
+ * Copyright (c) 2021-2025 Digital Bazaar, Inc. All rights reserved.
3
3
  */
4
4
  import * as bedrock from '@bedrock/core';
5
- import {createService, schemas} from '@bedrock/service-core';
6
5
  import {
7
- addRoutes as addContextStoreRoutes
6
+ addCborldRoutes, addContextRoutes
8
7
  } from '@bedrock/service-context-store';
8
+ import {createService, schemas} from '@bedrock/service-core';
9
9
  import {addRoutes} from './http.js';
10
10
  import {initializeServiceAgent} from '@bedrock/service-agent';
11
- import {klona} from 'klona';
12
11
  import {verifyOptions} from '../schemas/bedrock-vc-verifier.js';
13
12
 
14
13
  // load config defaults
@@ -18,8 +17,8 @@ const serviceType = 'vc-verifier';
18
17
 
19
18
  bedrock.events.on('bedrock.init', async () => {
20
19
  // add customizations to config validators...
21
- const createConfigBody = klona(schemas.createConfigBody);
22
- const updateConfigBody = klona(schemas.updateConfigBody);
20
+ const createConfigBody = structuredClone(schemas.createConfigBody);
21
+ const updateConfigBody = structuredClone(schemas.updateConfigBody);
23
22
  const schemasToUpdate = [createConfigBody, updateConfigBody];
24
23
  for(const schema of schemasToUpdate) {
25
24
  // verify options
@@ -52,7 +51,8 @@ bedrock.events.on('bedrock.init', async () => {
52
51
  });
53
52
 
54
53
  bedrock.events.on('bedrock-express.configure.routes', async app => {
55
- await addContextStoreRoutes({app, service});
54
+ await addCborldRoutes({app, service});
55
+ await addContextRoutes({app, service});
56
56
  await addRoutes({app, service});
57
57
  });
58
58
 
package/lib/suites.js CHANGED
@@ -11,6 +11,9 @@ import {
11
11
  import {
12
12
  createVerifyCryptosuite as createEcdsaSd2023VerifyCryptosuite
13
13
  } from '@digitalbazaar/ecdsa-sd-2023-cryptosuite';
14
+ import {
15
+ createCryptosuite as createEcdsaXi2023Cryptosuite
16
+ } from '@digitalbazaar/ecdsa-xi-2023-cryptosuite';
14
17
  import {
15
18
  createVerifyCryptosuite as createEddsaJcs2022VerifyCryptoSuite
16
19
  } from '@digitalbazaar/eddsa-jcs-2022-cryptosuite';
@@ -32,12 +35,13 @@ import {
32
35
 
33
36
  // DataIntegrityProof should work for multiple cryptosuites
34
37
  const SUPPORTED_CRYPTOSUITES = new Map([
35
- ['bbs-2023', createBbs2023VerifyCryptosuite()],
36
- ['ecdsa-rdfc-2019', ecdsaRdfc2019CryptoSuite],
37
- ['eddsa-rdfc-2022', eddsaRdfc2022CryptoSuite],
38
- ['ecdsa-jcs-2019', createEcdsaJcs2019VerifyCryptoSuite()],
39
- ['eddsa-jcs-2022', createEddsaJcs2022VerifyCryptoSuite()],
40
- ['ecdsa-sd-2023', createEcdsaSd2023VerifyCryptosuite()]
38
+ ['bbs-2023', () => createBbs2023VerifyCryptosuite()],
39
+ ['ecdsa-rdfc-2019', () => ecdsaRdfc2019CryptoSuite],
40
+ ['eddsa-rdfc-2022', () => eddsaRdfc2022CryptoSuite],
41
+ ['ecdsa-jcs-2019', () => createEcdsaJcs2019VerifyCryptoSuite()],
42
+ ['eddsa-jcs-2022', () => createEddsaJcs2022VerifyCryptoSuite()],
43
+ ['ecdsa-sd-2023', () => createEcdsaSd2023VerifyCryptosuite()],
44
+ ['ecdsa-xi-2023', options => createEcdsaXi2023Cryptosuite(options)]
41
45
  ]);
42
46
 
43
47
  const SUPPORTED_LEGACY_CRYPTOSUITES = new Map([
@@ -50,10 +54,15 @@ const SUPPORTED_LEGACY_SUITES = new Map([
50
54
  ['Ed25519Signature2020', Ed25519Signature2020]
51
55
  ]);
52
56
 
53
- export function createSuites() {
57
+ export function createSuites({options} = {}) {
54
58
  const cfg = bedrock.config['vc-verifier'];
55
59
  const {supportedSuites} = cfg;
56
60
  const suite = supportedSuites.map(supportedSuite => {
61
+ const createCryptosuite = SUPPORTED_CRYPTOSUITES.get(supportedSuite);
62
+ if(createCryptosuite) {
63
+ const cryptosuite = createCryptosuite(options);
64
+ return new DataIntegrityProof({cryptosuite});
65
+ }
57
66
  const LegacySuite = SUPPORTED_LEGACY_SUITES.get(supportedSuite);
58
67
  if(LegacySuite) {
59
68
  return new LegacySuite();
@@ -64,10 +73,6 @@ export function createSuites() {
64
73
  cryptosuite: LegacyCryptosuite, legacyContext: true
65
74
  });
66
75
  }
67
- const cryptosuite = SUPPORTED_CRYPTOSUITES.get(supportedSuite);
68
- if(cryptosuite) {
69
- return new DataIntegrityProof({cryptosuite});
70
- }
71
76
  throw new Error(`Unsupported suite ${supportedSuite}`);
72
77
  });
73
78
  return suite;
package/lib/vcb.js ADDED
@@ -0,0 +1,172 @@
1
+ /*
2
+ * Copyright (c) 2024-2025 Digital Bazaar, Inc. All rights reserved.
3
+ */
4
+ import * as bedrock from '@bedrock/core';
5
+ import * as cborld from '@digitalbazaar/cborld';
6
+ import * as di from './di.js';
7
+ import {aamva} from '@digitalbazaar/pdf417-dl-canonicalizer';
8
+ import {createCborldTypeTableLoader} from '@bedrock/service-context-store';
9
+ import {createDocumentLoader} from './documentLoader.js';
10
+ import {util} from '@digitalbazaar/vpqr';
11
+
12
+ const {util: {BedrockError}} = bedrock;
13
+
14
+ const VC_CONTEXT_2 = 'https://www.w3.org/ns/credentials/v2';
15
+ const VCB_CONTEXT_1 = 'https://w3id.org/vc-barcodes/v1';
16
+
17
+ // map of AAMVA issuer identification number to VCB location
18
+ const AAMVA_IIN_TO_VCB_LOCATION = new Map([
19
+ // VCB spec, i.e., test vector intentionally invalid issuer
20
+ ['000000', {subfile: 'ZZ', field: 'ZZA', encoding: 'base64url'}],
21
+ // US state of CA
22
+ ['636014', {subfile: 'ZC', field: 'ZCE', encoding: 'base64'}],
23
+ ]);
24
+
25
+ const SUPPORTED_BARCODE_FORMATS = new Set([
26
+ 'qr_code',
27
+ 'pdf417'
28
+ ]);
29
+
30
+ export async function verifyEnvelopedCredential({
31
+ config, contents, format, checks
32
+ } = {}) {
33
+ // handle base64 encoding
34
+ let {parameters} = format;
35
+ if(parameters.has('base64')) {
36
+ contents = new Uint8Array(Buffer.from(contents, 'base64'));
37
+ parameters = new Map(parameters);
38
+ parameters.delete('base64');
39
+ }
40
+
41
+ // only parameter understood is `barcode-format` with values of:
42
+ // 'qr_code' (default) or 'pdf417'
43
+ const barcodeFormat = parameters.size === 1 ?
44
+ parameters.get('barcode-format') : (parameters.size === 0 && 'qr_code');
45
+ if(!SUPPORTED_BARCODE_FORMATS.has(barcodeFormat)) {
46
+ _throwUnknownFormat(format);
47
+ }
48
+
49
+ // create loaders for JSON-LD contexts and CBOR-LD type tables
50
+ const documentLoader = await createDocumentLoader({config});
51
+ const typeTableLoader = await createCborldTypeTableLoader({
52
+ config, serviceType: 'vc-verifier'
53
+ });
54
+
55
+ // parse credential and any verification options from contents...
56
+ let credential;
57
+ let options;
58
+ if(barcodeFormat === 'qr_code') {
59
+ ({credential, options} = await _parseQrCodeEnvelope({
60
+ contents, documentLoader, typeTableLoader
61
+ }));
62
+ }
63
+ if(barcodeFormat === 'pdf417') {
64
+ ({credential, options} = await _parsePdf417Envelope({
65
+ contents, documentLoader, typeTableLoader
66
+ }));
67
+ }
68
+
69
+ // verify VC
70
+ const result = await di.verifyCredential({
71
+ config, credential, options, checks
72
+ });
73
+ return {...result, credential};
74
+ }
75
+
76
+ async function _parseQrCodeEnvelope({
77
+ contents, documentLoader, typeTableLoader
78
+ }) {
79
+ const {jsonldDocument: credential} = await util.fromQrCode({
80
+ text: contents,
81
+ documentLoader,
82
+ typeTableLoader,
83
+ expectedHeader: 'VC1-'
84
+ });
85
+ return {credential};
86
+ }
87
+
88
+ async function _parsePdf417Envelope({
89
+ contents, documentLoader, typeTableLoader
90
+ }) {
91
+ // parse AAMVA object from scanned PDF417 data; if contents are a string,
92
+ // presume UTF-8 encoding
93
+ const object = aamva.decode({data: contents, encoding: 'utf8'});
94
+
95
+ // find VCB in AAMVA object
96
+ const credential = await findVcb({object, documentLoader, typeTableLoader});
97
+ const componentIndex = credential.credentialSubject?.protectedComponentIndex;
98
+
99
+ // select AAMVA DL or ID document
100
+ const document = await aamva.select({
101
+ object,
102
+ selector: {
103
+ subfile: ['DL', 'ID'],
104
+ componentIndex
105
+ }
106
+ });
107
+ // hash document and store it as `extraInformation` for verification
108
+ const options = {
109
+ extraInformation: await aamva.hash({document})
110
+ };
111
+
112
+ return {credential, options};
113
+ }
114
+
115
+ async function findVcb({object, documentLoader, typeTableLoader}) {
116
+ const {issuerIdentificationNumber} = object;
117
+ const location = AAMVA_IIN_TO_VCB_LOCATION.get(issuerIdentificationNumber);
118
+ if(!location) {
119
+ throw new BedrockError(
120
+ 'Unknown envelope format; verifiable credential barcode not found.', {
121
+ name: 'DataError',
122
+ details: {httpStatusCode: 400, public: true}
123
+ });
124
+ }
125
+
126
+ const selection = await aamva.select({
127
+ object,
128
+ selector: {
129
+ subfile: [location.subfile],
130
+ fields: [location.field]
131
+ }
132
+ });
133
+
134
+ const encoded = selection.get(location.field);
135
+ if(!encoded) {
136
+ throw new BedrockError('Verifiable credential barcode not found.', {
137
+ name: 'DataError',
138
+ details: {httpStatusCode: 400, public: true}
139
+ });
140
+ }
141
+
142
+ const cborldBytes = new Uint8Array(Buffer.from(encoded, location.encoding));
143
+
144
+ // decode CBOR-LD bytes into JSON-LD VCB
145
+ const credential = await cborld.decode({
146
+ cborldBytes,
147
+ documentLoader,
148
+ typeTableLoader
149
+ });
150
+ const contexts = credential['@context'];
151
+ if(!Array.isArray(contexts) &&
152
+ contexts[0] === VC_CONTEXT_2 &&
153
+ contexts.includes(VCB_CONTEXT_1)) {
154
+ throw new BedrockError('Verifiable credential barcode not found.', {
155
+ name: 'DataError',
156
+ details: {httpStatusCode: 400, public: true}
157
+ });
158
+ }
159
+
160
+ return credential;
161
+ }
162
+
163
+ function _throwUnknownFormat(format) {
164
+ throw new BedrockError(
165
+ `Unknown envelope format "${format.mediaType}".`, {
166
+ name: 'DataError',
167
+ details: {
168
+ httpStatusCode: 400,
169
+ public: true
170
+ },
171
+ });
172
+ }
package/lib/verify.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Copyright (c) 2018-2024 Digital Bazaar, Inc. All rights reserved.
2
+ * Copyright (c) 2018-2025 Digital Bazaar, Inc. All rights reserved.
3
3
  */
4
4
  import * as di from './di.js';
5
5
  import {
@@ -12,11 +12,14 @@ export async function verifyCredential({config, credential, checks} = {}) {
12
12
  }
13
13
 
14
14
  const result = await verifyEnvelopedCredential({
15
- envelopedCredential: credential, checks
15
+ config, envelopedCredential: credential, checks
16
16
  });
17
- // if the credential has a `proof` field, do DI verification
17
+
18
+ // if credential envelope is verified, credential has a `proof` field, and
19
+ // format is JWT, do DI verification
18
20
  let {verified} = result;
19
- if(verified && result.credential.proof) {
21
+ if(verified && result.credential.proof &&
22
+ result.format.typeAndSubType === 'application/jwt') {
20
23
  const proofResult = await di.verifyCredential({
21
24
  config, credential: result.credential, checks
22
25
  });
@@ -74,8 +77,10 @@ export async function verifyPresentation({
74
77
  let credentialResults;
75
78
  if(!verified) {
76
79
  credentialResults = [];
77
- } else if(presentationResult.presentation?.proof) {
78
- // presentation in the envelope has a `proof`, so recurse to check it
80
+ } else if(presentationResult.presentation?.proof &&
81
+ presentationResult.format.typeAndSubType === 'application/jwt') {
82
+ // presentation in the envelope has a `proof` and envelope format is JWT,
83
+ // so recurse to check `proof` field
79
84
  const proofResult = await verifyPresentation({
80
85
  config, presentation: presentationResult.presentation,
81
86
  challenge, domain, checks
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bedrock/vc-verifier",
3
- "version": "22.0.0",
3
+ "version": "22.1.0",
4
4
  "type": "module",
5
5
  "description": "Bedrock VC Verifier",
6
6
  "main": "./lib/index.js",
@@ -26,28 +26,31 @@
26
26
  "homepage": "https://github.com/digitalbazaar/bedrock-vc-verifier",
27
27
  "dependencies": {
28
28
  "@digitalbazaar/bbs-2023-cryptosuite": "^2.0.1",
29
+ "@digitalbazaar/cborld": "^7.2.0",
29
30
  "@digitalbazaar/data-integrity": "^2.5.0",
30
31
  "@digitalbazaar/ecdsa-2019-cryptosuite": "^2.0.0",
31
32
  "@digitalbazaar/ecdsa-jcs-2019-cryptosuite": "^1.0.0",
32
33
  "@digitalbazaar/ecdsa-multikey": "^1.8.0",
33
34
  "@digitalbazaar/ecdsa-rdfc-2019-cryptosuite": "^1.2.0",
34
35
  "@digitalbazaar/ecdsa-sd-2023-cryptosuite": "^3.4.1",
36
+ "@digitalbazaar/ecdsa-xi-2023-cryptosuite": "^1.1.0",
35
37
  "@digitalbazaar/ed25519-multikey": "^1.3.1",
36
38
  "@digitalbazaar/ed25519-signature-2018": "^4.1.0",
37
39
  "@digitalbazaar/ed25519-signature-2020": "^5.4.0",
38
40
  "@digitalbazaar/eddsa-2022-cryptosuite": "^1.0.0",
39
41
  "@digitalbazaar/eddsa-jcs-2022-cryptosuite": "^1.0.0",
40
42
  "@digitalbazaar/eddsa-rdfc-2022-cryptosuite": "^1.2.0",
43
+ "@digitalbazaar/pdf417-dl-canonicalizer": "^1.2.1",
41
44
  "@digitalbazaar/vc": "^7.1.2",
42
45
  "@digitalbazaar/vc-bitstring-status-list": "^2.0.1",
43
46
  "@digitalbazaar/vc-revocation-list": "^7.0.0",
44
47
  "@digitalbazaar/vc-status-list": "^8.0.1",
48
+ "@digitalbazaar/vpqr": "^5.1.0",
45
49
  "assert-plus": "^1.0.0",
46
50
  "bnid": "^3.0.0",
47
51
  "body-parser": "^1.20.3",
48
52
  "cors": "^2.8.5",
49
53
  "jose": "^6.0.10",
50
- "klona": "^2.0.6",
51
54
  "serialize-error": "^12.0.0"
52
55
  },
53
56
  "peerDependencies": {
@@ -64,9 +67,10 @@
64
67
  "@bedrock/multikey-context": "^3.0.0",
65
68
  "@bedrock/security-context": "^9.0.0",
66
69
  "@bedrock/service-agent": "^10.0.0",
67
- "@bedrock/service-context-store": "^13.0.0",
70
+ "@bedrock/service-context-store": "^13.1.0",
68
71
  "@bedrock/service-core": "^11.0.0",
69
72
  "@bedrock/validation": "^7.1.1",
73
+ "@bedrock/vc-barcodes-context": "^1.0.0",
70
74
  "@bedrock/vc-revocation-list-context": "^5.0.0",
71
75
  "@bedrock/vc-status-list-context": "^6.0.3",
72
76
  "@bedrock/veres-one-context": "^16.0.0"