Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow bigints as type integer #385

Merged
merged 3 commits into from
Sep 6, 2023
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
1 change: 1 addition & 0 deletions packages/browser-wallet/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

- Changed 'Zero Knowledge' to 'Zero-knowledge' in display texts.
- An issue with images in verifiable credentials for lower resolutions.
- Schema validation of verifiable credentials with attributes that have `{ type: "integer" }` no longer rejects BigInt values.

## 1.1.6

Expand Down
29 changes: 24 additions & 5 deletions packages/browser-wallet/src/background/web3Id.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import {
IdStatement,
StatementTypes,
AttributeType,
isTimestampAttribute,
TimestampAttribute,
} from '@concordium/web-sdk';
import {
sessionVerifiableCredentials,
Expand Down Expand Up @@ -126,12 +128,21 @@ function rejectRequest(message: string): { run: false; response: MessageStatusWr
};
}

// TODO Expose function from SDK and re-use.
function timestampToDate(attribute: TimestampAttribute): Date {
return new Date(Date.parse(attribute.timestamp));
}

function validateTimestampAttribute(attributeTag: string, attributeValue: AttributeType) {
if (
attributeValue instanceof Date &&
(attributeValue.getTime() < MIN_DATE_TIMESTAMP || attributeValue.getTime() > MAX_DATE_TIMESTAMP)
) {
return `The attribute [${attributeValue}] for key [${attributeTag}] is out of bounds for a Date. The Date must be between ${MIN_DATE_ISO} and ${MAX_DATE_ISO}`;
if (isTimestampAttribute(attributeValue)) {
const timestamp = timestampToDate(attributeValue).getTime();
if (Number.isNaN(timestamp)) {
return `The attribute [${attributeValue.timestamp}] for key [${attributeTag}] cannot be parsed as a Date.`;
}
orhoj marked this conversation as resolved.
Show resolved Hide resolved

if (timestamp < MIN_DATE_TIMESTAMP || timestamp > MAX_DATE_TIMESTAMP) {
return `The attribute [${attributeValue.timestamp}] for key [${attributeTag}] is out of bounds for a Date. The Date must be between ${MIN_DATE_ISO} and ${MAX_DATE_ISO}`;
}
}
return undefined;
}
Expand All @@ -154,6 +165,14 @@ function validateAttributeBounds(
attributeTag: string,
attributeValue: AttributeType
): { error: false } | { error: true; message: string } {
if (
typeof attributeValue !== 'string' &&
typeof attributeValue !== 'bigint' &&
!isTimestampAttribute(attributeValue)
) {
return { error: true, message: 'Unsupported attribute type' };
}

const stringError = validateStringAttribute(attributeTag, attributeValue);
if (stringError) {
return { error: true, message: stringError };
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { useAsyncMemo } from 'wallet-common-helpers';
import { useHdWallet } from '@popup/shared/utils/account-helpers';
import { displayUrl } from '@popup/shared/utils/string-helpers';
import {
coerceBigIntIntegerToNumber,
createCredentialId,
createPublicKeyIdentifier,
fetchCredentialMetadata,
Expand Down Expand Up @@ -123,7 +124,8 @@ export default function AddWeb3IdCredential({ onAllow, onReject }: Props) {
const schemaWithNoId = withIdRemovedFromSchema(schema);
const validationResult = validator.validate(
{ credentialSubject: credential.credentialSubject },
schemaWithNoId as unknown as Schema
schemaWithNoId as unknown as Schema,
{ preValidateProperty: coerceBigIntIntegerToNumber }
);
if (!validationResult.valid) {
setError(t('error.schemaValidation', { errors: validationResult.errors.toString() }));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
VerifiableCredentialStatus,
} from '@shared/storage/types';
import { Buffer } from 'buffer/';
import jsonschema from 'jsonschema';
import jsonschema, { Schema } from 'jsonschema';
import { applyExecutionNRGBuffer, getContractName } from './contract-helpers';
import { getNet } from './network-helpers';
import { logError } from './log-helpers';
Expand Down Expand Up @@ -1236,3 +1236,21 @@ export function withIdRemovedFromSchema(schema: VerifiableCredentialSchema) {

return { ...schema, properties: schemaOuterPropertiesWithNoId };
}

/**
* BigInts do not validate against a json schema as being an integer. This pre validate function
* coerces any bigint values where { type: "integer" } into number, as that will ensure that
* they validate against the schema.
*/
export function coerceBigIntIntegerToNumber(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
instance: any,
key: string,
schema: Schema
) {
const value = instance[key];
if (schema.type && schema.type === 'integer' && typeof value === 'bigint') {
// eslint-disable-next-line no-param-reassign
instance[key] = Number(value);
}
}
20 changes: 20 additions & 0 deletions packages/browser-wallet/test/verifiable-credential-helpers.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { Schema, Validator } from 'jsonschema';
import {
RevocationDataHolder,
RevokeCredentialHolderParam,
Expand All @@ -13,6 +14,7 @@ import {
getCredentialIdFromSubjectDID,
getContractAddressFromIssuerDID,
getVerifiableCredentialPublicKeyfromSubjectDID,
coerceBigIntIntegerToNumber,
} from '../src/shared/utils/verifiable-credential-helpers';
import { mainnet, testnet } from '../src/shared/constants/networkConfiguration';

Expand Down Expand Up @@ -184,3 +186,21 @@ test('getCredentialIdFromSubjectDID extracts credId without network', () => {
'aad98095db73b5b22f7f64823a495c6c57413947353646313dc453fa4604715d2f93b2c1f8cb4c9625edd6330e1d27fa'
);
});

test('bigint with type integer validates against schema when coercing in pre validate', () => {
const validator = new Validator();
const schema: Schema = {
type: 'object',
properties: {
age: { type: 'integer' },
},
};

const p = {
age: BigInt(97),
};

const validationResult = validator.validate(p, schema, { preValidateProperty: coerceBigIntIntegerToNumber });

expect(validationResult.valid).toBeTruthy();
});
Loading