@bedrock/vc-delivery 6.4.0 → 6.5.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/exchanges.js CHANGED
@@ -1,5 +1,5 @@
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 database from '@bedrock/mongodb';
@@ -35,6 +35,8 @@ const LAST_ERROR_UPDATE_CONSTRAINTS = {
35
35
  updateTimeLimit: 1000
36
36
  };
37
37
 
38
+ const MONGODB_ILLEGAL_KEY_CHAR_REGEX = /[%$.]/;
39
+
38
40
  bedrock.events.on('bedrock-mongodb.ready', async () => {
39
41
  await database.openCollections([COLLECTION_NAME]);
40
42
 
@@ -110,14 +112,14 @@ export async function insert({workflowId, exchange}) {
110
112
  // backwards compatibility: enable existing systems to find record
111
113
  localExchangerId: localWorkflowId,
112
114
  meta,
113
- exchange
115
+ exchange: _encodeVariables({exchange})
114
116
  };
115
117
 
116
118
  // insert the exchange and get the updated record
117
119
  try {
118
120
  const collection = database.collections[COLLECTION_NAME];
119
- const result = await collection.insertOne(record);
120
- return result.ops[0];
121
+ await collection.insertOne(record);
122
+ return record;
121
123
  } catch(e) {
122
124
  if(!database.isDuplicateError(e)) {
123
125
  throw e;
@@ -199,6 +201,8 @@ export async function get({
199
201
  });
200
202
  }
201
203
 
204
+ record.exchange = _decodeVariables({exchange: record.exchange});
205
+
202
206
  // backwards compatibility; initialize `sequence`
203
207
  if(record.exchange.sequence === undefined) {
204
208
  const query = {
@@ -237,6 +241,9 @@ export async function update({workflowId, exchange, explain = false} = {}) {
237
241
  assert.object(exchange, 'exchange');
238
242
  const {id} = exchange;
239
243
 
244
+ // encode variable content for storage in mongoDB
245
+ exchange = _encodeVariables({exchange});
246
+
240
247
  // build update
241
248
  const update = _buildUpdate({exchange, complete: false});
242
249
 
@@ -566,13 +573,13 @@ function _buildUpdate({exchange, complete}) {
566
573
  $set: {'exchange.state': exchange.state, 'meta.updated': now},
567
574
  $unset: {}
568
575
  };
569
- if(complete) {
570
- // exchange complete, only update results
576
+ if(complete && typeof exchange.variables !== 'string') {
577
+ // exchange complete and variables not encoded, so only update results
571
578
  if(exchange.variables?.results) {
572
579
  update.$set['exchange.variables.results'] = exchange.variables.results;
573
580
  }
574
581
  } else {
575
- // exchange not complete, update all variables
582
+ // exchange not complete or variables are encoded, so update all variables
576
583
  if(exchange.variables) {
577
584
  update.$set['exchange.variables'] = exchange.variables;
578
585
  }
@@ -600,6 +607,41 @@ function _buildUpdate({exchange, complete}) {
600
607
  return update;
601
608
  }
602
609
 
610
+ function _encodeVariables({exchange}) {
611
+ // if any JSON object any variable uses a character that is not legal in
612
+ // a JSON key in mongoDB then stringify all the variables
613
+ if(_hasIllegalMongoDBKeyChar(exchange.variables)) {
614
+ return {...exchange, variables: JSON.stringify(exchange.variables)};
615
+ }
616
+ return exchange;
617
+ }
618
+
619
+ function _decodeVariables({exchange}) {
620
+ if(typeof exchange.variables === 'string') {
621
+ return {...exchange, variables: JSON.parse(exchange.variables)};
622
+ }
623
+ return exchange;
624
+ }
625
+
626
+ function _hasIllegalMongoDBKeyChar(value) {
627
+ if(Array.isArray(value)) {
628
+ for(const e of value) {
629
+ if(_hasIllegalMongoDBKeyChar(e)) {
630
+ return true;
631
+ }
632
+ }
633
+ } else if(value && typeof value === 'object') {
634
+ const keys = Object.keys(value);
635
+ for(const key of keys) {
636
+ if(MONGODB_ILLEGAL_KEY_CHAR_REGEX.test(key) ||
637
+ _hasIllegalMongoDBKeyChar(value[key])) {
638
+ return true;
639
+ }
640
+ }
641
+ }
642
+ return false;
643
+ }
644
+
603
645
  /**
604
646
  * An object containing information on the query plan.
605
647
  *
package/lib/vcapi.js CHANGED
@@ -223,9 +223,20 @@ export async function processExchange({req, res, workflow, exchangeRecord}) {
223
223
  break;
224
224
  }
225
225
 
226
+ // FIXME: remove this once the other FIXME below is implemented
227
+ // and provides support for issuance in non-last step
228
+ if(step.issueRequests?.length > 0) {
229
+ throw new BedrockError(
230
+ 'Invalid step detected; continuing exchanges currently must ' +
231
+ 'only issue in the final step.', {
232
+ name: 'DataError',
233
+ details: {httpStatusCode: 500, public: true}
234
+ });
235
+ }
236
+
226
237
  // update the exchange to go to the next step, then loop to send
227
238
  // next VPR
228
- currentStep = exchange.step = step.nextStep;
239
+ exchange.step = step.nextStep;
229
240
  // ensure exchange state is active
230
241
  if(exchange.state === 'pending') {
231
242
  exchange.state = 'active';
@@ -249,6 +260,7 @@ export async function processExchange({req, res, workflow, exchangeRecord}) {
249
260
  details: {httpStatusCode: 500, public: true}
250
261
  });
251
262
  }
263
+ currentStep = step.nextStep;
252
264
  }
253
265
 
254
266
  // mark exchange complete
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bedrock/vc-delivery",
3
- "version": "6.4.0",
3
+ "version": "6.5.0",
4
4
  "type": "module",
5
5
  "description": "Bedrock Verifiable Credential Delivery",
6
6
  "main": "./lib/index.js",