From 99c2ac8d524bfb6b38d930684519e203f387dec9 Mon Sep 17 00:00:00 2001 From: Abdulrahim Al Methiab Date: Mon, 29 Jul 2024 14:40:12 +0200 Subject: [PATCH 1/6] chore: update bundle test --- tests/bundle/bundle-test.ts | 476 ++++++++++++++---------------------- 1 file changed, 190 insertions(+), 286 deletions(-) diff --git a/tests/bundle/bundle-test.ts b/tests/bundle/bundle-test.ts index ca433f0c6..0d850b973 100644 --- a/tests/bundle/bundle-test.ts +++ b/tests/bundle/bundle-test.ts @@ -7,117 +7,29 @@ /// -import type { ApiPromise } from '@polkadot/api' -import type { - Did, - DidDocument, - DidUrl, - KiltAddress, - SignerInterface, - SubmittableExtrinsic, -} from '@kiltprotocol/types' +import { KiltAddress, SignerInterface } from '@kiltprotocol/types' const { kilt } = window +const Kilt = kilt -const { - ConfigService, - Issuer, - Verifier, - Holder, - DidResolver, - signAndSubmitTx, - getSignersForKeypair, -} = kilt +async function runAll() { + const api = await kilt.connect('ws://127.0.0.1:9944') -async function authorizeTx( - api: ApiPromise, - call: SubmittableExtrinsic, - did: string, - signer: SignerInterface, - submitter: string, - nonce = 1 -) { - let authorized = api.tx.did.submitDidCall( - { - did: did.slice(9), - call, - blockNumber: await api.query.system.number(), - submitter, - txCounter: nonce, + const didPublicKey = new Uint8Array([ + 136, 220, 52, 23, 213, 5, 142, 196, 180, 80, 62, 12, 18, 234, 26, 10, 137, + 190, 32, 15, 233, 137, 34, 66, 61, 67, 52, 1, 79, 166, 176, 238, + ]) + const [didKeypair] = await kilt.getSignersForKeypair({ + keypair: { + publicKey: didPublicKey, + secretKey: new Uint8Array([ + 171, 248, 229, 189, 190, 48, 198, 86, 86, 192, 163, 203, 209, 129, 255, + 138, 86, 41, 74, 105, 223, 237, 210, 121, 130, 170, 206, 74, 118, 144, + 145, 21, + ]), }, - { ed25519: new Uint8Array(64) } - ) - - const signature = await signer.sign({ data: authorized.args[0].toU8a() }) - - authorized = api.tx.did.submitDidCall(authorized.args[0].toU8a(), { - ed25519: signature, - }) - - return authorized -} - -async function createFullDid( - payer: SignerInterface<'Ed25519' | 'Sr25519', KiltAddress>, - keypair: { publicKey: Uint8Array; secretKey: Uint8Array } -) { - const api = ConfigService.get('api') - - const [signer] = await getSignersForKeypair({ - keypair, type: 'Ed25519', }) - const address = signer.id - const getSigners: ( - didDocument: DidDocument - ) => Array> = (didDocument) => { - return ( - didDocument.verificationMethod?.map< - Array> - >(({ id }) => [ - { - ...signer, - id, - }, - ]) ?? [] - ).flat() - } - - let tx = api.tx.did.create( - { - did: address, - submitter: payer.id, - newAttestationKey: { ed25519: keypair.publicKey }, - }, - { ed25519: new Uint8Array(64) } - ) - - const signature = await signer.sign({ data: tx.args[0].toU8a() }) - tx = api.tx.did.create(tx.args[0].toU8a(), { ed25519: signature }) - - await signAndSubmitTx(tx, payer) - - const { didDocument } = await DidResolver.resolve( - `did:kilt:${address}` as Did, - {} - ) - if (!didDocument) { - throw new Error(`failed to create did for account ${address}`) - } - - return { - didDocument, - getSigners, - address, - } -} - -async function runAll() { - // init sdk kilt config and connect to chain - const api = await kilt.connect('ws://127.0.0.1:9944') - - // Accounts - console.log('Account setup started') const faucet = { publicKey: new Uint8Array([ 238, 93, 102, 137, 215, 142, 38, 187, 91, 53, 176, 68, 23, 64, 160, 101, @@ -129,214 +41,206 @@ async function runAll() { 3, ]), } - const [payerSigner] = (await getSignersForKeypair({ + + const [submitter] = (await kilt.getSignersForKeypair({ keypair: faucet, type: 'Ed25519', })) as Array> - console.log('faucet signer created') - - const { didDocument: alice, getSigners: aliceSign } = await createFullDid( - payerSigner, - { - publicKey: new Uint8Array([ - 136, 220, 52, 23, 213, 5, 142, 196, 180, 80, 62, 12, 18, 234, 26, 10, - 137, 190, 32, 15, 233, 137, 34, 66, 61, 67, 52, 1, 79, 166, 176, 238, - ]), - secretKey: new Uint8Array([ - 171, 248, 229, 189, 190, 48, 198, 86, 86, 192, 163, 203, 209, 129, 255, - 138, 86, 41, 74, 105, 223, 237, 210, 121, 130, 170, 206, 74, 118, 144, - 145, 21, - ]), - } - ) - console.log('alice setup done') - - const { didDocument: bob, getSigners: bobSign } = await createFullDid( - payerSigner, - { - publicKey: new Uint8Array([ - 209, 124, 45, 120, 35, 235, 242, 96, 253, 19, 143, 45, 126, 39, 209, 20, - 192, 20, 93, 150, 139, 95, 245, 0, 97, 37, 242, 65, 79, 173, 174, 105, - ]), - secretKey: new Uint8Array([ - 59, 123, 96, 175, 42, 188, 213, 123, 164, 1, 171, 57, 143, 132, 244, - 202, 84, 189, 107, 33, 64, 210, 80, 63, 188, 243, 40, 101, 53, 254, 63, - 241, - ]), - } - ) - - console.log('bob setup done') + // ┏━━━━━━━━━━━━┓ + // ┃ create DID ┃ + // ┗━━━━━━━━━━━━┛ + // + // Generate the DID-signed creation tx and submit it to the blockchain with the specified account. + // The DID Document will have one Verification Key with an authentication relationship. + // + // Note the following parameters: + // - `api`: The connected blockchain api. + // - `signers`: The keys for verification materials inside the DID Document. For creating a DID, + // only the key for the verification method is required. + // - `submitter`: The account used to submit the transaction to the blockchain. Note: the submitter account must have + // enough funds to cover the required storage deposit. + // - `fromPublicKey`: The public key that will feature as the DID's initial authentication method and will determine the DID identifier. + + const transactionHandler = Kilt.DidHelpers.createDid({ + api, + signers: [didKeypair], + submitter, + fromPublicKey: { publicKey: didPublicKey, type: 'ed25519' }, + }) - // Light DID Account creation workflow - const authPublicKey = - '0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + // The `createDid` function returns a transaction handler, which includes two methods: + // - `submit`: Submits a transaction for inclusion in a block, resulting in its execution in the blockchain runtime. + // - `getSubmittable`: Produces transaction that can be submitted to a blockchain node for inclusion, or signed and submitted by an external service. - // const encPublicKey = - // '0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' + // Submit transaction. + // Note: `submit()` by default, waits for the block to be finalized. This behaviour can be overwritten + // in the function's optional parameters. + const didDocumentTransactionResult = await transactionHandler.submit() - const address = api.createType('Address', authPublicKey).toString() - const resolved = await DidResolver.resolve( - `did:kilt:light:01${address}:z1Ac9CMtYCTRWjetJfJqJoV7FcPDD9nHPHDHry7t3KZmvYe1HQP1tgnBuoG3enuGaowpF8V88sCxytDPDy6ZxhW` as Did, - {} - ) - if ( - !resolved.didDocument || - resolved.didDocument?.keyAgreement?.length !== 1 - ) { - throw new Error('DID Test Unsuccessful') - } else console.info(`light DID successfully resolved`) + // Once the transaction is submitted, the result should be checked. + // For the sake of this example, we will only check if the transaction went through. + if (didDocumentTransactionResult.status !== 'confirmed') { + throw new Error('create DID failed') + } - // Chain DID workflow -> creation & deletion - console.log('DID workflow started') - const { - didDocument: fullDid, - getSigners, - address: didAddress, - } = await createFullDid(payerSigner, { - publicKey: new Uint8Array([ - 157, 198, 166, 93, 125, 173, 238, 122, 17, 146, 49, 238, 62, 111, 140, 45, - 26, 6, 94, 42, 60, 167, 79, 19, 142, 20, 212, 5, 130, 44, 214, 190, - ]), - secretKey: new Uint8Array([ - 252, 195, 96, 143, 203, 194, 37, 74, 205, 243, 137, 71, 234, 82, 57, 46, - 212, 14, 113, 177, 1, 241, 62, 118, 184, 230, 121, 219, 17, 45, 36, 143, - ]), + // Get the DID Document from the transaction result. + let { didDocument } = didDocumentTransactionResult.asConfirmed + + // ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ + // ┃ Create Verification Method ┃ + // ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ + // + // - `DidHelpers` include a function to add a verification methods. + // Similar to `createDid`, setting a verification method requires some parameters. + // + // - `didDocument` is the latest state of the DID Document that shall be updated. + // - `signers` includes all the keypairs included in the DID documents and necessary for the + // specified operation, in this case, the keypair of the authentication key, which is necessary to + // allow updates to the DID Document. + // - `publicKey` is the key used for the verification method. + // + // Note: setting a verification method will remove any existing method for the specified relationship. + + // TODO: use mnemonic here. + // const seed = randomAsU8a(32) + // const keyAgreementKeypair = Crypto.makeEncryptionKeypairFromSeed(seed) + const keyAgreementKeypair = Kilt.generateKeypair({ + type: 'x25519', }) - - if ( - fullDid.authentication?.length === 1 && - fullDid.assertionMethod?.length === 1 && - fullDid.id.endsWith(didAddress) - ) { - console.info('DID matches') - } else { - throw new Error('DIDs do not match') + const vmTransactionResult = await Kilt.DidHelpers.setVerificationMethod({ + api, + didDocument, + signers: [didKeypair], + submitter, + publicKey: keyAgreementKeypair, + relationship: 'keyAgreement', + }).submit() + + if (vmTransactionResult.status !== 'confirmed') { + throw new Error('add verification method failed') } + ;({ didDocument } = vmTransactionResult.asConfirmed) - const deleteTx = await authorizeTx( + // ┏━━━━━━━━━━━━━━━━━┓ + // ┃ Claim web3name ┃ + // ┗━━━━━━━━━━━━━━━━━┛ + const claimW3nTransactionResult = await Kilt.DidHelpers.claimWeb3Name({ api, - api.tx.did.delete(0), - fullDid.id, - getSigners(fullDid)[0], - payerSigner.id - ) - - await signAndSubmitTx(deleteTx, payerSigner) + didDocument, + submitter, + signers: [didKeypair], + name: 'example123', + }).submit() - const resolvedAgain = await DidResolver.resolve(fullDid.id, {}) - if (resolvedAgain.didDocumentMetadata.deactivated) { - console.info('DID successfully deleted') - } else { - throw new Error('DID was not deleted') + if (claimW3nTransactionResult.status !== 'confirmed') { + throw new Error('claim web3name failed') } - // CType workflow - console.log('CType workflow started') - const DriversLicenseDef = - '{"$schema":"ipfs://bafybeiah66wbkhqbqn7idkostj2iqyan2tstc4tpqt65udlhimd7hcxjyq/","additionalProperties":false,"properties":{"age":{"type":"integer"},"name":{"type":"string"}},"title":"Drivers License","type":"object"}' + // TODO: does the DID Document change after adding a w3n? + ;({ didDocument } = claimW3nTransactionResult.asConfirmed) - const cTypeStoreTx = await authorizeTx( + // ┏━━━━━━━━━━━━━━━━┓ + // ┃ Add a service ┃ + // ┗━━━━━━━━━━━━━━━━┛ + const addServiceTransactionResult = await Kilt.DidHelpers.addService({ api, - api.tx.ctype.add(DriversLicenseDef), - alice.id, - aliceSign(alice)[0], - payerSigner.id - ) - - const result = await signAndSubmitTx(cTypeStoreTx, payerSigner) - - const ctypeHash = result.events - ?.find((ev) => api.events.ctype.CTypeCreated.is(ev.event)) - ?.event.data[1].toHex() + submitter, + signers: [didKeypair], + didDocument, + // TODO: change service endpoint. + service: { + id: '#my_service', + type: ['http://schema.org/EmailService'], + serviceEndpoint: ['mailto:info@kilt.io'], + }, + }).submit() - if (!ctypeHash || !(await api.query.ctype.ctypes(ctypeHash)).isSome) { - throw new Error('storing ctype failed') + if (addServiceTransactionResult.status !== 'confirmed') { + throw new Error('add service failed') } + ;({ didDocument } = addServiceTransactionResult.asConfirmed) + + // ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ + // ┃ Remove a Verification Method ┃ + // ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ + // + // Removing a verification method can be done by specifying its id. + // + // Note: + // - The provided `didDocument` must include the specified verification method. + // - The authentication verification method can not be removed. + const removeVmTransactionResult = + await Kilt.DidHelpers.removeVerificationMethod({ + api, + didDocument, + signers: [didKeypair], + submitter, + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + verificationMethodId: didDocument.keyAgreement![0], + relationship: 'keyAgreement', + }).submit() - const DriversLicense = JSON.parse(DriversLicenseDef) - DriversLicense.$id = `kilt:ctype:${ctypeHash}` - - console.info('CType successfully stored on chain') - - // Attestation workflow - console.log('Attestation workflow started') - const credentialSubject = { id: bob.id, name: 'Bob', age: 21 } - - const credential = await Issuer.createCredential({ - cType: DriversLicense, - credentialSubject, - issuer: alice.id, - }) - - console.info('Credential subject conforms to CType') - - if ( - credential.credentialSubject.name !== credentialSubject.name || - credential.credentialSubject.age !== credentialSubject.age || - credential.credentialSubject.id !== bob.id - ) { - throw new Error('Claim content inside Credential mismatching') + if (removeVmTransactionResult.status !== 'confirmed') { + throw new Error('remove verification method failed') } + ;({ didDocument } = removeVmTransactionResult.asConfirmed) + + // ┏━━━━━━━━━━━━━━━━━━┓ + // ┃ Release web3name ┃ + // ┗━━━━━━━━━━━━━━━━━━┛ + // + // A web3name can be released from a DID and potentially claimed by another DID. + const releaseW3nTransactionResult = await Kilt.DidHelpers.releaseWeb3Name({ + api, + didDocument, + submitter, + signers: [didKeypair], + }).submit() - const issued = await Issuer.issue(credential, { - didDocument: alice, - signers: [...aliceSign(alice), payerSigner], - submitter: payerSigner.id, - }) - console.info('Credential issued') - - const credentialResult = await Verifier.verifyCredential({ - credential: issued, - config: { - cTypes: [DriversLicense], - }, - }) - - if (credentialResult.verified) { - console.info('Credential proof verified') - console.info('Credential status verified') - } else { - throw new Error(`Credential failed to verify: ${credentialResult.error}`, { - cause: credentialResult, - }) + if (releaseW3nTransactionResult.status !== 'confirmed') { + throw new Error('release web3name failed') } + ;({ didDocument } = releaseW3nTransactionResult.asConfirmed) + + // ┏━━━━━━━━━━━━━━━━━━┓ + // ┃ Remove a service ┃ + // ┗━━━━━━━━━━━━━━━━━━┛ + // + // Services can be removed by specifying the service `id` + const removeServiceTransactionResult = await Kilt.DidHelpers.removeService({ + api, + submitter, + signers: [didKeypair], + didDocument, + id: '#my_service', + }).submit() - const challenge = crypto.randomUUID() - - const derived = await Holder.deriveProof(issued, { - disclose: { allBut: ['/credentialSubject/name'] }, - }) - - const presentation = await Holder.createPresentation( - [derived], - { - didDocument: bob, - signers: bobSign(bob), - }, - {}, - { - challenge, - } - ) - console.info('Presentation created') + if (removeServiceTransactionResult.status !== 'confirmed') { + throw new Error('remove service failed') + } + ;({ didDocument } = removeServiceTransactionResult.asConfirmed) + + // ┏━━━━━━━━━━━━━━━━━━┓ + // ┃ Deactivate a DID ┃ + // ┗━━━━━━━━━━━━━━━━━━┛ + // + // _Permanently_ deactivate the DID, removing all verification methods and services from its document. + // Deactivating a DID cannot be undone, once a DID has been deactivated, all operations on it (including attempts at re-creation) are permanently disabled. + const deactivateDidTransactionResult = await Kilt.DidHelpers.deactivateDid({ + api, + submitter, + signers: [didKeypair], + didDocument, + }).submit() - const presentationResult = await Verifier.verifyPresentation({ - presentation, - verificationCriteria: { challenge }, - }) - if (presentationResult.verified) { - console.info('Presentation verified') - } else { - throw new Error( - [ - 'Presentation failed to verify', - ...(presentationResult.error ?? []), - ].join('\n '), - { cause: presentationResult } - ) + if (deactivateDidTransactionResult.status !== 'confirmed') { + throw new Error('deactivate DID failed') } + ;({ didDocument } = deactivateDidTransactionResult.asConfirmed) + + // Release the connection to the blockchain. + await api.disconnect() } window.runAll = runAll From 542348419d52305bca2f76fe3cc7011b0ceaa2f6 Mon Sep 17 00:00:00 2001 From: Raphael Flechtner Date: Tue, 30 Jul 2024 14:16:46 +0200 Subject: [PATCH 2/6] test: add bundle tests for issuance & verification --- tests/bundle/bundle-test.ts | 159 ++++++++++++++++++++++++++++-------- 1 file changed, 124 insertions(+), 35 deletions(-) diff --git a/tests/bundle/bundle-test.ts b/tests/bundle/bundle-test.ts index 0d850b973..0d52c73c0 100644 --- a/tests/bundle/bundle-test.ts +++ b/tests/bundle/bundle-test.ts @@ -15,21 +15,8 @@ const Kilt = kilt async function runAll() { const api = await kilt.connect('ws://127.0.0.1:9944') - const didPublicKey = new Uint8Array([ - 136, 220, 52, 23, 213, 5, 142, 196, 180, 80, 62, 12, 18, 234, 26, 10, 137, - 190, 32, 15, 233, 137, 34, 66, 61, 67, 52, 1, 79, 166, 176, 238, - ]) - const [didKeypair] = await kilt.getSignersForKeypair({ - keypair: { - publicKey: didPublicKey, - secretKey: new Uint8Array([ - 171, 248, 229, 189, 190, 48, 198, 86, 86, 192, 163, 203, 209, 129, 255, - 138, 86, 41, 74, 105, 223, 237, 210, 121, 130, 170, 206, 74, 118, 144, - 145, 21, - ]), - }, - type: 'Ed25519', - }) + const authenticationKeyPair = kilt.generateKeypair({ type: 'ed25519' }) + const faucet = { publicKey: new Uint8Array([ 238, 93, 102, 137, 215, 142, 38, 187, 91, 53, 176, 68, 23, 64, 160, 101, @@ -64,9 +51,9 @@ async function runAll() { const transactionHandler = Kilt.DidHelpers.createDid({ api, - signers: [didKeypair], + signers: [authenticationKeyPair], submitter, - fromPublicKey: { publicKey: didPublicKey, type: 'ed25519' }, + fromPublicKey: authenticationKeyPair.publicKeyMultibase, }) // The `createDid` function returns a transaction handler, which includes two methods: @@ -85,7 +72,7 @@ async function runAll() { } // Get the DID Document from the transaction result. - let { didDocument } = didDocumentTransactionResult.asConfirmed + let { didDocument, signers } = didDocumentTransactionResult.asConfirmed // ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ // ┃ Create Verification Method ┃ @@ -103,24 +90,22 @@ async function runAll() { // Note: setting a verification method will remove any existing method for the specified relationship. // TODO: use mnemonic here. - // const seed = randomAsU8a(32) - // const keyAgreementKeypair = Crypto.makeEncryptionKeypairFromSeed(seed) - const keyAgreementKeypair = Kilt.generateKeypair({ - type: 'x25519', + const assertionKeyPair = Kilt.generateKeypair({ + type: 'sr25519', }) const vmTransactionResult = await Kilt.DidHelpers.setVerificationMethod({ api, didDocument, - signers: [didKeypair], + signers: [...signers, assertionKeyPair], submitter, - publicKey: keyAgreementKeypair, - relationship: 'keyAgreement', + publicKey: assertionKeyPair.publicKeyMultibase, + relationship: 'assertionMethod', }).submit() if (vmTransactionResult.status !== 'confirmed') { throw new Error('add verification method failed') } - ;({ didDocument } = vmTransactionResult.asConfirmed) + ;({ didDocument, signers } = vmTransactionResult.asConfirmed) // ┏━━━━━━━━━━━━━━━━━┓ // ┃ Claim web3name ┃ @@ -129,7 +114,7 @@ async function runAll() { api, didDocument, submitter, - signers: [didKeypair], + signers, name: 'example123', }).submit() @@ -137,7 +122,7 @@ async function runAll() { throw new Error('claim web3name failed') } - // TODO: does the DID Document change after adding a w3n? + // The didDocument now contains an `alsoKnownAs` entry. ;({ didDocument } = claimW3nTransactionResult.asConfirmed) // ┏━━━━━━━━━━━━━━━━┓ @@ -146,7 +131,7 @@ async function runAll() { const addServiceTransactionResult = await Kilt.DidHelpers.addService({ api, submitter, - signers: [didKeypair], + signers, didDocument, // TODO: change service endpoint. service: { @@ -161,6 +146,110 @@ async function runAll() { } ;({ didDocument } = addServiceTransactionResult.asConfirmed) + // ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ + // ┃ Register a CType ┃ + // ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ + // + // Register a credential type on chain so we can issue credentials against it. + // + // Note: + // We are registering a CType that has been created previously using functionality from the @kiltprotocol/credentials package. + // The @kiltprotocol/sdk-js package and bundle do not currently offer support for this. + // + // TODO: Decide if CType definitions are expected to be hardcoded in application logic, at least for credential issuance. + // Verifying credentials / presentations is already possible even if the CType definition is not known. + // + const DriversLicenseDef = + '{"$schema":"ipfs://bafybeiah66wbkhqbqn7idkostj2iqyan2tstc4tpqt65udlhimd7hcxjyq/","additionalProperties":false,"properties":{"age":{"type":"integer"},"name":{"type":"string"}},"title":"Drivers License","type":"object"}' + + const createCTypeResult = await Kilt.DidHelpers.transact({ + api, + didDocument, + signers, + submitter, + call: api.tx.ctype.add(DriversLicenseDef), + expectedEvents: [{ section: 'CType', method: 'CTypeCreated' }], + }).submit() + + if (createCTypeResult.status !== 'confirmed') { + throw new Error('CType creation failed') + } + + // TODO: We don't have the CType id in the definition, so we need to get it from the events. + const ctypeHash = createCTypeResult.asConfirmed.events + .find((event) => api.events.ctype.CTypeCreated.is(event)) + ?.data[1].toHex() + + // TODO: Should we at least be able to load an existing CType from the chain? + const DriversLicense = JSON.parse(DriversLicenseDef) + DriversLicense.$id = `kilt:ctype:${ctypeHash}` + + // ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ + // ┃ Issue a Credential ┃ + // ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ + // + // Create and issue a credential using our Did. + // The holder is also our Did, so we are issuing to ourselves here. + // + const unsigned = await kilt.Issuer.createCredential({ + issuer: didDocument.id, + credentialSubject: { + id: didDocument.id, + age: 22, + name: 'Gustav', + }, + cType: DriversLicense, + }) + + const credential = await kilt.Issuer.issue(unsigned, { + didDocument, + signers: [...signers, submitter], + submitter: submitter.id, + }) + + // ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ + // ┃ Create a Presentation ┃ + // ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ + // + // Create a derived credential that only contains selected properties (selective disclosure), then create a credential presentation for it. + // The presentation includes a proof of ownership and is scoped to a verified and time frame to prevent unauthorized re-use. + // + const derived = await kilt.Holder.deriveProof(credential, { + disclose: { only: ['/credentialSubject/age'] }, + }) + + const presentation = await kilt.Holder.createPresentation( + [derived], + { + didDocument, + signers, + }, + { verifier: didDocument.id, validUntil: new Date(Date.now() + 100_000) } + ) + + // ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ + // ┃ Verify a Presentation ┃ + // ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ + // + // Verify a presentation. + // + // Verification would fail if: + // - The presentation is not signed by the holder's Did. + // - The current time is outside of the validity time frame of the presentation. + // - The verifier in the presentation does not match the one specified. + // + const { verified, error } = await kilt.Verifier.verifyPresentation({ + presentation, + verificationCriteria: { + verifier: didDocument.id, + proofPurpose: 'authentication', + }, + }) + + if (verified !== true) { + throw new Error(`failed to verify credential: ${JSON.stringify(error)}`) + } + // ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ // ┃ Remove a Verification Method ┃ // ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ @@ -174,11 +263,11 @@ async function runAll() { await Kilt.DidHelpers.removeVerificationMethod({ api, didDocument, - signers: [didKeypair], + signers, submitter, // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - verificationMethodId: didDocument.keyAgreement![0], - relationship: 'keyAgreement', + verificationMethodId: didDocument.assertionMethod![0], + relationship: 'assertionMethod', }).submit() if (removeVmTransactionResult.status !== 'confirmed') { @@ -195,7 +284,7 @@ async function runAll() { api, didDocument, submitter, - signers: [didKeypair], + signers, }).submit() if (releaseW3nTransactionResult.status !== 'confirmed') { @@ -211,7 +300,7 @@ async function runAll() { const removeServiceTransactionResult = await Kilt.DidHelpers.removeService({ api, submitter, - signers: [didKeypair], + signers, didDocument, id: '#my_service', }).submit() @@ -230,7 +319,7 @@ async function runAll() { const deactivateDidTransactionResult = await Kilt.DidHelpers.deactivateDid({ api, submitter, - signers: [didKeypair], + signers, didDocument, }).submit() From ea89805c713ac0be93da71341862922e93ee5c5b Mon Sep 17 00:00:00 2001 From: Raphael Flechtner Date: Tue, 30 Jul 2024 14:19:22 +0200 Subject: [PATCH 3/6] test: upper-case Kilt in bundle tests --- tests/bundle/bundle-test.ts | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/tests/bundle/bundle-test.ts b/tests/bundle/bundle-test.ts index 0d52c73c0..1c973e126 100644 --- a/tests/bundle/bundle-test.ts +++ b/tests/bundle/bundle-test.ts @@ -9,13 +9,12 @@ import { KiltAddress, SignerInterface } from '@kiltprotocol/types' -const { kilt } = window -const Kilt = kilt +const { kilt: Kilt } = window async function runAll() { - const api = await kilt.connect('ws://127.0.0.1:9944') + const api = await Kilt.connect('ws://127.0.0.1:9944') - const authenticationKeyPair = kilt.generateKeypair({ type: 'ed25519' }) + const authenticationKeyPair = Kilt.generateKeypair({ type: 'ed25519' }) const faucet = { publicKey: new Uint8Array([ @@ -29,7 +28,7 @@ async function runAll() { ]), } - const [submitter] = (await kilt.getSignersForKeypair({ + const [submitter] = (await Kilt.getSignersForKeypair({ keypair: faucet, type: 'Ed25519', })) as Array> @@ -191,7 +190,7 @@ async function runAll() { // Create and issue a credential using our Did. // The holder is also our Did, so we are issuing to ourselves here. // - const unsigned = await kilt.Issuer.createCredential({ + const unsigned = await Kilt.Issuer.createCredential({ issuer: didDocument.id, credentialSubject: { id: didDocument.id, @@ -201,7 +200,7 @@ async function runAll() { cType: DriversLicense, }) - const credential = await kilt.Issuer.issue(unsigned, { + const credential = await Kilt.Issuer.issue(unsigned, { didDocument, signers: [...signers, submitter], submitter: submitter.id, @@ -214,11 +213,11 @@ async function runAll() { // Create a derived credential that only contains selected properties (selective disclosure), then create a credential presentation for it. // The presentation includes a proof of ownership and is scoped to a verified and time frame to prevent unauthorized re-use. // - const derived = await kilt.Holder.deriveProof(credential, { + const derived = await Kilt.Holder.deriveProof(credential, { disclose: { only: ['/credentialSubject/age'] }, }) - const presentation = await kilt.Holder.createPresentation( + const presentation = await Kilt.Holder.createPresentation( [derived], { didDocument, @@ -238,7 +237,7 @@ async function runAll() { // - The current time is outside of the validity time frame of the presentation. // - The verifier in the presentation does not match the one specified. // - const { verified, error } = await kilt.Verifier.verifyPresentation({ + const { verified, error } = await Kilt.Verifier.verifyPresentation({ presentation, verificationCriteria: { verifier: didDocument.id, From ccf266046d4e661fca99a579bf04b120beed1dab Mon Sep 17 00:00:00 2001 From: Raphael Flechtner Date: Tue, 30 Jul 2024 14:59:21 +0200 Subject: [PATCH 4/6] test: add logging to bundle tests --- tests/bundle/bundle-test.ts | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/tests/bundle/bundle-test.ts b/tests/bundle/bundle-test.ts index 1c973e126..9577253ee 100644 --- a/tests/bundle/bundle-test.ts +++ b/tests/bundle/bundle-test.ts @@ -7,13 +7,15 @@ /// -import { KiltAddress, SignerInterface } from '@kiltprotocol/types' +import type { KiltAddress, SignerInterface } from '@kiltprotocol/types' const { kilt: Kilt } = window async function runAll() { const api = await Kilt.connect('ws://127.0.0.1:9944') + console.log('connected') + const authenticationKeyPair = Kilt.generateKeypair({ type: 'ed25519' }) const faucet = { @@ -33,6 +35,8 @@ async function runAll() { type: 'Ed25519', })) as Array> + console.log('keypair generation complete') + // ┏━━━━━━━━━━━━┓ // ┃ create DID ┃ // ┗━━━━━━━━━━━━┛ @@ -73,6 +77,8 @@ async function runAll() { // Get the DID Document from the transaction result. let { didDocument, signers } = didDocumentTransactionResult.asConfirmed + console.log('Did created') + // ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ // ┃ Create Verification Method ┃ // ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ @@ -106,6 +112,8 @@ async function runAll() { } ;({ didDocument, signers } = vmTransactionResult.asConfirmed) + console.log('assertion method added') + // ┏━━━━━━━━━━━━━━━━━┓ // ┃ Claim web3name ┃ // ┗━━━━━━━━━━━━━━━━━┛ @@ -124,6 +132,8 @@ async function runAll() { // The didDocument now contains an `alsoKnownAs` entry. ;({ didDocument } = claimW3nTransactionResult.asConfirmed) + console.log('w3n claimed') + // ┏━━━━━━━━━━━━━━━━┓ // ┃ Add a service ┃ // ┗━━━━━━━━━━━━━━━━┛ @@ -145,6 +155,8 @@ async function runAll() { } ;({ didDocument } = addServiceTransactionResult.asConfirmed) + console.log('service added') + // ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ // ┃ Register a CType ┃ // ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ @@ -183,6 +195,8 @@ async function runAll() { const DriversLicense = JSON.parse(DriversLicenseDef) DriversLicense.$id = `kilt:ctype:${ctypeHash}` + console.log('CType registered') + // ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ // ┃ Issue a Credential ┃ // ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ @@ -206,6 +220,8 @@ async function runAll() { submitter: submitter.id, }) + console.log('credential issued') + // ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ // ┃ Create a Presentation ┃ // ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ @@ -226,6 +242,8 @@ async function runAll() { { verifier: didDocument.id, validUntil: new Date(Date.now() + 100_000) } ) + console.log('presentation created') + // ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ // ┃ Verify a Presentation ┃ // ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ @@ -249,6 +267,8 @@ async function runAll() { throw new Error(`failed to verify credential: ${JSON.stringify(error)}`) } + console.log('presentation verified') + // ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ // ┃ Remove a Verification Method ┃ // ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ @@ -274,6 +294,8 @@ async function runAll() { } ;({ didDocument } = removeVmTransactionResult.asConfirmed) + console.log('assertion method removed') + // ┏━━━━━━━━━━━━━━━━━━┓ // ┃ Release web3name ┃ // ┗━━━━━━━━━━━━━━━━━━┛ @@ -291,6 +313,8 @@ async function runAll() { } ;({ didDocument } = releaseW3nTransactionResult.asConfirmed) + console.log('w3n released') + // ┏━━━━━━━━━━━━━━━━━━┓ // ┃ Remove a service ┃ // ┗━━━━━━━━━━━━━━━━━━┛ @@ -309,6 +333,8 @@ async function runAll() { } ;({ didDocument } = removeServiceTransactionResult.asConfirmed) + console.log('service removed') + // ┏━━━━━━━━━━━━━━━━━━┓ // ┃ Deactivate a DID ┃ // ┗━━━━━━━━━━━━━━━━━━┛ @@ -327,8 +353,16 @@ async function runAll() { } ;({ didDocument } = deactivateDidTransactionResult.asConfirmed) + if (Array.isArray(didDocument.verificationMethod)) { + throw new Error('Did not deactivated') + } + + console.log('Did deactivated') + // Release the connection to the blockchain. await api.disconnect() + + console.log('disconnected') } window.runAll = runAll From 3c65a651993f413daf9300e9f32ed829429f2923 Mon Sep 17 00:00:00 2001 From: Raphael Flechtner Date: Tue, 30 Jul 2024 15:12:46 +0200 Subject: [PATCH 5/6] test: check ctype being registered --- tests/bundle/bundle-test.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/bundle/bundle-test.ts b/tests/bundle/bundle-test.ts index 9577253ee..56d7f77e4 100644 --- a/tests/bundle/bundle-test.ts +++ b/tests/bundle/bundle-test.ts @@ -191,6 +191,10 @@ async function runAll() { .find((event) => api.events.ctype.CTypeCreated.is(event)) ?.data[1].toHex() + if ((await api.query.ctype.ctypes(ctypeHash)).isEmpty) { + throw new Error('CType not registered') + } + // TODO: Should we at least be able to load an existing CType from the chain? const DriversLicense = JSON.parse(DriversLicenseDef) DriversLicense.$id = `kilt:ctype:${ctypeHash}` From adfc479495127cdb55e4f6f4c86f8f32a7fb454a Mon Sep 17 00:00:00 2001 From: Abdulrahim Al Methiab <31316147+abdulmth@users.noreply.github.com> Date: Wed, 31 Jul 2024 10:16:32 +0200 Subject: [PATCH 6/6] fix documentation --- tests/bundle/bundle-test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/bundle/bundle-test.ts b/tests/bundle/bundle-test.ts index 56d7f77e4..53a72289f 100644 --- a/tests/bundle/bundle-test.ts +++ b/tests/bundle/bundle-test.ts @@ -47,7 +47,7 @@ async function runAll() { // Note the following parameters: // - `api`: The connected blockchain api. // - `signers`: The keys for verification materials inside the DID Document. For creating a DID, - // only the key for the verification method is required. + // only the key for the authentication verification method is required. // - `submitter`: The account used to submit the transaction to the blockchain. Note: the submitter account must have // enough funds to cover the required storage deposit. // - `fromPublicKey`: The public key that will feature as the DID's initial authentication method and will determine the DID identifier.