Skip to content

Commit

Permalink
Fix pex to bounds to match the API's
Browse files Browse the repository at this point in the history
  • Loading branch information
cykoder committed Jan 27, 2025
1 parent e185acc commit cfbf687
Showing 1 changed file with 122 additions and 47 deletions.
169 changes: 122 additions & 47 deletions packages/wasm/src/services/credential/pex-helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ export const EPSILON_INT = 1;

export const MAX_DATE_PLACEHOLDER = 884541351600000;
export const MIN_DATE_PLACEHOLDER = -17592186044415;
export const MAX_NUMBER = 100 ** 5;
export const MAX_INTEGER = 100 ** 9;
export const MIN_INTEGER = -4294967295;
export const MAX_NUMBER = 100 ** 6;
export const MIN_NUMBER = -4294967294;

/*
Expand All @@ -21,6 +23,15 @@ function correctFieldPath(path) {
return path.replace('$.', '');
}

function getNumDecimalPlaces(n) {
const parts = n.toString().split('.');
return parts.length > 1 && parts[1].length;
}

function toMaxDecimalPlaces(n, maxDecimalPlaces) {
return +n.toFixed(maxDecimalPlaces);
}

function getAttributeName({field, selectedCredentials, index}) {
let attributeName;
if (Array.isArray(field.path) && field.path.length > 1) {
Expand Down Expand Up @@ -49,23 +60,37 @@ function getAttributeName({field, selectedCredentials, index}) {
return attributeName;
}

export function pexToBounds(
pexRequest,
selectedCredentials = [],
isRawBoundies = false,
) {
export function pexToBounds(pexRequest, selectedCredentials = [], removeFromRequest = false) {

Check failure on line 63 in packages/wasm/src/services/credential/pex-helpers.js

View workflow job for this annotation

GitHub Actions / lintAndTest

Replace `pexRequest,·selectedCredentials·=·[],·removeFromRequest·=·false` with `⏎··pexRequest,⏎··selectedCredentials·=·[],⏎··removeFromRequest·=·false,⏎`

Check failure on line 63 in packages/wasm/src/services/credential/pex-helpers.js

View workflow job for this annotation

GitHub Actions / integrationTests

Replace `pexRequest,·selectedCredentials·=·[],·removeFromRequest·=·false` with `⏎··pexRequest,⏎··selectedCredentials·=·[],⏎··removeFromRequest·=·false,⏎`
const descriptorBounds = [];
const [MIN_DATE_ADJ, MAX_DATE_ADJ, MIN_NUMBER_ADJ, MAX_NUMBER_ADJ] = [
MIN_DATE_PLACEHOLDER,
MAX_DATE_PLACEHOLDER,
MIN_NUMBER,
MAX_NUMBER,
].map(value => (isRawBoundies ? undefined : value));
const fieldsToRemove = [];

// One list of bounds per descriptor/credential
pexRequest.input_descriptors.forEach((inputDescriptor, index) => {
const selectedCredential = selectedCredentials[index];
if (!selectedCredential) {
throw new Error(`Expected selected credential at index ${index}`);
}

// Get embedded schema if existing
let decodedSchema = {};
if (selectedCredential.credentialSchema) {
const schemaStartStr = 'data:application/json;charset=utf-8,';

if (selectedCredential.credentialSchema.details) {
decodedSchema = JSON.parse(selectedCredential.credentialSchema.details).jsonSchema || {};

Check failure on line 80 in packages/wasm/src/services/credential/pex-helpers.js

View workflow job for this annotation

GitHub Actions / lintAndTest

Replace `·JSON.parse(selectedCredential.credentialSchema.details).jsonSchema·||` with `⏎··········JSON.parse(selectedCredential.credentialSchema.details).jsonSchema·||⏎·········`

Check failure on line 80 in packages/wasm/src/services/credential/pex-helpers.js

View workflow job for this annotation

GitHub Actions / integrationTests

Replace `·JSON.parse(selectedCredential.credentialSchema.details).jsonSchema·||` with `⏎··········JSON.parse(selectedCredential.credentialSchema.details).jsonSchema·||⏎·········`
} else if (
selectedCredential.credentialSchema.id &&
selectedCredential.credentialSchema.id.startsWith(schemaStartStr)
) {
// LEGACY embedded schema handling
decodedSchema = JSON.parse(
decodeURIComponent(selectedCredential.credentialSchema.id.split(schemaStartStr)[1])

Check failure on line 87 in packages/wasm/src/services/credential/pex-helpers.js

View workflow job for this annotation

GitHub Actions / lintAndTest

Replace `selectedCredential.credentialSchema.id.split(schemaStartStr)[1])` with `⏎············selectedCredential.credentialSchema.id.split(schemaStartStr)[1],⏎··········),`

Check failure on line 87 in packages/wasm/src/services/credential/pex-helpers.js

View workflow job for this annotation

GitHub Actions / integrationTests

Replace `selectedCredential.credentialSchema.id.split(schemaStartStr)[1])` with `⏎············selectedCredential.credentialSchema.id.split(schemaStartStr)[1],⏎··········),`
);
}
}

const bounds = [];
inputDescriptor.constraints.fields.forEach(field => {
inputDescriptor.constraints.fields.forEach((field) => {

Check failure on line 93 in packages/wasm/src/services/credential/pex-helpers.js

View workflow job for this annotation

GitHub Actions / lintAndTest

Replace `(field)` with `field`

Check failure on line 93 in packages/wasm/src/services/credential/pex-helpers.js

View workflow job for this annotation

GitHub Actions / integrationTests

Replace `(field)` with `field`
const {
exclusiveMaximum,
exclusiveMinimum,
Expand All @@ -77,6 +102,35 @@ export function pexToBounds(
type,
} = field.filter || {};

if (!field.path || field.path.length === 0) {
throw new Error('Missing or empty field "path" property, expected array or string');

Check failure on line 106 in packages/wasm/src/services/credential/pex-helpers.js

View workflow job for this annotation

GitHub Actions / lintAndTest

Replace `'Missing·or·empty·field·"path"·property,·expected·array·or·string'` with `⏎··········'Missing·or·empty·field·"path"·property,·expected·array·or·string',⏎········`

Check failure on line 106 in packages/wasm/src/services/credential/pex-helpers.js

View workflow job for this annotation

GitHub Actions / integrationTests

Replace `'Missing·or·empty·field·"path"·property,·expected·array·or·string'` with `⏎··········'Missing·or·empty·field·"path"·property,·expected·array·or·string',⏎········`
}

let attributeName;
if (Array.isArray(field.path) && field.path.length > 1) {
// Must find a path that matches in selectedcredential, and choose that for bounds
const pathCount = field.path.length;
for (let i = 0; i < pathCount; i++) {
const path = field.path[i];
const paths = JSONPath.paths(selectedCredential, path);
if (paths.length) {
// First come first served
attributeName = correctFieldPath(JSONPath.stringify(paths[0]));
break;
}
}
} else {
const path = Array.isArray(field.path) ? field.path[0] : field.path;
attributeName = correctFieldPath(path);
}

if (!attributeName) {
throw new Error('Invalid "path" property, expected JSONPath into the credential');

Check failure on line 128 in packages/wasm/src/services/credential/pex-helpers.js

View workflow job for this annotation

GitHub Actions / lintAndTest

Replace `'Invalid·"path"·property,·expected·JSONPath·into·the·credential'` with `⏎··········'Invalid·"path"·property,·expected·JSONPath·into·the·credential',⏎········`

Check failure on line 128 in packages/wasm/src/services/credential/pex-helpers.js

View workflow job for this annotation

GitHub Actions / integrationTests

Replace `'Invalid·"path"·property,·expected·JSONPath·into·the·credential'` with `⏎··········'Invalid·"path"·property,·expected·JSONPath·into·the·credential',⏎········`
}

const schemaPath = `$.properties.${attributeName.replaceAll('.', '.properties.')}`;

Check failure on line 131 in packages/wasm/src/services/credential/pex-helpers.js

View workflow job for this annotation

GitHub Actions / lintAndTest

Replace `'.',·'.properties.'` with `⏎········'.',⏎········'.properties.',⏎······`

Check failure on line 131 in packages/wasm/src/services/credential/pex-helpers.js

View workflow job for this annotation

GitHub Actions / integrationTests

Replace `'.',·'.properties.'` with `⏎········'.',⏎········'.properties.',⏎······`
const attributeSchema = JSONPath.query(decodedSchema, schemaPath, 1)[0] || { type };

Check failure on line 132 in packages/wasm/src/services/credential/pex-helpers.js

View workflow job for this annotation

GitHub Actions / lintAndTest

Replace `decodedSchema,·schemaPath,·1)[0]·||·{·type·` with `⏎········decodedSchema,⏎········schemaPath,⏎········1,⏎······)[0]·||·{type`

Check failure on line 132 in packages/wasm/src/services/credential/pex-helpers.js

View workflow job for this annotation

GitHub Actions / integrationTests

Replace `decodedSchema,·schemaPath,·1)[0]·||·{·type·` with `⏎········decodedSchema,⏎········schemaPath,⏎········1,⏎······)[0]·||·{type`

let max =
maximum === undefined
? formatMaximum === undefined
Expand All @@ -95,63 +149,84 @@ export function pexToBounds(
return;
}

const attributeType = attributeSchema.type || type;

// Get min/max bounds values, if using exclusive we must apply an epsilon so equality isnt true
if (format === 'date-time' || format === 'date') {
max = max === undefined ? MAX_DATE_ADJ : max;
max = max ? new Date(max) : undefined;
min = min === undefined ? MIN_DATE_ADJ : min;
min = min ? new Date(min) : undefined;
} else if (type === 'number') {
max = new Date(max === undefined ? MAX_DATE_PLACEHOLDER : max);
min = new Date(min === undefined ? MIN_DATE_PLACEHOLDER : min);
} else if (attributeType === 'number') {
const epsilon = attributeSchema.multipleOf || EPSILON_NUMBER;
const attribDecimalPlaces = getNumDecimalPlaces(epsilon);

max =
max === undefined
? MAX_NUMBER_ADJ
: exclusiveMaximum === undefined || isRawBoundies
? attributeSchema.maximum === undefined
? MAX_NUMBER
: attributeSchema.maximum
: exclusiveMaximum === undefined
? max
: max - EPSILON_NUMBER;
: max - epsilon;
min =
min === undefined
? MIN_NUMBER_ADJ
: exclusiveMinimum === undefined || isRawBoundies
? attributeSchema.minimum === undefined
? MIN_NUMBER
: attributeSchema.minimum
: exclusiveMinimum === undefined
? min
: min + EPSILON_NUMBER;
} else if (type === 'integer') {
: min + epsilon;

// Because of floating point math sucks, sometimes we can get extra decimal points
// the bounds must also match the same decimal points as the input
// for this we read from the embedded schema
min = toMaxDecimalPlaces(min, attribDecimalPlaces);
max = toMaxDecimalPlaces(max, attribDecimalPlaces);
} else if (attributeType === 'integer') {
max =
max === undefined
? MAX_NUMBER_ADJ
: exclusiveMaximum === undefined || isRawBoundies
? attributeSchema.maximum === undefined
? MAX_INTEGER
: attributeSchema.maximum
: exclusiveMaximum === undefined
? max
: max - EPSILON_INT;
min =
min === undefined
? MIN_NUMBER_ADJ
: exclusiveMinimum === undefined || isRawBoundies
? attributeSchema.minimum === undefined
? MIN_INTEGER
: attributeSchema.minimum
: exclusiveMinimum === undefined
? min
: min + EPSILON_INT;

// Ensure that input values are not decimals otherwise crypto-wasm-ts will complain
min = Math.floor(min);
max = Math.floor(max);
} else {
throw new Error(
`Unsupported format ${format} and type ${type} for enforce bounds`,
);
throw new Error(`Unsupported format ${format} and type ${type} for enforce bounds`);

Check failure on line 206 in packages/wasm/src/services/credential/pex-helpers.js

View workflow job for this annotation

GitHub Actions / lintAndTest

Replace ``Unsupported·format·${format}·and·type·${type}·for·enforce·bounds`` with `⏎··········`Unsupported·format·${format}·and·type·${type}·for·enforce·bounds`,⏎········`

Check failure on line 206 in packages/wasm/src/services/credential/pex-helpers.js

View workflow job for this annotation

GitHub Actions / integrationTests

Replace ``Unsupported·format·${format}·and·type·${type}·for·enforce·bounds`` with `⏎··········`Unsupported·format·${format}·and·type·${type}·for·enforce·bounds`,⏎········`
}

const attributeName = getAttributeName({
field,
selectedCredentials,
index,
});

if (attributeName !== undefined) {
bounds.push({
attributeName,
min,
max,
type,
format,
if (removeFromRequest) {
fieldsToRemove.push({
fields: inputDescriptor.constraints.fields,
field,
});
}

bounds.push({
attributeName,
min,
max,
});
});

if (bounds.length) {
descriptorBounds.push(bounds);
descriptorBounds.push(bounds);
});

fieldsToRemove.forEach(({ fields, field }) => {

Check failure on line 226 in packages/wasm/src/services/credential/pex-helpers.js

View workflow job for this annotation

GitHub Actions / lintAndTest

Replace `·fields,·field·` with `fields,·field`

Check failure on line 226 in packages/wasm/src/services/credential/pex-helpers.js

View workflow job for this annotation

GitHub Actions / integrationTests

Replace `·fields,·field·` with `fields,·field`
const idx = fields.indexOf(field);
if (idx !== -1) {
fields.splice(idx, 1);
}
});

Expand Down

0 comments on commit cfbf687

Please sign in to comment.