Skip to content

Commit

Permalink
JSON-encode exchange variables if they include illegal mongodb key ch…
Browse files Browse the repository at this point in the history
…ars.
  • Loading branch information
dlongley committed Jan 28, 2025
1 parent ab543b6 commit ce999ff
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 7 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# bedrock-vc-delivery ChangeLog

## 6.5.0 - 2025-01-dd

### Added
- Allow exchange variables to contain JSON key values that are not
supported in mongoDB.

## 6.4.1 - 2025-01-27

### Fixed
Expand Down
56 changes: 49 additions & 7 deletions lib/exchanges.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*!
* Copyright (c) 2022-2024 Digital Bazaar, Inc. All rights reserved.
* Copyright (c) 2022-2025 Digital Bazaar, Inc. All rights reserved.
*/
import * as bedrock from '@bedrock/core';
import * as database from '@bedrock/mongodb';
Expand Down Expand Up @@ -35,6 +35,8 @@ const LAST_ERROR_UPDATE_CONSTRAINTS = {
updateTimeLimit: 1000
};

const MONGODB_ILLEGAL_KEY_CHAR_REGEX = /[%$.]/;

bedrock.events.on('bedrock-mongodb.ready', async () => {
await database.openCollections([COLLECTION_NAME]);

Expand Down Expand Up @@ -110,14 +112,14 @@ export async function insert({workflowId, exchange}) {
// backwards compatibility: enable existing systems to find record
localExchangerId: localWorkflowId,
meta,
exchange
exchange: _encodeVariables({exchange})
};

// insert the exchange and get the updated record
try {
const collection = database.collections[COLLECTION_NAME];
const result = await collection.insertOne(record);
return result.ops[0];
await collection.insertOne(record);
return record;
} catch(e) {
if(!database.isDuplicateError(e)) {
throw e;
Expand Down Expand Up @@ -199,6 +201,8 @@ export async function get({
});
}

record.exchange = _decodeVariables({exchange: record.exchange});

// backwards compatibility; initialize `sequence`
if(record.exchange.sequence === undefined) {
const query = {
Expand Down Expand Up @@ -237,6 +241,9 @@ export async function update({workflowId, exchange, explain = false} = {}) {
assert.object(exchange, 'exchange');
const {id} = exchange;

// encode variable content for storage in mongoDB
exchange = _encodeVariables({exchange});

// build update
const update = _buildUpdate({exchange, complete: false});

Expand Down Expand Up @@ -566,13 +573,13 @@ function _buildUpdate({exchange, complete}) {
$set: {'exchange.state': exchange.state, 'meta.updated': now},
$unset: {}
};
if(complete) {
// exchange complete, only update results
if(complete && typeof exchange.variables !== 'string') {
// exchange complete and variables not encoded, so only update results
if(exchange.variables?.results) {
update.$set['exchange.variables.results'] = exchange.variables.results;
}
} else {
// exchange not complete, update all variables
// exchange not complete or variables are encoded, so update all variables
if(exchange.variables) {
update.$set['exchange.variables'] = exchange.variables;
}
Expand Down Expand Up @@ -600,6 +607,41 @@ function _buildUpdate({exchange, complete}) {
return update;
}

function _encodeVariables({exchange}) {
// if any JSON object any variable uses a character that is not legal in
// a JSON key in mongoDB then stringify all the variables
if(_hasIllegalMongoDBKeyChar(exchange.variables)) {
return {...exchange, variables: JSON.stringify(exchange.variables)};
}
return exchange;
}

function _decodeVariables({exchange}) {
if(typeof exchange.variables === 'string') {
return {...exchange, variables: JSON.parse(exchange.variables)};
}
return exchange;
}

function _hasIllegalMongoDBKeyChar(value) {
if(Array.isArray(value)) {
for(const e of value) {
if(_hasIllegalMongoDBKeyChar(e)) {
return true;
}
}
} else if(value && typeof value === 'object') {
const keys = Object.keys(value);
for(const key of keys) {
if(MONGODB_ILLEGAL_KEY_CHAR_REGEX.test(key) ||
_hasIllegalMongoDBKeyChar(value[key])) {
return true;
}
}
}
return false;
}

/**
* An object containing information on the query plan.
*
Expand Down

0 comments on commit ce999ff

Please sign in to comment.