Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# bedrock-web-wallet ChangeLog

## 15.2.0 - 2026-02-dd

### Added
- Add support for string values in `acceptedCryptosuites` in VPR queries.

## 15.1.0 - 2026-01-26

### Added
Expand Down
61 changes: 46 additions & 15 deletions lib/exchanges/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,13 @@ export function getDIDAuthenticationOptions({vpr} = {}) {
// future, processing should be done by `group` (which can be `undefined`)
// so only the `DIDAuthentication` query in the `group` of choice for
// presentation is selected
options.acceptedCryptosuites = didAuthnQueries[0]?.acceptedCryptoSuites;
if(Array.isArray(didAuthnQueries[0]?.acceptedCryptoSuites)) {
// normalize `acceptedCryptosuites` to objects
options.acceptedCryptosuites = didAuthnQueries[0].acceptedCryptoSuites
.map(e => typeof e === 'string' ? ({cryptosuite: e}) : e);

// for backwards-compatibility, map `acceptedCryptosuites` to
// `acceptedProofTypes`
if(options.acceptedCryptosuites) {
// for backwards-compatibility, map `acceptedCryptosuites` to
// `acceptedProofTypes`
options.acceptedProofTypes = options.acceptedCryptosuites.map(
({cryptosuite}) => ({name: cryptosuite}));
}
Expand Down Expand Up @@ -56,27 +58,56 @@ export function getDIDAuthenticationOptions({vpr} = {}) {
}

function _normalizeDIDAuthenticationQuery({vpr, query}) {
if(query.acceptedCryptoSuites) {
// query is already normal
return query.acceptedCryptoSuites;
const {
acceptedCryptosuites, acceptedCryptoSuites: mispelled, ...rest
} = query;

if(acceptedCryptosuites) {
if(Array.isArray(acceptedCryptosuites)) {
// normalize `acceptedCryptosuites` and leave out
// misspelled `acceptedCryptoSuites`
return {
...rest,
acceptedCryptosuites:
_normalizeAcceptedCryptosuites(acceptedCryptosuites)
};
}
// remove invalid `acceptedCryptosuites` value
query = {...rest};
}

// normalize to standard `acceptedCryptosuites` from older mechanisms...
if(query.acceptedCryptoSuites) {
// handle different casing
const {acceptedCryptoSuites, ...rest} = query;
return {...rest, acceptedCryptosuites: acceptedCryptoSuites};

// handle mispelling that was used for a while
if(mispelled) {
if(Array.isArray(mispelled)) {
return {
...rest,
acceptedCryptosuites:
_normalizeAcceptedCryptosuites(mispelled)
};
}
// remove invalid mispelling value
query = {...rest};
}

// handle VPR-level expression with:
// "acceptedProofTypes": [{name: <cryptosuiteName>}]
// "supportedProofTypes": [{name: <cryptosuiteName>}]
const acceptedProofTypes = vpr.acceptedProofTypes ?? vpr.supportedProofTypes;
if(acceptedProofTypes) {
const acceptedCryptosuites = acceptedProofTypes.map(
({name}) => ({cryptosuite: name}));
return {...query, acceptedCryptosuites};
if(Array.isArray(acceptedProofTypes)) {
const acceptedCryptosuites = acceptedProofTypes
.filter(e => e?.name)
.map(({name}) => ({cryptosuite: name}));
return {...rest, acceptedCryptosuites};
}

return query;
}

function _normalizeAcceptedCryptosuites(acceptedCryptosuites) {
// remove any invalid values; normalize to objects
return acceptedCryptosuites
.filter(e => e && (typeof e === 'string' || e.cryptosuite))
.map(e => typeof e === 'string' ? ({cryptosuite: e}) : e);
}
27 changes: 16 additions & 11 deletions lib/presentations.js
Original file line number Diff line number Diff line change
Expand Up @@ -233,23 +233,28 @@ async function _deriveCredentials({
}) {
// can assume a single `vprQuery.credentialQuery` due to prior processing
const {credentialQuery} = vprQuery;
// normalize `acceptedCryptosuites` and sanitize `example` inputs
let {acceptedCryptosuites = [], example = {}} = credentialQuery;
if(!Array.isArray(acceptedCryptosuites)) {
acceptedCryptosuites = [acceptedCryptosuites];
}
if(!(example && typeof example === 'object')) {
example = {};

// normalize `acceptedCryptosuites`
let {acceptedCryptosuites = []} = credentialQuery;
if(Array.isArray(acceptedCryptosuites)) {
// remove any invalid values; normalize to objects
return acceptedCryptosuites
.filter(e => e && (typeof e === 'string' || e.cryptosuite))
.map(e => typeof e === 'string' ? ({cryptosuite: e}) : e);
} else {
// invalid `acceptedCryptosuites` value, reset to empty array
acceptedCryptosuites = [];
}
if(acceptedCryptosuites.length === 0) {
// verifier does not mention any accepted SD cryptosuites, so nothing to do
return;
}

// normalize `acceptedCryptosuites` to `[{cryptosuite}, ...]` to handle
// backwards-compatibility where an array of strings was used
acceptedCryptosuites = acceptedCryptosuites.map(
ac => typeof ac === 'object' ? ac : ({cryptosuite: ac}));
// normalize `example`
let {example = {}} = credentialQuery;
if(!(example && typeof example === 'object')) {
example = {};
}

// convert `vprQuery.credentialQuery.example` to JSON pointers, modulo
// `@context` field (the `@context` field is assumed to already have been
Expand Down
Loading