@bedrock/vc-delivery 7.1.0 → 7.2.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/helpers.js CHANGED
@@ -188,6 +188,36 @@ export function deepEqual(obj1, obj2) {
188
188
  return true;
189
189
  }
190
190
 
191
+ export function createVerifyOptions({
192
+ verifyPresentationOptions,
193
+ expectedChallenge,
194
+ verifiablePresentationRequest,
195
+ presentation,
196
+ domain,
197
+ checks
198
+ }) {
199
+ // start with `verifyPresentationOptions`, then overwrite as needed
200
+ const options = {...verifyPresentationOptions};
201
+
202
+ // update `checks` with anything additional from `verifyPresentationOptions`
203
+ const checkSet = new Set(checks);
204
+ if(verifyPresentationOptions.checks) {
205
+ Object.entries(verifyPresentationOptions.checks)
206
+ .forEach(([check, enabled]) => enabled && checkSet.add(check));
207
+ }
208
+ options.checks = [...checkSet];
209
+
210
+ // update `challenge`
211
+ options.challenge = expectedChallenge ??
212
+ verifiablePresentationRequest.challenge ??
213
+ presentation?.proof?.challenge;
214
+
215
+ // update `domain`
216
+ options.domain = domain;
217
+
218
+ return options;
219
+ }
220
+
191
221
  export function stripStacktrace(error) {
192
222
  // serialize error and allow-list specific properties
193
223
  const serialized = serializeError(error);
package/lib/index.js CHANGED
@@ -1,12 +1,11 @@
1
1
  /*!
2
- * Copyright (c) 2022-2024 Digital Bazaar, Inc. All rights reserved.
2
+ * Copyright (c) 2022-2025 Digital Bazaar, Inc. All rights reserved.
3
3
  */
4
4
  import * as bedrock from '@bedrock/core';
5
5
  import * as workflowSchemas from '../schemas/bedrock-vc-workflow.js';
6
6
  import {createService, schemas} from '@bedrock/service-core';
7
7
  import {addRoutes} from './http.js';
8
8
  import {initializeServiceAgent} from '@bedrock/service-agent';
9
- import {klona} from 'klona';
10
9
  import {MAX_ISSUER_INSTANCES} from './constants.js';
11
10
  import {parseLocalId} from './helpers.js';
12
11
  import '@bedrock/express';
@@ -24,8 +23,8 @@ bedrock.events.on('bedrock.init', async () => {
24
23
 
25
24
  async function _initService({serviceType, routePrefix}) {
26
25
  // add customizations to config validators...
27
- const createConfigBody = klona(schemas.createConfigBody);
28
- const updateConfigBody = klona(schemas.updateConfigBody);
26
+ const createConfigBody = structuredClone(schemas.createConfigBody);
27
+ const updateConfigBody = structuredClone(schemas.updateConfigBody);
29
28
  const schemasToUpdate = [createConfigBody, updateConfigBody];
30
29
  const {
31
30
  credentialTemplates, steps, initialStep, issuerInstances
@@ -37,7 +36,7 @@ async function _initService({serviceType, routePrefix}) {
37
36
  schema.properties.initialStep = initialStep;
38
37
  schema.properties.issuerInstances = issuerInstances;
39
38
  // allow zcaps by custom reference ID
40
- schema.properties.zcaps = klona(schemas.zcaps);
39
+ schema.properties.zcaps = structuredClone(schemas.zcaps);
41
40
  // max of 4 basic zcaps + max issuer instances
42
41
  schema.properties.zcaps.maxProperties = 4 + MAX_ISSUER_INSTANCES;
43
42
  schema.properties.zcaps.additionalProperties = schemas.delegatedZcap;
@@ -12,7 +12,6 @@ import {
12
12
  verifiablePresentation as verifiablePresentationSchema
13
13
  } from '../../schemas/bedrock-vc-workflow.js';
14
14
  import {compile} from '@bedrock/validation';
15
- import {klona} from 'klona';
16
15
  import {logger} from '../logger.js';
17
16
  import {oid4vp} from '@digitalbazaar/oid4-client';
18
17
  import {verify} from '../verify.js';
@@ -103,7 +102,8 @@ export async function getAuthorizationRequest({req}) {
103
102
  authorizationRequest.client_id_scheme = 'redirect_uri';
104
103
  }
105
104
  if(client_metadata) {
106
- authorizationRequest.client_metadata = klona(client_metadata);
105
+ authorizationRequest.client_metadata = structuredClone(
106
+ client_metadata);
107
107
  } else if(client_metadata_uri) {
108
108
  authorizationRequest.client_metadata_uri = client_metadata_uri;
109
109
  } else {
@@ -193,9 +193,15 @@ export async function processAuthorizationResponse({req}) {
193
193
  // verify the received VP
194
194
  const {verifiablePresentationRequest} = await oid4vp.toVpr(
195
195
  {authorizationRequest});
196
- const {allowUnprotectedPresentation = false} = step;
196
+ const {
197
+ allowUnprotectedPresentation = false,
198
+ verifyPresentationOptions = {},
199
+ verifyPresentationResultSchema
200
+ } = step;
197
201
  const verifyResult = await verify({
198
202
  workflow,
203
+ verifyPresentationOptions,
204
+ verifyPresentationResultSchema,
199
205
  verifiablePresentationRequest,
200
206
  presentation,
201
207
  allowUnprotectedPresentation,
package/lib/vcapi.js CHANGED
@@ -11,7 +11,6 @@ import {
11
11
  import {exportJWK, generateKeyPair, importJWK} from 'jose';
12
12
  import {compile} from '@bedrock/validation';
13
13
  import {issue} from './issue.js';
14
- import {klona} from 'klona';
15
14
  import {logger} from './logger.js';
16
15
 
17
16
  const {util: {BedrockError}} = bedrock;
@@ -141,7 +140,7 @@ export async function processExchange({req, res, workflow, exchangeRecord}) {
141
140
 
142
141
  // if no presentation was received in the body...
143
142
  if(!receivedPresentation) {
144
- const verifiablePresentationRequest = klona(
143
+ const verifiablePresentationRequest = structuredClone(
145
144
  step.verifiablePresentationRequest);
146
145
  if(createChallenge) {
147
146
  /* Note: When creating a challenge, the initial step always
@@ -194,9 +193,15 @@ export async function processExchange({req, res, workflow, exchangeRecord}) {
194
193
 
195
194
  // verify the received VP
196
195
  const expectedChallenge = isInitialStep ? exchange.id : undefined;
197
- const {allowUnprotectedPresentation = false} = step;
196
+ const {
197
+ allowUnprotectedPresentation = false,
198
+ verifyPresentationOptions = {},
199
+ verifyPresentationResultSchema
200
+ } = step;
198
201
  const verifyResult = await verify({
199
202
  workflow,
203
+ verifyPresentationOptions,
204
+ verifyPresentationResultSchema,
200
205
  verifiablePresentationRequest: step.verifiablePresentationRequest,
201
206
  presentation: receivedPresentation,
202
207
  allowUnprotectedPresentation,
package/lib/verify.js CHANGED
@@ -4,8 +4,13 @@
4
4
  import * as bedrock from '@bedrock/core';
5
5
  import * as EcdsaMultikey from '@digitalbazaar/ecdsa-multikey';
6
6
  import * as Ed25519Multikey from '@digitalbazaar/ed25519-multikey';
7
- import {getZcapClient, stripStacktrace} from './helpers.js';
7
+ import {
8
+ createVerifyOptions,
9
+ getZcapClient,
10
+ stripStacktrace
11
+ } from './helpers.js';
8
12
  import {importJWK, jwtVerify} from 'jose';
13
+ import {compile} from '@bedrock/validation';
9
14
  import {didIo} from '@bedrock/did-io';
10
15
 
11
16
  const {util: {BedrockError}} = bedrock;
@@ -25,8 +30,9 @@ export async function createChallenge({workflow} = {}) {
25
30
  }
26
31
 
27
32
  export async function verify({
28
- workflow, verifiablePresentationRequest, presentation,
29
- allowUnprotectedPresentation = false, expectedChallenge
33
+ workflow, verifyPresentationOptions, verifiablePresentationRequest,
34
+ presentation, allowUnprotectedPresentation = false, expectedChallenge,
35
+ verifyPresentationResultSchema
30
36
  } = {}) {
31
37
  // create zcap client for verifying
32
38
  const {zcapClient, zcaps} = await getZcapClient({workflow});
@@ -46,17 +52,18 @@ export async function verify({
46
52
  new URL(workflow.id).origin;
47
53
  let result;
48
54
  try {
55
+ const options = createVerifyOptions({
56
+ verifyPresentationOptions,
57
+ expectedChallenge,
58
+ verifiablePresentationRequest,
59
+ presentation,
60
+ domain,
61
+ checks
62
+ });
49
63
  result = await zcapClient.write({
50
64
  capability,
51
65
  json: {
52
- options: {
53
- // FIXME: support multi-proof presentations?
54
- challenge: expectedChallenge ??
55
- verifiablePresentationRequest.challenge ??
56
- presentation?.proof?.challenge,
57
- domain,
58
- checks
59
- },
66
+ options,
60
67
  verifiablePresentation: presentation
61
68
  }
62
69
  });
@@ -120,7 +127,15 @@ export async function verify({
120
127
  const verificationMethod = presentationResult?.results[0]
121
128
  .verificationMethod ?? null;
122
129
 
123
- // FIXME: ensure VP satisfies VPR
130
+ // validate against the verify presentation result schema, if applicable
131
+ if(verifyPresentationResultSchema) {
132
+ const {jsonSchema: schema} = verifyPresentationResultSchema;
133
+ const validate = compile({schema});
134
+ const {valid, error} = validate(result.data);
135
+ if(!valid) {
136
+ throw error;
137
+ }
138
+ }
124
139
 
125
140
  return {
126
141
  verified,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bedrock/vc-delivery",
3
- "version": "7.1.0",
3
+ "version": "7.2.0",
4
4
  "type": "module",
5
5
  "description": "Bedrock Verifiable Credential Delivery",
6
6
  "main": "./lib/index.js",
@@ -47,7 +47,6 @@
47
47
  "cors": "^2.8.5",
48
48
  "jose": "^5.10.0",
49
49
  "jsonata": "^2.0.6",
50
- "klona": "^2.0.6",
51
50
  "serialize-error": "^12.0.0"
52
51
  },
53
52
  "peerDependencies": {
@@ -72,6 +71,6 @@
72
71
  "eslint-plugin-unicorn": "^56.0.1"
73
72
  },
74
73
  "engines": {
75
- "node": ">=18"
74
+ "node": ">=20"
76
75
  }
77
76
  }
@@ -486,6 +486,28 @@ const step = {
486
486
  stepTemplate: typedTemplate,
487
487
  verifiablePresentationRequest: {
488
488
  type: 'object'
489
+ },
490
+ verifyPresentationOptions: {
491
+ type: 'object',
492
+ properties: {
493
+ checks: {
494
+ type: 'object'
495
+ }
496
+ },
497
+ additionalProperties: true
498
+ },
499
+ verifyPresentationResultSchema: {
500
+ type: 'object',
501
+ required: ['type', 'jsonSchema'],
502
+ additionalProperties: false,
503
+ properties: {
504
+ type: {
505
+ type: 'string'
506
+ },
507
+ jsonSchema: {
508
+ type: 'object'
509
+ }
510
+ }
489
511
  }
490
512
  }
491
513
  };