diff --git a/deps/concordium-rust-sdk b/deps/concordium-rust-sdk index 35476f86..5a84f1a1 160000 --- a/deps/concordium-rust-sdk +++ b/deps/concordium-rust-sdk @@ -1 +1 @@ -Subproject commit 35476f869507f9892efb1c157c59e89356d1857a +Subproject commit 5a84f1a1489647b013bdacb08fed7257ee805bd8 diff --git a/test-tools/issuer-front-end/CHANGELOG.md b/test-tools/issuer-front-end/CHANGELOG.md index e4c9ef21..69d9cee1 100644 --- a/test-tools/issuer-front-end/CHANGELOG.md +++ b/test-tools/issuer-front-end/CHANGELOG.md @@ -1,5 +1,9 @@ ## Unreleased changes +## 1.0.1 + +- Make the issuer compatible with the latest 1.1.0 wallet. + ## 1.0.0 - Initial issuer front end diff --git a/test-tools/issuer-front-end/package.json b/test-tools/issuer-front-end/package.json index f24a0bd9..57a13374 100644 --- a/test-tools/issuer-front-end/package.json +++ b/test-tools/issuer-front-end/package.json @@ -1,7 +1,7 @@ { "name": "issuer-front-end", "packageManager": "yarn@3.2.0", - "version": "1.0.0", + "version": "1.0.1", "license": "Apache-2.0", "engines": { "node": ">=16.x" @@ -13,12 +13,16 @@ "@concordium/web-sdk": "^6.1.0-alpha.1", "@walletconnect/types": "^2.1.4", "eslint": "^8.37.0", + "json-bigint": "^1.0.0", "moment": "^2.29.4", "react": "^18.1.0", "react-bootstrap": "^2.7.4", "react-dom": "^18.1.0", "react-switch": "^7.0.0" }, + "resolutions": { + "@concordium/web-sdk": "^6.1.0-alpha.1" + }, "devDependencies": { "@craftamap/esbuild-plugin-html": "^0.4.0", "@types/node": "^18.7.23", diff --git a/test-tools/issuer-front-end/src/Main.tsx b/test-tools/issuer-front-end/src/Main.tsx index bb17a73d..1753d80a 100644 --- a/test-tools/issuer-front-end/src/Main.tsx +++ b/test-tools/issuer-front-end/src/Main.tsx @@ -1,10 +1,11 @@ /* eslint-disable no-console */ -import React, { useEffect, useState, ChangeEvent, PropsWithChildren, useRef, useCallback } from 'react'; +import React, { useEffect, useState, ChangeEvent, PropsWithChildren, useCallback } from 'react'; import Switch from 'react-switch'; import { WalletConnectionProps, useConnection, useConnect, useGrpcClient, TESTNET } from '@concordium/react-components'; import { Button, Col, Row, Form, InputGroup } from 'react-bootstrap'; import { detectConcordiumProvider } from '@concordium/browser-wallet-api-helpers'; import { AccountAddress, ConcordiumGRPCClient } from '@concordium/web-sdk'; +import { stringify } from 'json-bigint'; import { version } from '../package.json'; import { WalletConnectionTypeButton } from './WalletConnectorTypeButton'; @@ -31,7 +32,7 @@ type RequestSignatureResponse = { signature: string; commitments: object; }; - randomness: object; + randomness: Record; }; type RequestIssuerKeysResponse = { @@ -49,7 +50,7 @@ type SchemaRef = { }; interface Attribute { - [key: string]: string | number; + [key: string]: string | bigint; } function TestBox({ header, children, note }: TestBoxProps) { @@ -81,6 +82,8 @@ async function addRevokationKey( } } +type AttributeDetails = { tag: string; type: string; value: string | undefined }; + export default function Main(props: WalletConnectionProps) { const { activeConnectorType, activeConnector, activeConnectorError, connectedAccounts, genesisHashes } = props; @@ -101,7 +104,7 @@ export default function Main(props: WalletConnectionProps) { const [issuerKeys, setIssuerKeys] = useState(); const [parsingError, setParsingError] = useState(''); - const [attributeSchema, setAttributeSchema] = useState([]); + const [attributeSchema, setAttributeSchema] = useState([]); const [reason, setReason] = useState(''); @@ -140,10 +143,6 @@ export default function Main(props: WalletConnectionProps) { const [validUntilDate, setValidUntilDate] = useState('2025-06-12T07:30'); const [credentialHasExpiryDate, setCredentialHasExpiryDate] = useState(true); - const schemaMetaDataURLRef = useRef(null); - const schemaCredentialURLRef = useRef(null); - const schemaIssuerURLRef = useRef(null); - const handleValidFromDateChange = useCallback((event: ChangeEvent) => { const target = event.target as HTMLTextAreaElement; setValidFromDate(target.value); @@ -192,9 +191,9 @@ export default function Main(props: WalletConnectionProps) { .then((json) => { const { properties } = json.properties.credentialSubject.properties.attributes; - const attributeSchemaValues: string[][] = []; - Object.keys(properties).forEach((key) => { - attributeSchemaValues.push([key, properties[key].type, '']); + const attributeSchemaValues: AttributeDetails[] = []; + Object.entries(properties).forEach(([key, obj]) => { + attributeSchemaValues.push({ tag: key, type: (obj as { type: string }).type, value: undefined }); }); setAttributeSchema(attributeSchemaValues); @@ -224,14 +223,20 @@ export default function Main(props: WalletConnectionProps) { const registryMetadataReturnValue = JSON.parse(await registryMetadata(client, Number(target.value))); + setSchemaCredential(registryMetadataReturnValue.credential_schema); + fetch(registryMetadataReturnValue.credential_schema.schema_ref.url) .then((response) => response.json()) .then((json) => { const { properties } = json.properties.credentialSubject.properties.attributes; - const attributeSchemaValues: string[][] = []; - Object.keys(properties).forEach((key) => { - attributeSchemaValues.push([key, properties[key].type, '']); + const attributeSchemaValues: AttributeDetails[] = []; + Object.entries(properties).forEach(([key, obj]) => { + attributeSchemaValues.push({ + tag: key, + type: (obj as { type: string }).type, + value: undefined, + }); }); setAttributeSchema(attributeSchemaValues); @@ -241,16 +246,19 @@ export default function Main(props: WalletConnectionProps) { [] ); - const handleAttributeChange = useCallback((i: string, attributeSchemaValue: string[][], event: ChangeEvent) => { - const target = event.target as HTMLTextAreaElement; + const handleAttributeChange = useCallback( + (i: string, attributeSchemaValue: AttributeDetails[], event: ChangeEvent) => { + const target = event.target as HTMLTextAreaElement; - Object.keys(attributeSchemaValue).forEach((key) => { - if (attributeSchemaValue[Number(key)][0] === i) { - // eslint-disable-next-line no-param-reassign - attributeSchemaValue[Number(key)][2] = target.value; - } - }); - }, []); + attributeSchemaValue.forEach((obj) => { + if (obj.tag === i) { + // eslint-disable-next-line no-param-reassign + obj.value = target.value; + } + }); + }, + [] + ); // Refresh accountInfo periodically. // eslint-disable-next-line consistent-return @@ -298,15 +306,6 @@ export default function Main(props: WalletConnectionProps) { setBrowserPublicKey(''); }); } - - const schemaMetaDataURL = schemaMetaDataURLRef.current as unknown as HTMLFormElement; - schemaMetaDataURL?.setAttribute('placeholder', EXAMPLE_CREDENTIAL_METADATA); - - const schemaCredentialURL = schemaCredentialURLRef.current as unknown as HTMLFormElement; - schemaCredentialURL?.setAttribute('placeholder', EXAMPLE_CREDENTIAL_SCHEMA); - - const schemaIssuerURL = schemaIssuerURLRef.current as unknown as HTMLFormElement; - schemaIssuerURL?.setAttribute('placeholder', EXAMPLE_ISSUER_METADATA); }, [connection, account]); useEffect(() => { @@ -315,9 +314,9 @@ export default function Main(props: WalletConnectionProps) { .then((json) => { const { properties } = json.properties.credentialSubject.properties.attributes; - const attributeSchemaValues: string[][] = []; - Object.keys(properties).forEach((key) => { - attributeSchemaValues.push([key, properties[key].type, '']); + const attributeSchemaValues: AttributeDetails[] = []; + Object.entries(properties).forEach(([key, obj]) => { + attributeSchemaValues.push({ tag: key, type: (obj as { type: string }).type, value: undefined }); }); setAttributeSchema(attributeSchemaValues); @@ -418,7 +417,7 @@ export default function Main(props: WalletConnectionProps) { className="inputFieldStyle" id="issuerMetaDataURL" type="text" - ref={schemaIssuerURLRef} + placeholder={EXAMPLE_ISSUER_METADATA} onChange={changeIssuerMetaDataURLHandler} />
@@ -439,7 +438,7 @@ export default function Main(props: WalletConnectionProps) { className="inputFieldStyle" id="credentialSchemaURL" type="text" - ref={schemaCredentialURLRef} + placeholder={EXAMPLE_CREDENTIAL_SCHEMA} onChange={changeCredentialSchemaURLHandler} /> {revocationKeys.length !== 0 && ( @@ -560,16 +559,16 @@ export default function Main(props: WalletConnectionProps) { > {attributeSchema.map((item) => (
- Add {item[0]}: + Add {item.tag}:
{ - handleAttributeChange(item[0], attributeSchema, event); + handleAttributeChange(item.tag, attributeSchema, event); }} />
@@ -632,7 +631,7 @@ export default function Main(props: WalletConnectionProps) { className="inputFieldStyle" id="credentialMetaDataURL" type="text" - ref={schemaMetaDataURLRef} + placeholder={EXAMPLE_CREDENTIAL_METADATA} onChange={changeCredentialMetaDataURLHandler} />
@@ -688,41 +687,22 @@ export default function Main(props: WalletConnectionProps) { const attributes: Attribute = {}; - Object.keys(attributeSchema).forEach((key) => { - if (attributeSchema[Number(key)][2] === '') { - setParsingError( - `Attribute ${attributeSchema[Number(key)][0]} need to be set.` - ); - throw new Error( - `Attribute ${attributeSchema[Number(key)][0]} need to be set.` - ); + attributeSchema.forEach((obj) => { + if (obj.value === undefined) { + setParsingError(`Attribute ${obj.tag} needs to be set.`); + throw new Error(`Attribute ${obj.tag} needs to be set.`); } - if ( - JSON.stringify(attributeSchema[Number(key)][1]) === - JSON.stringify('string') - ) { - // eslint-disable-next-line prefer-destructuring - attributes[attributeSchema[Number(key)][0]] = - attributeSchema[Number(key)][2]; - } else if ( - JSON.stringify(attributeSchema[Number(key)][1]) === - JSON.stringify('number') - ) { - // eslint-disable-next-line prefer-destructuring - attributes[attributeSchema[Number(key)][0]] = Number( - attributeSchema[Number(key)][2] - ); + if (obj.type === 'string') { + attributes[obj.tag] = obj.value; + } else if (obj.type === 'number') { + attributes[obj.tag] = BigInt(obj.value); } else { setParsingError( - `Attribute ${attributeSchema[Number(key)][0]} has type ${ - attributeSchema[Number(key)][1] - }. Only the types string/number are supported.` + `Attribute ${obj.tag} has type ${obj.type}. Only the types string/number are supported.` ); throw new Error( - `Attribute ${attributeSchema[Number(key)][0]} has type ${ - attributeSchema[Number(key)][1] - }. Only the types string/number are supported.` + `Attribute ${obj.tag} has type ${obj.type}. Only the types string/number are supported.` ); } }); @@ -732,7 +712,8 @@ export default function Main(props: WalletConnectionProps) { provider .addWeb3IdCredential( { - type: types.push(credentialType), + $schema: 'https://json-schema.org/draft/2020-12/schema', + type: [...types, credentialType], issuer: `did:ccd:testnet:sci:${credentialRegistryContratIndex}:0/issuer`, issuanceDate: new Date().toISOString(), credentialSubject: { attributes }, @@ -778,13 +759,13 @@ export default function Main(props: WalletConnectionProps) { const requestSignatureResponse = (await requestSignature( seed, - JSON.stringify(commitments) + stringify(commitments) )) as RequestSignatureResponse; const proofObject = { - type: 'Ed25519Signature2020', + type: 'Ed25519Signature2020' as const, verificationMethod: id, - proofPurpose: 'assertionMethod', + proofPurpose: 'assertionMethod' as const, proofValue: requestSignatureResponse.signedCommitments.signature, }; @@ -952,16 +933,16 @@ export default function Main(props: WalletConnectionProps) { > {attributeSchema.map((item) => (
- Add {item[0]}: + Add {item.tag}:
{ - handleAttributeChange(item[0], attributeSchema, event); + handleAttributeChange(item.tag, attributeSchema, event); }} />
@@ -1024,7 +1005,7 @@ export default function Main(props: WalletConnectionProps) { className="inputFieldStyle" id="credentialMetaDataURL" type="text" - placeholder="https://raw.githubusercontent.com/Concordium/concordium-web3id/credential-metadata-example/examples/json-schemas/metadata/credential-metadata.json" + placeholder={EXAMPLE_CREDENTIAL_METADATA} onChange={changeCredentialMetaDataURLHandler} />
@@ -1076,51 +1057,32 @@ export default function Main(props: WalletConnectionProps) { const attributes: Attribute = {}; - Object.keys(attributeSchema).forEach((key) => { - if (attributeSchema[Number(key)][2] === '') { - setParsingError( - `Attribute ${attributeSchema[Number(key)][0]} need to be set.` - ); - throw new Error( - `Attribute ${attributeSchema[Number(key)][0]} need to be set.` - ); + attributeSchema.forEach((obj) => { + if (obj.value === undefined) { + setParsingError(`Attribute ${obj.tag} needs to be set.`); + throw new Error(`Attribute ${obj.tag} needs to be set.`); } - if ( - JSON.stringify(attributeSchema[Number(key)][1]) === - JSON.stringify('string') - ) { - // eslint-disable-next-line prefer-destructuring - attributes[attributeSchema[Number(key)][0]] = - attributeSchema[Number(key)][2]; - } else if ( - JSON.stringify(attributeSchema[Number(key)][1]) === - JSON.stringify('number') - ) { - // eslint-disable-next-line prefer-destructuring - attributes[attributeSchema[Number(key)][0]] = Number( - attributeSchema[Number(key)][2] - ); + if (obj.type === 'string') { + attributes[obj.tag] = obj.value; + } else if (obj.type === 'number') { + attributes[obj.tag] = BigInt(obj.value); } else { setParsingError( - `Attribute ${attributeSchema[Number(key)][0]} has type ${ - attributeSchema[Number(key)][1] - }. Only the types string/number are supported.` + `Attribute ${obj.tag} has type ${obj.type}. Only the types string/number are supported.` ); throw new Error( - `Attribute ${attributeSchema[Number(key)][0]} has type ${ - attributeSchema[Number(key)][1] - }. Only the types string/number are supported.` + `Attribute ${obj.tag} has type ${obj.type}. Only the types string/number are supported.` ); } }); const types = Array.from(DEFAULT_CREDENTIAL_TYPES); - provider .addWeb3IdCredential( { - type: types.push(credentialType), + $schema: 'https://json-schema.org/draft/2020-12/schema', + type: [...types, credentialType], issuer: `did:ccd:testnet:sci:${credentialRegistryContratIndex}:0/issuer`, issuanceDate: new Date().toISOString(), credentialSubject: { attributes }, @@ -1151,13 +1113,13 @@ export default function Main(props: WalletConnectionProps) { const requestSignatureResponse = (await requestSignature( seed, - JSON.stringify(commitments) + stringify(commitments) )) as RequestSignatureResponse; const proofObject = { - type: 'Ed25519Signature2020', + type: 'Ed25519Signature2020' as const, verificationMethod: id, - proofPurpose: 'assertionMethod', + proofPurpose: 'assertionMethod' as const, proofValue: requestSignatureResponse.signedCommitments.signature, }; @@ -1237,16 +1199,16 @@ export default function Main(props: WalletConnectionProps) { > {attributeSchema.map((item) => (
- Add {item[0]}: + Add {item.tag}:
{ - handleAttributeChange(item[0], attributeSchema, event); + handleAttributeChange(item.tag, attributeSchema, event); }} />
@@ -1309,7 +1271,7 @@ export default function Main(props: WalletConnectionProps) { className="inputFieldStyle" id="credentialMetaDataURL" type="text" - placeholder="https://raw.githubusercontent.com/Concordium/concordium-web3id/credential-metadata-example/examples/json-schemas/metadata/credential-metadata.json" + placeholder={EXAMPLE_CREDENTIAL_METADATA} onChange={changeCredentialMetaDataURLHandler} />
@@ -1361,41 +1323,22 @@ export default function Main(props: WalletConnectionProps) { const attributes: Attribute = {}; - Object.keys(attributeSchema).forEach((key) => { - if (attributeSchema[Number(key)][2] === '') { - setParsingError( - `Attribute ${attributeSchema[Number(key)][0]} need to be set.` - ); - throw new Error( - `Attribute ${attributeSchema[Number(key)][0]} need to be set.` - ); + attributeSchema.forEach((obj) => { + if (obj.value === undefined) { + setParsingError(`Attribute ${obj.tag} needs to be set.`); + throw new Error(`Attribute ${obj.tag} needs to be set.`); } - if ( - JSON.stringify(attributeSchema[Number(key)][1]) === - JSON.stringify('string') - ) { - // eslint-disable-next-line prefer-destructuring - attributes[attributeSchema[Number(key)][0]] = - attributeSchema[Number(key)][2]; - } else if ( - JSON.stringify(attributeSchema[Number(key)][1]) === - JSON.stringify('number') - ) { - // eslint-disable-next-line prefer-destructuring - attributes[attributeSchema[Number(key)][0]] = Number( - attributeSchema[Number(key)][2] - ); + if (obj.type === 'string') { + attributes[obj.tag] = obj.value; + } else if (obj.type === 'number') { + attributes[obj.tag] = BigInt(obj.value); } else { setParsingError( - `Attribute ${attributeSchema[Number(key)][0]} has type ${ - attributeSchema[Number(key)][1] - }. Only the types string/number are supported.` + `Attribute ${obj.tag} has type ${obj.type}. Only the types string/number are supported.` ); throw new Error( - `Attribute ${attributeSchema[Number(key)][0]} has type ${ - attributeSchema[Number(key)][1] - }. Only the types string/number are supported.` + `Attribute ${obj.tag} has type ${obj.type}. Only the types string/number are supported.` ); } }); @@ -1405,7 +1348,8 @@ export default function Main(props: WalletConnectionProps) { provider .addWeb3IdCredential( { - type: types.push(credentialType), + $schema: 'https://json-schema.org/draft/2020-12/schema', + type: [...types, credentialType], issuer: `did:ccd:testnet:sci:${credentialRegistryContratIndex}:0/issuer`, issuanceDate: new Date().toISOString(), credentialSubject: { attributes }, @@ -1447,9 +1391,9 @@ export default function Main(props: WalletConnectionProps) { }; const proofObject = { - type: 'Ed25519Signature2020', + type: 'Ed25519Signature2020' as const, verificationMethod: id, - proofPurpose: 'assertionMethod', + proofPurpose: 'assertionMethod' as const, proofValue: 'e8c3944d6a9a19e74ad3ef028b04c0637756540306aba8842000f557cbfb7415187f907d26f20474081d4084fc8e5ff14167171f65fac76b06508ae46f55aa05', }; diff --git a/test-tools/issuer-front-end/src/constants.ts b/test-tools/issuer-front-end/src/constants.ts index c85022ab..ddc07b37 100644 --- a/test-tools/issuer-front-end/src/constants.ts +++ b/test-tools/issuer-front-end/src/constants.ts @@ -3,7 +3,7 @@ import moment from 'moment'; export const EXAMPLE_CREDENTIAL_SCHEMA = `https://raw.githubusercontent.com/Concordium/concordium-web3id/ac803895b1ffaa50888cfc6667331f6ebb0b889e/examples/json-schemas/education-certificate/JsonSchema2023-education-certificate.json`; -export const EXAMPLE_CREDENTIAL_METADATA = `https://raw.githubusercontent.com/Concordium/concordium-web3id/21bc43872c5d972f6c1b48af7956ec74f2e3e6ef/examples/json-schemas/metadata/credential-metadata.json`; +export const EXAMPLE_CREDENTIAL_METADATA = `https://gist.githubusercontent.com/abizjak/ff1e90d82c5446c0e001ee6d4e33ea6b/raw/4528363aff42e3ff36b50a1d873287f2f520d610/metadata.json`; export const EXAMPLE_ISSUER_METADATA = `https://gist.githubusercontent.com/DOBEN/d12deee42e06601efb72859da9be5759/raw/137a9a4b9623dfe16fa8e9bb7ab07f5858d92c53/gistfile1.txt`; diff --git a/test-tools/issuer-front-end/yarn.lock b/test-tools/issuer-front-end/yarn.lock index 48979d80..534e99f0 100644 --- a/test-tools/issuer-front-end/yarn.lock +++ b/test-tools/issuer-front-end/yarn.lock @@ -278,26 +278,6 @@ __metadata: languageName: node linkType: hard -"@concordium/common-sdk@npm:6.5.0": - version: 6.5.0 - resolution: "@concordium/common-sdk@npm:6.5.0" - dependencies: - "@concordium/rust-bindings": 0.11.1 - "@grpc/grpc-js": ^1.3.4 - "@noble/ed25519": ^1.7.1 - "@protobuf-ts/runtime-rpc": ^2.8.2 - "@scure/bip39": ^1.1.0 - bs58check: ^2.1.2 - buffer: ^6.0.3 - cross-fetch: 3.1.5 - hash.js: ^1.1.7 - iso-3166-1: ^2.1.1 - json-bigint: ^1.0.0 - uuid: ^8.3.2 - checksum: daf7e586b5fd89a4f2e84c602b9ffdbe5215a176b6673aa42abf7c54d722f5380f716672100f6a68c321ba97b87c381476bce768ff1e5299b5d07c6ded96e716 - languageName: node - linkType: hard - "@concordium/common-sdk@npm:9.1.0-alpha.1": version: 9.1.0-alpha.1 resolution: "@concordium/common-sdk@npm:9.1.0-alpha.1" @@ -329,13 +309,6 @@ __metadata: languageName: node linkType: hard -"@concordium/rust-bindings@npm:0.11.1": - version: 0.11.1 - resolution: "@concordium/rust-bindings@npm:0.11.1" - checksum: fe1bbcd0a98a7e148cfe9fa5ec69a693b19608b64b01723aedd9a7616958d5069cef006f8dfa610f7fad3cd3e8d356c99c76ff2606ea44d90138a43897118277 - languageName: node - linkType: hard - "@concordium/rust-bindings@npm:1.2.0-alpha.1": version: 1.2.0-alpha.1 resolution: "@concordium/rust-bindings@npm:1.2.0-alpha.1" @@ -354,20 +327,6 @@ __metadata: languageName: node linkType: hard -"@concordium/web-sdk@npm:^3.4.2": - version: 3.5.0 - resolution: "@concordium/web-sdk@npm:3.5.0" - dependencies: - "@concordium/common-sdk": 6.5.0 - "@concordium/rust-bindings": 0.11.1 - "@grpc/grpc-js": ^1.3.4 - "@protobuf-ts/grpcweb-transport": ^2.8.2 - buffer: ^6.0.3 - process: ^0.11.10 - checksum: 681cfdb2533bba93ac62f44b0fcf5596a0fd89a5895085e3e6a416fa162bc1d22ac3bc1a6f8b89a196c46e89e9fd6401c25c493079f406bf8dfa9c6a7eb0aaa7 - languageName: node - linkType: hard - "@concordium/web-sdk@npm:^6.1.0-alpha.1": version: 6.1.0-alpha.1 resolution: "@concordium/web-sdk@npm:6.1.0-alpha.1" @@ -5299,6 +5258,7 @@ cors@latest: eslint-plugin-react: ^7.29.4 eslint-plugin-react-hooks: ^4.4.0 fs: ^0.0.1-security + json-bigint: ^1.0.0 live-server: =1.2.1 moment: ^2.29.4 prettier: ^2.6.2 diff --git a/test-tools/web3id-test/Cargo.lock b/test-tools/web3id-test/Cargo.lock index a97bbc31..4779d1a2 100644 --- a/test-tools/web3id-test/Cargo.lock +++ b/test-tools/web3id-test/Cargo.lock @@ -3301,7 +3301,7 @@ dependencies = [ [[package]] name = "web3id-issuer" -version = "0.2.0" +version = "0.3.0" dependencies = [ "anyhow", "axum",