From 439914f8902a82d87be32675533d38996f55b509 Mon Sep 17 00:00:00 2001 From: Dave Longley Date: Mon, 28 Oct 2024 16:59:56 -0400 Subject: [PATCH] Filter by VPR `QueryByExample` `example` JSON-LD context. --- CHANGELOG.md | 6 ++++++ lib/presentations.js | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c150837..c9d56ef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # bedrock-web-wallet ChangeLog +## 14.6.2 - 2024-10-dd + +### Fixed +- Filter VPR query matches by JSON-LD context, if one was provided + in the query by example `example`. + ## 14.6.1 - 2024-10-02 ### Fixed diff --git a/lib/presentations.js b/lib/presentations.js index 3a952ca..e129d67 100644 --- a/lib/presentations.js +++ b/lib/presentations.js @@ -384,6 +384,9 @@ async function _getMatches({ for(const result of results) { const {credentialQuery, matches} = result; + // remove any matches that do not include the requested context + result.matches = matches.filter(_matchContextFilter({credentialQuery})); + // apply local filters // FIXME: write generalized matching instead result.matches = matches.filter(_openBadgeFilter({credentialQuery})); @@ -422,6 +425,36 @@ function _openBadgeFilter({credentialQuery}) { }; } +function _matchContextFilter({credentialQuery}) { + // get expected context + let expectedContext = credentialQuery?.example?.['@context']; + if(expectedContext === undefined) { + // no context specified, allow any result + return () => true; + } + // normalize to an array + if(!Array.isArray(expectedContext)) { + expectedContext = [expectedContext]; + } + // map to an array of strings for later comparison + expectedContext = expectedContext.map( + ctx => typeof ctx === 'string' ? ctx : JSON.stringify(ctx)); + return ({record: {content}}) => { + // normalize record context to an array if present + let recordContext = content['@context']; + if(recordContext !== undefined && !Array.isArray(recordContext)) { + recordContext = [recordContext]; + } + // map to an array of strings for later comparison + recordContext = recordContext.map( + ctx => typeof ctx === 'string' ? ctx : JSON.stringify(ctx)); + + // if every context value in `expectedContext` is present in + // `recordContext`, then accept the record + return expectedContext.every(c => recordContext.includes(c)); + }; +} + async function _matchQueryByExample({ verifiablePresentationRequest, query, credentialStore, matches }) {