diff --git a/examples/cactus-example-discounted-asset-trade-client/package.json b/examples/cactus-example-discounted-asset-trade-client/package.json index ec0a6105c27..8e607ebd6cd 100644 --- a/examples/cactus-example-discounted-asset-trade-client/package.json +++ b/examples/cactus-example-discounted-asset-trade-client/package.json @@ -50,6 +50,7 @@ "@hyperledger/anoncreds-nodejs": "^0.2.0-dev.4", "@hyperledger/aries-askar-nodejs": "^0.2.0-dev.1", "@hyperledger/indy-vdr-nodejs": "^0.2.0-dev.3", + "inquirer": "^8.2.6", "loglevel": "^1.8.1" }, "devDependencies": { @@ -65,8 +66,7 @@ "@types/indy-sdk": "^1.16.26", "@types/inquirer": "^8.2.6", "clear": "^0.1.0", - "figlet": "^1.5.2", - "ts-node": "^10.4.0" + "figlet": "^1.5.2" }, "engines": { "node": ">=18", diff --git a/examples/cactus-example-discounted-asset-trade-client/src/main/typescript/index.ts b/examples/cactus-example-discounted-asset-trade-client/src/main/typescript/index.ts new file mode 100755 index 00000000000..87cb558397c --- /dev/null +++ b/examples/cactus-example-discounted-asset-trade-client/src/main/typescript/index.ts @@ -0,0 +1 @@ +export * from "./public-api"; diff --git a/examples/cactus-example-discounted-asset-trade-client/src/main/typescript/lib/agent-setup.ts b/examples/cactus-example-discounted-asset-trade-client/src/main/typescript/lib/agent-setup.ts index 2e55931bfdc..d2139ce127c 100644 --- a/examples/cactus-example-discounted-asset-trade-client/src/main/typescript/lib/agent-setup.ts +++ b/examples/cactus-example-discounted-asset-trade-client/src/main/typescript/lib/agent-setup.ts @@ -219,6 +219,7 @@ export async function createAliceAgent() { const agent = await setupAgent(ALICE_AGENT_NAME, ALICE_AGENT_PORT); setupCredentialListener(agent); setupProofListener(agent); + // TOdo - connect listener with logs return agent; } diff --git a/examples/cactus-example-discounted-asset-trade-client/src/main/typescript/lib/credentials.ts b/examples/cactus-example-discounted-asset-trade-client/src/main/typescript/lib/credentials.ts index a75c2877b4f..0089879a0cd 100644 --- a/examples/cactus-example-discounted-asset-trade-client/src/main/typescript/lib/credentials.ts +++ b/examples/cactus-example-discounted-asset-trade-client/src/main/typescript/lib/credentials.ts @@ -223,3 +223,22 @@ export async function issueCredential( credentialId: indyCredentialExchangeRecord.id, }; } + +export async function getAgentCredentials(agent: Agent) { + const validCredentials = await agent.credentials.findAllByQuery({ + state: CredentialState.Done, + }); + log.debug("Valid credentials count:", validCredentials.length); + + return validCredentials.map((c) => { + return { + id: c.id, + schemaId: c.metadata.data["_anoncreds/credential"].schemaId, + credentialDefinitionId: + c.metadata.data["_anoncreds/credential"].credentialDefinitionId, + connectionId: c.connectionId, + credentials: c.credentials, + credentialAttributes: c.credentialAttributes, + }; + }); +} diff --git a/examples/cactus-example-discounted-asset-trade-client/src/main/typescript/public-api.ts b/examples/cactus-example-discounted-asset-trade-client/src/main/typescript/public-api.ts new file mode 100755 index 00000000000..68179323d78 --- /dev/null +++ b/examples/cactus-example-discounted-asset-trade-client/src/main/typescript/public-api.ts @@ -0,0 +1,4 @@ +export * from "./lib/agent-setup"; +export * from "./lib/connections"; +export * from "./lib/credentials"; +export * from "./lib/proofs"; diff --git a/examples/cactus-example-discounted-asset-trade-client/src/main/typescript/scripts/run-discounted-asset-trade-client.ts b/examples/cactus-example-discounted-asset-trade-client/src/main/typescript/scripts/run-discounted-asset-trade-client.ts new file mode 100644 index 00000000000..313e3abcaf2 --- /dev/null +++ b/examples/cactus-example-discounted-asset-trade-client/src/main/typescript/scripts/run-discounted-asset-trade-client.ts @@ -0,0 +1,110 @@ +import { Agent } from "@aries-framework/core"; +import inquirer from "inquirer"; +import * as log from "loglevel"; +import { + createAliceAgent, + createNewConnectionInvitation, + getAgentCredentials, + waitForConnection, +} from "../public-api"; + +log.setDefaultLevel("DEBUG"); + +enum PromptOptions { + StartTrade = "Start the trade", + GetCredentials = "Get this agent credentials", + GetAssets = "Get assets", + Exit = "Exit", +} + +async function connectAgentToBLP(clientAgent: Agent) { + log.debug("Connecting to the discounted asset trade sample app agent..."); + + // Create invitation + const { outOfBandRecord, invitationUrl } = + await createNewConnectionInvitation(clientAgent); + const isConnectedPromise = waitForConnection(clientAgent, outOfBandRecord.id); + + // Send request to the BLP agent + // TODO - send with HTTP + log.debug("Invitation link:", invitationUrl); + + // Wait for connection + await isConnectedPromise; + log.info("Connected to the discounted asset trade sample app agent!"); +} + +async function sendTradeRequest() { + // TODO + log.info("Trade request sent!"); +} + +async function printAgentCredentials(agent: Agent) { + const credentials = await getAgentCredentials(agent); + log.info(JSON.stringify(credentials, undefined, 2)); +} + +async function getAssetsFromSampleApp() { + // TODO + log.info("Assets: foo"); +} + +async function getPromptChoice() { + return inquirer.prompt({ + type: "list", + prefix: "", + name: "menu", + message: "Action:", + choices: Object.values(PromptOptions), + }); +} + +async function menuLoop(agent: Agent) { + let isRunning = true; + + while (isRunning) { + try { + const choice = await getPromptChoice(); + switch (choice.menu) { + case PromptOptions.StartTrade: + await sendTradeRequest(); + break; + case PromptOptions.GetCredentials: + await printAgentCredentials(agent); + break; + case PromptOptions.GetAssets: + await getAssetsFromSampleApp(); + break; + case PromptOptions.Exit: + isRunning = false; + break; + } + } catch (error) { + if (error.isTtyError) { + log.error("Prompt couldn't be rendered in the current environment:"); + isRunning = false; + } else { + log.error("Menu action error:", error); + } + } + } +} + +async function run() { + const aliceAgent = await createAliceAgent(); + log.debug("Alice (client) agent created"); + + try { + await connectAgentToBLP(aliceAgent); + + log.debug("Running menu loop..."); + await menuLoop(aliceAgent); + } catch (error) { + log.error("Client app error:", error); + } finally { + log.info("Exiting the client app..."); + aliceAgent.shutdown(); + } +} + +run(); diff --git a/examples/cactus-example-discounted-asset-trade-client/src/main/typescript/scripts/setup-credentials.ts b/examples/cactus-example-discounted-asset-trade-client/src/main/typescript/scripts/setup-credentials.ts index 55e63ec8bdf..59b5d1e223d 100644 --- a/examples/cactus-example-discounted-asset-trade-client/src/main/typescript/scripts/setup-credentials.ts +++ b/examples/cactus-example-discounted-asset-trade-client/src/main/typescript/scripts/setup-credentials.ts @@ -65,6 +65,7 @@ import { connectAgents } from "../lib/connections"; import { issueCredential } from "../lib/credentials"; import { checkCredentialProof } from "../lib/proofs"; +// https://github.com/SamVerschueren/listr ?? async function runTest() { const aliceAgent = await createAliceAgent(); console.log("BOB FINISHED"); @@ -80,26 +81,26 @@ async function runTest() { log.debug("Alice connection ID:", aliceAgentConRecord.id); log.debug("Issuer connection ID:", issuerAgentConRecord.id); - console.log("Issue..."); - const { credentialDefinitionId } = await issueCredential( - issuerAgent, - [ - { name: "first_name", value: "Alice" }, - { name: "last_name", value: "Garcia" }, - { name: "salary", value: "2400" }, - { name: "employee_status", value: "Permanent" }, - { name: "experience", value: "10" }, - ], - issuerAgentConRecord.id, - isserDid, - ); + // console.log("Issue..."); + // const { credentialDefinitionId } = await issueCredential( + // issuerAgent, + // [ + // { name: "first_name", value: "Alice" }, + // { name: "last_name", value: "Garcia" }, + // { name: "salary", value: "2400" }, + // { name: "employee_status", value: "Permanent" }, + // { name: "experience", value: "10" }, + // ], + // issuerAgentConRecord.id, + // isserDid, + // ); - console.log("Check proof..."); - await checkCredentialProof( - issuerAgent, - credentialDefinitionId, - issuerAgentConRecord.id, - ); + // console.log("Check proof..."); + // await checkCredentialProof( + // issuerAgent, + // credentialDefinitionId, + // issuerAgentConRecord.id, + // ); console.log("Close..."); await aliceAgent.shutdown(); diff --git a/tools/docker/indy-testnet/agent/src/blp.ts b/tools/docker/indy-testnet/agent/src/blp.ts index a19106267fe..4ffb95c94b1 100644 --- a/tools/docker/indy-testnet/agent/src/blp.ts +++ b/tools/docker/indy-testnet/agent/src/blp.ts @@ -378,6 +378,24 @@ const registerCredentialDefinition = async ( return credentialDefinitionResult; }; +const waitForConnectionReady = async ( + agent: Agent, + outOfBandRecordId: string, +) => { + let connection: ConnectionRecord | undefined; + do { + await new Promise((resolve) => setTimeout(resolve, 500)); + + connection = ( + await agent.connections.findAllByOutOfBandId(outOfBandRecordId) + ).pop(); + + if (!connection) { + throw Error("No connection!"); + } + } while (connection && !connection.isReady); +}; + const run = async () => { console.log("Initializing BLP agent..."); const blpAgent = await initializeBLPAgent(); @@ -386,11 +404,11 @@ const run = async () => { let outOfBandRecordId = "8c334af4-ba40-496b-abbf-d61cd4b2ddf3"; try { const invitationUrl = - "https://example.org?oob=eyJAdHlwZSI6Imh0dHBzOi8vZGlkY29tbS5vcmcvb3V0LW9mLWJhbmQvMS4xL2ludml0YXRpb24iLCJAaWQiOiJiZWYwYjA1Ny1iYjZlLTQzMDctYjY2ZS0yZDM0YWYzNWQ5MTAiLCJsYWJlbCI6ImRlbW8tYWdlbnQtYm9iIiwiYWNjZXB0IjpbImRpZGNvbW0vYWlwMSIsImRpZGNvbW0vYWlwMjtlbnY9cmZjMTkiXSwiaGFuZHNoYWtlX3Byb3RvY29scyI6WyJodHRwczovL2RpZGNvbW0ub3JnL2RpZGV4Y2hhbmdlLzEuMCIsImh0dHBzOi8vZGlkY29tbS5vcmcvY29ubmVjdGlvbnMvMS4wIl0sInNlcnZpY2VzIjpbeyJpZCI6IiNpbmxpbmUtMCIsInNlcnZpY2VFbmRwb2ludCI6Imh0dHA6Ly9sb2NhbGhvc3Q6MzAwMyIsInR5cGUiOiJkaWQtY29tbXVuaWNhdGlvbiIsInJlY2lwaWVudEtleXMiOlsiZGlkOmtleTp6Nk1rcTZ2WEdrN0JyQ1RuOUhUNnVqeUt0M2lHMjdWb3daTXBoMzdLWjR4Y1lVOTQiXSwicm91dGluZ0tleXMiOltdfV19"; + "https://example.org?oob=eyJAdHlwZSI6Imh0dHBzOi8vZGlkY29tbS5vcmcvb3V0LW9mLWJhbmQvMS4xL2ludml0YXRpb24iLCJAaWQiOiJiNjUxYjhiMC1hOGZhLTQwNmItOTg2Yi1jMTRjMDAzZTNjNDEiLCJsYWJlbCI6ImFsaWNlQ2FjdGlBZ2VudCIsImFjY2VwdCI6WyJkaWRjb21tL2FpcDEiLCJkaWRjb21tL2FpcDI7ZW52PXJmYzE5Il0sImhhbmRzaGFrZV9wcm90b2NvbHMiOlsiaHR0cHM6Ly9kaWRjb21tLm9yZy9kaWRleGNoYW5nZS8xLjAiLCJodHRwczovL2RpZGNvbW0ub3JnL2Nvbm5lY3Rpb25zLzEuMCJdLCJzZXJ2aWNlcyI6W3siaWQiOiIjaW5saW5lLTAiLCJzZXJ2aWNlRW5kcG9pbnQiOiJodHRwOi8vbG9jYWxob3N0OjMwMDMiLCJ0eXBlIjoiZGlkLWNvbW11bmljYXRpb24iLCJyZWNpcGllbnRLZXlzIjpbImRpZDprZXk6ejZNa3NQMmJaZHhjVGtlTVhFYThNRmhrWnVpdXpRdFllZEtlNldlaktuNTF4cmdrIl0sInJvdXRpbmdLZXlzIjpbXX1dfQ"; console.log("Accepting the invitation from alice in BLP..."); - const oob = await receiveInvitation(blpAgent, invitationUrl); outOfBandRecordId = oob.id; + await waitForConnectionReady(blpAgent, outOfBandRecordId); } catch (error) { console.log("Connection alrady on"); } @@ -420,11 +438,12 @@ const run = async () => { ); // Send proof + console.log("Request proof"); const credentialDefinitionId = - "did:indy:bcovrin:test:Th7MpTaRZVRYnPiabds81Y/anoncreds/v0/CLAIM_DEF/63/default"; // TODO - get?? + "did:indy:bcovrin:test:Th7MpTaRZVRYnPiabds81Y/anoncreds/v0/CLAIM_DEF/95/default"; // TODO - get?? const proofAttribute = { name: { - name: "name", + name: "employee_status", restrictions: [ { cred_def_id: credentialDefinitionId, diff --git a/tools/docker/indy-testnet/agent/src/bob.ts b/tools/docker/indy-testnet/agent/src/bob.ts deleted file mode 100644 index aa455f3419a..00000000000 --- a/tools/docker/indy-testnet/agent/src/bob.ts +++ /dev/null @@ -1,573 +0,0 @@ -import { AskarModule } from "@aries-framework/askar"; -import { - Agent, - InitConfig, - ConnectionEventTypes, - ConnectionStateChangedEvent, - WsOutboundTransport, - HttpOutboundTransport, - DidExchangeState, - OutOfBandRecord, - ConnectionsModule, - DidsModule, - TypedArrayEncoder, - KeyType, - CredentialsModule, - V2CredentialProtocol, - CredentialStateChangedEvent, - CredentialEventTypes, - CredentialState, - ConnectionRecord, - ProofEventTypes, - ProofStateChangedEvent, - ProofState, - ProofsModule, - AutoAcceptProof, - V2ProofProtocol, - AutoAcceptCredential, -} from "@aries-framework/core"; -import { agentDependencies, HttpInboundTransport } from "@aries-framework/node"; -import { ariesAskar } from "@hyperledger/aries-askar-nodejs"; -import { - IndyVdrAnonCredsRegistry, - IndyVdrIndyDidRegistrar, - IndyVdrIndyDidResolver, - IndyVdrModule, -} from "@aries-framework/indy-vdr"; -import { indyVdr } from "@hyperledger/indy-vdr-nodejs"; -import { - AnonCredsCredentialFormatService, - AnonCredsModule, - AnonCredsProofFormatService, - LegacyIndyCredentialFormatService, - LegacyIndyProofFormatService, - V1CredentialProtocol, - V1ProofProtocol, -} from "@aries-framework/anoncreds"; -import { AnonCredsRsModule } from "@aries-framework/anoncreds-rs"; -import { anoncreds } from "@hyperledger/anoncreds-nodejs"; -import { readFileSync } from "fs"; -import { - IndySdkAnonCredsRegistry, - IndySdkModule, - IndySdkSovDidResolver, -} from "@aries-framework/indy-sdk"; -import * as indySdk from "indy-sdk"; - -const seed = TypedArrayEncoder.fromString(`000000000000000000000000Steward1`); // What you input on bcovrin. Should be kept secure in production! -const unqualifiedIndyDid = `Bt17egJz8UzzmYd6iGJ6S1`; // will be returned after registering seed on bcovrin -// Verkey: 6vvDZ5YE4WRd39YwG9zn6s5vcz6trnHUcSihXfanVeqy -const indyDid = `did:indy:bcovrin:test:${unqualifiedIndyDid}`; - -const bcovrinGenesisTx = `{"reqSignature":{},"txn":{"data":{"data":{"alias":"Node1","blskey":"4N8aUNHSgjQVgkpm8nhNEfDf6txHznoYREg9kirmJrkivgL4oSEimFF6nsQ6M41QvhM2Z33nves5vfSn9n1UwNFJBYtWVnHYMATn76vLuL3zU88KyeAYcHfsih3He6UHcXDxcaecHVz6jhCYz1P2UZn2bDVruL5wXpehgBfBaLKm3Ba","blskey_pop":"RahHYiCvoNCtPTrVtP7nMC5eTYrsUA8WjXbdhNc8debh1agE9bGiJxWBXYNFbnJXoXhWFMvyqhqhRoq737YQemH5ik9oL7R4NTTCz2LEZhkgLJzB3QRQqJyBNyv7acbdHrAT8nQ9UkLbaVL9NBpnWXBTw4LEMePaSHEw66RzPNdAX1","client_ip":"138.197.138.255","client_port":9702,"node_ip":"138.197.138.255","node_port":9701,"services":["VALIDATOR"]},"dest":"Gw6pDLhcBcoQesN72qfotTgFa7cbuqZpkX3Xo6pLhPhv"},"metadata":{"from":"Th7MpTaRZVRYnPiabds81Y"},"type":"0"},"txnMetadata":{"seqNo":1,"txnId":"fea82e10e894419fe2bea7d96296a6d46f50f93f9eeda954ec461b2ed2950b62"},"ver":"1"} -{"reqSignature":{},"txn":{"data":{"data":{"alias":"Node2","blskey":"37rAPpXVoxzKhz7d9gkUe52XuXryuLXoM6P6LbWDB7LSbG62Lsb33sfG7zqS8TK1MXwuCHj1FKNzVpsnafmqLG1vXN88rt38mNFs9TENzm4QHdBzsvCuoBnPH7rpYYDo9DZNJePaDvRvqJKByCabubJz3XXKbEeshzpz4Ma5QYpJqjk","blskey_pop":"Qr658mWZ2YC8JXGXwMDQTzuZCWF7NK9EwxphGmcBvCh6ybUuLxbG65nsX4JvD4SPNtkJ2w9ug1yLTj6fgmuDg41TgECXjLCij3RMsV8CwewBVgVN67wsA45DFWvqvLtu4rjNnE9JbdFTc1Z4WCPA3Xan44K1HoHAq9EVeaRYs8zoF5","client_ip":"138.197.138.255","client_port":9704,"node_ip":"138.197.138.255","node_port":9703,"services":["VALIDATOR"]},"dest":"8ECVSk179mjsjKRLWiQtssMLgp6EPhWXtaYyStWPSGAb"},"metadata":{"from":"EbP4aYNeTHL6q385GuVpRV"},"type":"0"},"txnMetadata":{"seqNo":2,"txnId":"1ac8aece2a18ced660fef8694b61aac3af08ba875ce3026a160acbc3a3af35fc"},"ver":"1"} -{"reqSignature":{},"txn":{"data":{"data":{"alias":"Node3","blskey":"3WFpdbg7C5cnLYZwFZevJqhubkFALBfCBBok15GdrKMUhUjGsk3jV6QKj6MZgEubF7oqCafxNdkm7eswgA4sdKTRc82tLGzZBd6vNqU8dupzup6uYUf32KTHTPQbuUM8Yk4QFXjEf2Usu2TJcNkdgpyeUSX42u5LqdDDpNSWUK5deC5","blskey_pop":"QwDeb2CkNSx6r8QC8vGQK3GRv7Yndn84TGNijX8YXHPiagXajyfTjoR87rXUu4G4QLk2cF8NNyqWiYMus1623dELWwx57rLCFqGh7N4ZRbGDRP4fnVcaKg1BcUxQ866Ven4gw8y4N56S5HzxXNBZtLYmhGHvDtk6PFkFwCvxYrNYjh","client_ip":"138.197.138.255","client_port":9706,"node_ip":"138.197.138.255","node_port":9705,"services":["VALIDATOR"]},"dest":"DKVxG2fXXTU8yT5N7hGEbXB3dfdAnYv1JczDUHpmDxya"},"metadata":{"from":"4cU41vWW82ArfxJxHkzXPG"},"type":"0"},"txnMetadata":{"seqNo":3,"txnId":"7e9f355dffa78ed24668f0e0e369fd8c224076571c51e2ea8be5f26479edebe4"},"ver":"1"} -{"reqSignature":{},"txn":{"data":{"data":{"alias":"Node4","blskey":"2zN3bHM1m4rLz54MJHYSwvqzPchYp8jkHswveCLAEJVcX6Mm1wHQD1SkPYMzUDTZvWvhuE6VNAkK3KxVeEmsanSmvjVkReDeBEMxeDaayjcZjFGPydyey1qxBHmTvAnBKoPydvuTAqx5f7YNNRAdeLmUi99gERUU7TD8KfAa6MpQ9bw","blskey_pop":"RPLagxaR5xdimFzwmzYnz4ZhWtYQEj8iR5ZU53T2gitPCyCHQneUn2Huc4oeLd2B2HzkGnjAff4hWTJT6C7qHYB1Mv2wU5iHHGFWkhnTX9WsEAbunJCV2qcaXScKj4tTfvdDKfLiVuU2av6hbsMztirRze7LvYBkRHV3tGwyCptsrP","client_ip":"138.197.138.255","client_port":9708,"node_ip":"138.197.138.255","node_port":9707,"services":["VALIDATOR"]},"dest":"4PS3EDQ3dW1tci1Bp6543CfuuebjFrg36kLAUcskGfaA"},"metadata":{"from":"TWwCRQRZ2ZHMJFn9TzLp7W"},"type":"0"},"txnMetadata":{"seqNo":4,"txnId":"aa5e817d7cc626170eca175822029339a444eb0ee8f0bd20d3b0b76e566fb008"},"ver":"1"}`; - -export const genesisTransactions = readFileSync( - "/home/vagrant/cactus/tools/docker/indy-testnet/sandbox/pool_transactions_genesis", -).toString("utf-8"); - -export const localTestNetwork = { - isProduction: false, - genesisTransactions, - indyNamespace: "bcovrin:test", - connectOnStartup: true, -}; - -const initializeBobAgent = async () => { - // Simple agent configuration. This sets some basic fields like the wallet - // configuration and the label. It also sets the mediator invitation url, - // because this is most likely required in a mobile environment. - const config: InitConfig = { - label: "demo-agent-bob", - walletConfig: { - id: "mainBob", - key: "demoagentbob00000000000000000000", - }, - endpoints: ["http://localhost:3003"], - }; - - const legacyIndyCredentialFormatService = - new LegacyIndyCredentialFormatService(); - const legacyIndyProofFormatService = new LegacyIndyProofFormatService(); - - // A new instance of an agent is created here - // Askar can also be replaced by the indy-sdk if required - const agent = new Agent({ - config, - modules: { - connections: new ConnectionsModule({ - autoAcceptConnections: true, - }), - - // For issuing credentials - credentials: new CredentialsModule({ - autoAcceptCredentials: AutoAcceptCredential.ContentApproved, - credentialProtocols: [ - new V1CredentialProtocol({ - indyCredentialFormat: legacyIndyCredentialFormatService, - }), - new V2CredentialProtocol({ - // credentialFormats: [legacyIndyCredentialFormatService, new AnonCredsCredentialFormatService()], - credentialFormats: [ - legacyIndyCredentialFormatService, - new AnonCredsCredentialFormatService(), - ], - }), - ], - }), - - proofs: new ProofsModule({ - autoAcceptProofs: AutoAcceptProof.ContentApproved, - proofProtocols: [ - new V1ProofProtocol({ - indyProofFormat: legacyIndyProofFormatService, - }), - new V2ProofProtocol({ - proofFormats: [ - legacyIndyProofFormatService, - new AnonCredsProofFormatService(), - ], - }), - ], - }), - - anoncreds: new AnonCredsModule({ - // Here we add an Indy VDR registry as an example, any AnonCreds registry - // can be used - registries: [new IndyVdrAnonCredsRegistry()], - }), - - // AnonCreds RS is a direct implementation of the AnonCreds V1.0 specification that provides functionality like; creating a schema object, creating a credential definition object, creating a credential, verifying a proof presentation and much more. - // we should register both the AnonCreds and AnonCredsRs module on the agent. - anoncredsRs: new AnonCredsRsModule({ - anoncreds, - }), - - //Hyperledger Indy VDR, Verifiable Data Registry, can be used to connect to one or more Indy Node ledger pools given sets of genesis transactions - indyVdr: new IndyVdrModule({ - indyVdr, // implements all the native bindings for Indy VDR - networks: [localTestNetwork], - }), - - // Did resolvers configured to work with IndyVDR - dids: new DidsModule({ - registrars: [new IndyVdrIndyDidRegistrar()], - resolvers: [new IndyVdrIndyDidResolver()], - }), - - askar: new AskarModule({ ariesAskar }), - }, - dependencies: agentDependencies, - }); - - // Register a simple `WebSocket` outbound transport - agent.registerOutboundTransport(new WsOutboundTransport()); - - // Register a simple `Http` outbound transport - agent.registerOutboundTransport(new HttpOutboundTransport()); - - // Register a simple `Http` inbound transport - agent.registerInboundTransport(new HttpInboundTransport({ port: 3003 })); - - // Initialize the agent - await agent.initialize(); - - return agent; -}; - -const initializeBobAgentLegacy = async () => { - // Simple agent configuration. This sets some basic fields like the wallet - // configuration and the label. It also sets the mediator invitation url, - // because this is most likely required in a mobile environment. - const config: InitConfig = { - label: "demo-agent-bob", - walletConfig: { - id: "mainBob", - key: "demoagentbob00000000000000000000", - }, - endpoints: ["http://localhost:3003"], - }; - - const legacyIndyCredentialFormatService = - new LegacyIndyCredentialFormatService(); - const legacyIndyProofFormatService = new LegacyIndyProofFormatService(); - - // A new instance of an agent is created here - // Askar can also be replaced by the indy-sdk if required - const agent = new Agent({ - config, - modules: { - connections: new ConnectionsModule({ - autoAcceptConnections: true, - }), - - // For issuing credentials - credentials: new CredentialsModule({ - // autoAcceptCredentials: AutoAcceptCredential.ContentApproved, - credentialProtocols: [ - new V1CredentialProtocol({ - indyCredentialFormat: legacyIndyCredentialFormatService, - }), - new V2CredentialProtocol({ - credentialFormats: [legacyIndyCredentialFormatService], - }), - ], - }), - - proofs: new ProofsModule({ - autoAcceptProofs: AutoAcceptProof.Always, - proofProtocols: [ - new V1ProofProtocol({ - indyProofFormat: legacyIndyProofFormatService, - }), - new V2ProofProtocol({ - proofFormats: [legacyIndyProofFormatService], - }), - ], - }), - - anoncreds: new AnonCredsModule({ - // Here we add an Indy VDR registry as an example, any AnonCreds registry - // can be used - registries: [new IndySdkAnonCredsRegistry()], - }), - - // AnonCreds RS is a direct implementation of the AnonCreds V1.0 specification that provides functionality like; creating a schema object, creating a credential definition object, creating a credential, verifying a proof presentation and much more. - // we should register both the AnonCreds and AnonCredsRs module on the agent. - indySdk: new IndySdkModule({ - indySdk, - networks: [localTestNetwork], - }), - - // Did resolvers configured to work with IndyVDR - dids: new DidsModule({ - resolvers: [new IndySdkSovDidResolver()], - }), - }, - dependencies: agentDependencies, - }); - - // Register a simple `WebSocket` outbound transport - agent.registerOutboundTransport(new WsOutboundTransport()); - - // Register a simple `Http` outbound transport - agent.registerOutboundTransport(new HttpOutboundTransport()); - - // Register a simple `Http` inbound transport - agent.registerInboundTransport(new HttpInboundTransport({ port: 3003 })); - - // Initialize the agent - await agent.initialize(); - - return agent; -}; - -const createNewInvitation = async (agent: Agent) => { - const outOfBandRecord = await agent.oob.createInvitation(); - - return { - invitationUrl: outOfBandRecord.outOfBandInvitation.toUrl({ - domain: "https://example.org", - }), - outOfBandRecord, - }; -}; - -const receiveInvitation = async (agent: Agent, invitationUrl: string) => { - const { outOfBandRecord } = - await agent.oob.receiveInvitationFromUrl(invitationUrl); - - return outOfBandRecord; -}; - -// Listen for connections -const setupConnectionListener = ( - agent: Agent, - outOfBandRecord: OutOfBandRecord, - cb: (...args: any) => void, -) => { - agent.events.on( - ConnectionEventTypes.ConnectionStateChanged, - ({ payload }) => { - if (payload.connectionRecord.outOfBandId !== outOfBandRecord.id) return; - if (payload.connectionRecord.state === DidExchangeState.Completed) { - // the connection is now ready for usage in other protocols! - console.log( - `Connection for out-of-band id ${outOfBandRecord.id} completed`, - ); - - // Custom business logic can be included here - // In this example we can send a basic message to the connection, but - // anything is possible - cb(); - } - }, - ); -}; - -async function waitForConnection(agent: Agent, outOfBandId: string) { - if (!outOfBandId) { - throw new Error("Missing outOfBandId"); - } - - console.log("Waiting for Alice to finish connection..."); - - const getConnectionRecord = (outOfBandId: string) => - new Promise((resolve, reject) => { - // Timeout of 30 seconds - const timeoutId = setTimeout( - () => reject(new Error("Missing connection")), - 60000, - ); - - // Start listener - agent.events.on( - ConnectionEventTypes.ConnectionStateChanged, - (e) => { - if (e.payload.connectionRecord.outOfBandId !== outOfBandId) return; - clearTimeout(timeoutId); - resolve(e.payload.connectionRecord); - }, - ); - - // Also retrieve the connection record by invitation if the event has already fired - void agent.connections - .findAllByOutOfBandId(outOfBandId) - .then(([connectionRecord]) => { - if (connectionRecord) { - clearTimeout(timeoutId); - resolve(connectionRecord); - } - }); - }); - - const connectionRecord = await getConnectionRecord(outOfBandId); - - try { - await agent.connections.returnWhenIsConnected(connectionRecord.id); - } catch (e) { - console.log("Timeout reached!"); - return; - } - console.log("Connection OK!"); -} - -// Listen for credential -const setupCredentialListener = (agent: Agent) => { - agent.events.on( - CredentialEventTypes.CredentialStateChanged, - async ({ payload }) => { - console.log("CREDENTIAL REQUEST", payload.credentialRecord); - switch (payload.credentialRecord.state) { - case CredentialState.OfferReceived: - console.log("received a credential"); - // custom logic here - await agent.credentials.acceptOffer({ - credentialRecordId: payload.credentialRecord.id, - }); - console.log("accepted!"); - } - }, - ); -}; - -/** - * Register Endorser DID at http://test.bcovrin.vonx.io/ - * Load it by it's seed here. - * No need to do if endorser DID already in wallet. - * @param agent - */ -const loadEndorserToken = async (agent: Agent) => { - await agent.dids.import({ - did: indyDid, - overwrite: true, - privateKeys: [ - { - privateKey: seed, - keyType: KeyType.Ed25519, - }, - ], - }); -}; - -export async function importExistingIndyDidFromPrivateKey(agent: Agent) { - const buf = TypedArrayEncoder.fromString("000000000000000000000000Steward1"); - const key = await agent.wallet.createKey({ - keyType: KeyType.Ed25519, - privateKey: buf, - }); - - // did is first 16 bytes of public key encoded as base58 - const unqualifiedIndyDid = TypedArrayEncoder.toBase58( - key.publicKey.slice(0, 16), - ); - - console.log("HODOR KEY:", key.publicKey); - console.log("HODOR unqualifiedIndyDid:", unqualifiedIndyDid); - console.log("HODOR DID:", `did:indy:bcovrin:test:${unqualifiedIndyDid}`); - - // import the did in the wallet so it can be used - await agent.dids.import({ - did: `did:indy:bcovrin:test:${unqualifiedIndyDid}`, - }); - - return unqualifiedIndyDid; -} - -const registerCredentialSchema = async (agent: Agent, did: string) => { - const randomString = Math.random().toString(36).substr(2, 10); - const schemaResult = await agent.modules.anoncreds.registerSchema({ - schema: { - attrNames: ["name"], - issuerId: did, // must be the same as an endorser DID in your wallet. - name: randomString, - version: "1.0.0", - }, - options: {}, - }); - - if (schemaResult.schemaState.state === "failed") { - throw new Error( - `Error creating schema: ${schemaResult.schemaState.reason}`, - ); - } - - return schemaResult; -}; - -const registerCredentialDefinition = async ( - agent: Agent, - schemaResult: any, - did: string, -) => { - const credentialDefinitionResult = - await agent.modules.anoncreds.registerCredentialDefinition({ - credentialDefinition: { - tag: "default", - issuerId: did, // must be the same as an endorser DID in your wallet. - schemaId: schemaResult.schemaState.schemaId, - }, - options: {}, - }); - - if (credentialDefinitionResult.credentialDefinitionState.state === "failed") { - throw new Error( - `Error creating credential definition: ${credentialDefinitionResult.credentialDefinitionState.reason}`, - ); - } - - return credentialDefinitionResult; -}; - -async function run() { - console.log("Initializing Bob agent..."); - const bobAgent = await initializeBobAgent(); - - // TODO - read - try { - const invitationUrl = - "https://example.org?oob=eyJAdHlwZSI6Imh0dHBzOi8vZGlkY29tbS5vcmcvb3V0LW9mLWJhbmQvMS4xL2ludml0YXRpb24iLCJAaWQiOiJmMGM5N2ExMy0zZGFhLTRkZDUtOWY3Ni01ZTY0ZDBjMDBjNjgiLCJsYWJlbCI6ImRlbW8tYWdlbnQtYWNtZSIsImFjY2VwdCI6WyJkaWRjb21tL2FpcDEiLCJkaWRjb21tL2FpcDI7ZW52PXJmYzE5Il0sImhhbmRzaGFrZV9wcm90b2NvbHMiOlsiaHR0cHM6Ly9kaWRjb21tLm9yZy9kaWRleGNoYW5nZS8xLjAiLCJodHRwczovL2RpZGNvbW0ub3JnL2Nvbm5lY3Rpb25zLzEuMCJdLCJzZXJ2aWNlcyI6W3siaWQiOiIjaW5saW5lLTAiLCJzZXJ2aWNlRW5kcG9pbnQiOiJodHRwOi8vbG9jYWxob3N0OjMwMDEiLCJ0eXBlIjoiZGlkLWNvbW11bmljYXRpb24iLCJyZWNpcGllbnRLZXlzIjpbImRpZDprZXk6ejZNa21xc0xYUzhtQ3VjQ01VN0toWm1Ob25HUjZxMVB5bjlZdEdoOXN3VEtMcVpFIl0sInJvdXRpbmdLZXlzIjpbXX1dfQ"; - console.log("Accepting the invitation as Bob..."); - await receiveInvitation(bobAgent, invitationUrl); - } catch (error) { - console.log("Connection alrady on"); - } - - ////////////////////////// - // ACCEPT credential - - try { - console.log("Setup listener"); - setupCredentialListener(bobAgent); - } catch (error) { - console.error("error", error); - } - - //// Crate proof? - await new Promise((resolve) => setTimeout(resolve, 15000)); - - ///////////////// - // CREATE PROOF REQUEST - - // Create proof request listener for alice - bobAgent.events.on( - ProofEventTypes.ProofStateChanged, - async ({ payload }: ProofStateChangedEvent) => { - console.log("PROOF RECORD RECEIVED ON BOB:", payload.proofRecord); - - if (payload.proofRecord.state === ProofState.RequestReceived) { - console.log("PROOF REQUEST RECEIVED (BOB)!"); - - const requestedCredentials = - await bobAgent.proofs.selectCredentialsForRequest({ - proofRecordId: payload.proofRecord.id, - }); - console.log("requestedCredentials", requestedCredentials); - - await bobAgent.proofs.acceptRequest({ - proofRecordId: payload.proofRecord.id, - proofFormats: requestedCredentials.proofFormats, - }); - console.log("proof accepted by BOB"); - } - }, - ); - - console.log("DONE."); -} - -async function runForBlp() { - console.log("Initializing Bob agent..."); - const bobAgent = await initializeBobAgent(); - - // TODO - read - let outOfBandRecordId = "604eb97f-7f0a-4f8b-86b8-edffeaeb114b"; - const conRec = - await bobAgent.connections.findAllByOutOfBandId(outOfBandRecordId); - console.log("conRec", conRec); - if (conRec && conRec[0]) { - outOfBandRecordId = conRec[0].outOfBandId ?? ""; - } else { - console.log("Creating the invitation as Acme..."); - const { outOfBandRecord, invitationUrl } = - await createNewInvitation(bobAgent); - outOfBandRecordId = outOfBandRecord.id; - console.log("outOfBandRecord", outOfBandRecord); - console.log("Listening for connection changes...", invitationUrl); - } - await waitForConnection(bobAgent, outOfBandRecordId); - console.log("outOfBandRecordId:", outOfBandRecordId); - - ///////////////// - // CREATE PROOF REQUEST - - // Create proof request listener for alice - bobAgent.events.on( - ProofEventTypes.ProofStateChanged, - async ({ payload }: ProofStateChangedEvent) => { - console.log("PROOF RECORD RECEIVED ON BOB:", payload.proofRecord); - - if (payload.proofRecord.state === ProofState.RequestReceived) { - console.log("PROOF REQUEST RECEIVED (BOB)!"); - - const requestedCredentials = - await bobAgent.proofs.selectCredentialsForRequest({ - proofRecordId: payload.proofRecord.id, - }); - console.log("requestedCredentials", requestedCredentials); - - await bobAgent.proofs.acceptRequest({ - proofRecordId: payload.proofRecord.id, - proofFormats: requestedCredentials.proofFormats, - }); - console.log("proof accepted by BOB"); - } - }, - ); - - console.log("DONE."); -} - -runForBlp(); diff --git a/tools/docker/indy-testnet/agent/src/issuer.ts b/tools/docker/indy-testnet/agent/src/issuer.ts deleted file mode 100644 index 35b5dfa5fb1..00000000000 --- a/tools/docker/indy-testnet/agent/src/issuer.ts +++ /dev/null @@ -1,541 +0,0 @@ -import { AskarModule } from "@aries-framework/askar"; -import { - Agent, - InitConfig, - ConnectionEventTypes, - ConnectionStateChangedEvent, - WsOutboundTransport, - HttpOutboundTransport, - DidExchangeState, - OutOfBandRecord, - ConnectionsModule, - DidsModule, - TypedArrayEncoder, - KeyType, - CredentialsModule, - V2CredentialProtocol, - CredentialStateChangedEvent, - CredentialEventTypes, - CredentialState, - ConnectionRecord, - ProofEventTypes, - ProofStateChangedEvent, - ProofState, - ProofsModule, - AutoAcceptProof, - V2ProofProtocol, - AutoAcceptCredential, -} from "@aries-framework/core"; -import { agentDependencies, HttpInboundTransport } from "@aries-framework/node"; -import { ariesAskar } from "@hyperledger/aries-askar-nodejs"; -import { - IndyVdrAnonCredsRegistry, - IndyVdrIndyDidRegistrar, - IndyVdrIndyDidResolver, - IndyVdrModule, - IndyVdrRegisterSchemaOptions, -} from "@aries-framework/indy-vdr"; -import { indyVdr } from "@hyperledger/indy-vdr-nodejs"; -import { - AnonCredsCredentialFormatService, - AnonCredsModule, - AnonCredsProofFormatService, - LegacyIndyCredentialFormatService, - LegacyIndyProofFormatService, - V1ProofProtocol, -} from "@aries-framework/anoncreds"; -import { AnonCredsRsModule } from "@aries-framework/anoncreds-rs"; -import { anoncreds } from "@hyperledger/anoncreds-nodejs"; -import { readFileSync } from "fs"; - -const seed = TypedArrayEncoder.fromString(`000000000000000000000000Steward1`); // What you input on bcovrin. Should be kept secure in production! -const unqualifiedIndyDid = `Bt17egJz8UzzmYd6iGJ6S1`; // will be returned after registering seed on bcovrin -// Verkey: 6vvDZ5YE4WRd39YwG9zn6s5vcz6trnHUcSihXfanVeqy -const indyDid = `did:indy:bcovrin:test:${unqualifiedIndyDid}`; - -export const genesisTransactions = readFileSync( - "/home/vagrant/cactus/tools/docker/indy-testnet/sandbox/pool_transactions_genesis", -).toString("utf-8"); - -export const localTestNetwork = { - isProduction: false, - genesisTransactions, - indyNamespace: "bcovrin:test", - connectOnStartup: true, -}; - -const initializeAcmeAgent = async () => { - // Simple agent configuration. This sets some basic fields like the wallet - // configuration and the label. - const config: InitConfig = { - label: "demo-agent-acme", - walletConfig: { - id: "mainAcme1", - key: "demoagentacme0000000000000000000", - }, - endpoints: ["http://localhost:3001"], - }; - - const legacyIndyCredentialFormatService = - new LegacyIndyCredentialFormatService(); - const legacyIndyProofFormatService = new LegacyIndyProofFormatService(); - - // A new instance of an agent is created here - // Askar can also be replaced by the indy-sdk if required - const agent = new Agent({ - config, - modules: { - connections: new ConnectionsModule({ - autoAcceptConnections: true, - }), - - // For issuing credentials - credentials: new CredentialsModule({ - autoAcceptCredentials: AutoAcceptCredential.ContentApproved, - credentialProtocols: [ - new V2CredentialProtocol({ - // credentialFormats: [legacyIndyCredentialFormatService, new AnonCredsCredentialFormatService()], - credentialFormats: [ - legacyIndyCredentialFormatService, - new AnonCredsCredentialFormatService(), - ], - }), - ], - }), - - proofs: new ProofsModule({ - autoAcceptProofs: AutoAcceptProof.ContentApproved, - proofProtocols: [ - new V1ProofProtocol({ - indyProofFormat: legacyIndyProofFormatService, - }), - new V2ProofProtocol({ - proofFormats: [ - legacyIndyProofFormatService, - new AnonCredsProofFormatService(), - ], - }), - ], - }), - - anoncreds: new AnonCredsModule({ - // Here we add an Indy VDR registry as an example, any AnonCreds registry - // can be used - registries: [new IndyVdrAnonCredsRegistry()], - }), - - // AnonCreds RS is a direct implementation of the AnonCreds V1.0 specification that provides functionality like; creating a schema object, creating a credential definition object, creating a credential, verifying a proof presentation and much more. - // we should register both the AnonCreds and AnonCredsRs module on the agent. - anoncredsRs: new AnonCredsRsModule({ - anoncreds, - }), - - //Hyperledger Indy VDR, Verifiable Data Registry, can be used to connect to one or more Indy Node ledger pools given sets of genesis transactions - indyVdr: new IndyVdrModule({ - indyVdr, // implements all the native bindings for Indy VDR - networks: [localTestNetwork], - }), - - // Did resolvers configured to work with IndyVDR - dids: new DidsModule({ - registrars: [new IndyVdrIndyDidRegistrar()], - resolvers: [new IndyVdrIndyDidResolver()], - }), - - askar: new AskarModule({ ariesAskar }), - }, - dependencies: agentDependencies, - }); - - // Register a simple `WebSocket` outbound transport - agent.registerOutboundTransport(new WsOutboundTransport()); - - // Register a simple `Http` outbound transport - agent.registerOutboundTransport(new HttpOutboundTransport()); - - // Register a simple `Http` inbound transport - agent.registerInboundTransport(new HttpInboundTransport({ port: 3001 })); - - // Initialize the agent - await agent.initialize(); - - return agent; -}; - -const createNewInvitation = async (agent: Agent) => { - const outOfBandRecord = await agent.oob.createInvitation(); - - return { - invitationUrl: outOfBandRecord.outOfBandInvitation.toUrl({ - domain: "https://example.org", - }), - outOfBandRecord, - }; -}; - -const receiveInvitation = async (agent: Agent, invitationUrl: string) => { - const { outOfBandRecord } = - await agent.oob.receiveInvitationFromUrl(invitationUrl); - - return outOfBandRecord; -}; - -// Listen for connections -const setupConnectionListener = ( - agent: Agent, - outOfBandRecord: OutOfBandRecord, - cb: (...args: any) => void, -) => { - agent.events.on( - ConnectionEventTypes.ConnectionStateChanged, - ({ payload }) => { - if (payload.connectionRecord.outOfBandId !== outOfBandRecord.id) return; - if (payload.connectionRecord.state === DidExchangeState.Completed) { - // the connection is now ready for usage in other protocols! - console.log( - `Connection for out-of-band id ${outOfBandRecord.id} completed`, - ); - - // Custom business logic can be included here - // In this example we can send a basic message to the connection, but - // anything is possible - cb(); - } - }, - ); -}; - -async function waitForConnection(agent: Agent, outOfBandId: string) { - if (!outOfBandId) { - throw new Error("Missing outOfBandId"); - } - - console.log("Waiting for Alice to finish connection..."); - - const getConnectionRecord = (outOfBandId: string) => - new Promise((resolve, reject) => { - // Timeout of 30 seconds - const timeoutId = setTimeout( - () => reject(new Error("Missing connection")), - 60000, - ); - - // Start listener - agent.events.on( - ConnectionEventTypes.ConnectionStateChanged, - (e) => { - if (e.payload.connectionRecord.outOfBandId !== outOfBandId) return; - clearTimeout(timeoutId); - resolve(e.payload.connectionRecord); - }, - ); - - // Also retrieve the connection record by invitation if the event has already fired - void agent.connections - .findAllByOutOfBandId(outOfBandId) - .then(([connectionRecord]) => { - if (connectionRecord) { - clearTimeout(timeoutId); - resolve(connectionRecord); - } - }); - }); - - const connectionRecord = await getConnectionRecord(outOfBandId); - - try { - await agent.connections.returnWhenIsConnected(connectionRecord.id); - } catch (e) { - console.log("Timeout reached!"); - return; - } - console.log("Connection OK!"); -} - -// Listen for credential -const setupCredentialListener = (agent: Agent) => { - return new Promise((resolve, reject) => { - agent.events.on( - CredentialEventTypes.CredentialStateChanged, - async ({ payload }) => { - console.log("CRED:", payload.credentialRecord); - switch (payload.credentialRecord.state) { - case CredentialState.OfferReceived: - console.log("sent success"); - break; - case CredentialState.Done: - console.log( - `Credential for credential id ${payload.credentialRecord.id} is accepted`, - ); - } - resolve(payload.credentialRecord); - }, - ); - }); -}; - -/** - * Register Endorser DID at http://test.bcovrin.vonx.io/ - * Load it by it's seed here. - * No need to do if endorser DID already in wallet. - * @param agent - */ -const loadEndorserToken = async (agent: Agent) => { - await agent.dids.import({ - did: indyDid, - overwrite: true, - privateKeys: [ - { - privateKey: seed, - keyType: KeyType.Ed25519, - }, - ], - }); -}; - -export async function importExistingIndyDidFromPrivateKey(agent: Agent) { - const buf = TypedArrayEncoder.fromString("000000000000000000000000Steward1"); - const key = await agent.wallet.createKey({ - keyType: KeyType.Ed25519, - privateKey: buf, - }); - - // did is first 16 bytes of public key encoded as base58 - const unqualifiedIndyDid = TypedArrayEncoder.toBase58( - key.publicKey.slice(0, 16), - ); - - console.log("HODOR KEY:", key.publicKey); - console.log("HODOR unqualifiedIndyDid:", unqualifiedIndyDid); - console.log("HODOR DID:", `did:indy:bcovrin:test:${unqualifiedIndyDid}`); - - // import the did in the wallet so it can be used - await agent.dids.import({ - did: `did:indy:bcovrin:test:${unqualifiedIndyDid}`, - }); - - return unqualifiedIndyDid; -} - -const registerCredentialSchema = async (agent: Agent, did: string) => { - const randomString = Math.random().toString(36).substr(2, 10); - const schemaResult = await agent.modules.anoncreds.registerSchema({ - schema: { - attrNames: ["name"], - issuerId: did, // must be the same as an endorser DID in your wallet. - name: randomString, - version: "1.0.0", - }, - options: { - endorserMode: "internal", - endorserDid: did, - }, - }); - - if (schemaResult.schemaState.state !== "finished") { - throw new Error( - `Error registering schema: ${ - schemaResult.schemaState.state === "failed" - ? schemaResult.schemaState.reason - : "Not Finished" - }`, - ); - } - - return schemaResult; -}; - -const registerCredentialDefinition = async ( - agent: Agent, - schemaResult: any, - did: string, -) => { - const credentialDefinitionResult = - await agent.modules.anoncreds.registerCredentialDefinition({ - credentialDefinition: { - tag: "default", - issuerId: did, // must be the same as an endorser DID in your wallet. - schemaId: schemaResult.schemaState.schemaId, - }, - options: { - endorserMode: "internal", - endorserDid: did, - }, - }); - - if ( - credentialDefinitionResult.credentialDefinitionState.state !== "finished" - ) { - throw new Error( - `Error registering credential definition: ${ - credentialDefinitionResult.credentialDefinitionState.state === "failed" - ? credentialDefinitionResult.credentialDefinitionState.reason - : "Not Finished" - }}`, - ); - } - - return credentialDefinitionResult; -}; - -const run = async () => { - console.log("Initializing Acme agent..."); - const acmeAgent = await initializeAcmeAgent(); - - console.log("Load ACME endorser DID..."); - try { - await importExistingIndyDidFromPrivateKey(acmeAgent); - } catch (error) {} - - const did = "did:indy:bcovrin:test:Th7MpTaRZVRYnPiabds81Y"; - - let outOfBandRecordId = "ec363c2a-696b-47ab-ae05-a2c8620dfca0"; - const conRec = - await acmeAgent.connections.findAllByOutOfBandId(outOfBandRecordId); - console.log("conRec", conRec); - if (conRec && conRec[0]) { - outOfBandRecordId = conRec[0].outOfBandId ?? ""; - } else { - console.log("Creating the invitation as Acme..."); - const { outOfBandRecord, invitationUrl } = - await createNewInvitation(acmeAgent); - outOfBandRecordId = outOfBandRecord.id; - console.log("outOfBandRecord", outOfBandRecord); - console.log("Listening for connection changes...", invitationUrl); - } - - // setupConnectionListener(acmeAgent, outOfBandRecord, () => - // console.log( - // "We now have an active connection to use in the following tutorials" - // ) - // ); - await waitForConnection(acmeAgent, outOfBandRecordId); - console.log("outOfBandRecordId:", outOfBandRecordId); - - // TODO - only if not already created - console.log("Register Credential Schema"); - const schemaResult = await registerCredentialSchema(acmeAgent, did); - console.log("schemaResult:", schemaResult); - // schemaResult: { - // schemaState: { - // state: 'finished', - // schema: { - // attrNames: [Array], - // issuerId: 'did:indy:bcovrin:test:Bt17egJz8UzzmYd6iGJ6S1', - // name: 'sample2', - // version: '1.0.0' - // }, - // schemaId: 'did:indy:bcovrin:test:Bt17egJz8UzzmYd6iGJ6S1/anoncreds/v0/SCHEMA/sample2/1.0.0' - // }, - // registrationMetadata: {}, - // schemaMetadata: { indyLedgerSeqNo: 95971 } - // } - - console.log("Register Credential Definition"); - const credentialDefinitionResult = await registerCredentialDefinition( - acmeAgent, - schemaResult, - did, - ); - console.log("credentialDefinitionResult:", credentialDefinitionResult); - // credentialDefinitionResult: { - // credentialDefinitionMetadata: {}, - // credentialDefinitionState: { - // credentialDefinition: { - // schemaId: 'did:indy:bcovrin:test:Bt17egJz8UzzmYd6iGJ6S1/anoncreds/v0/SCHEMA/sample2/1.0.0', - // type: 'CL', - // tag: 'default', - // value: [Object], - // issuerId: 'did:indy:bcovrin:test:Bt17egJz8UzzmYd6iGJ6S1' - // }, - // credentialDefinitionId: 'did:indy:bcovrin:test:Bt17egJz8UzzmYd6iGJ6S1/anoncreds/v0/CLAIM_DEF/95971/default', - // state: 'finished' - // }, - // registrationMetadata: {} - // } - - ////////////////////////// - // Issue credential - - const issent = setupCredentialListener(acmeAgent); - - console.log("outOfBandRecord ID:", outOfBandRecordId); - const [connection] = - await acmeAgent.connections.findAllByOutOfBandId(outOfBandRecordId); - - if (!connection) { - throw Error("No connection!"); - } - console.log("Conn ID:", connection.id); - - const credId = - credentialDefinitionResult.credentialDefinitionState.credentialDefinitionId; - console.log("credentialDefinitionId:", credId); - const indyCredentialExchangeRecord = - await acmeAgent.credentials.offerCredential({ - protocolVersion: "v2", - connectionId: connection.id, - credentialFormats: { - anoncreds: { - credentialDefinitionId: credId, - attributes: [{ name: "name", value: "Jane Doe" }], - }, - }, - }); - // Can wait for acceptance as well - console.log("indyCredentialExchangeRecord:", indyCredentialExchangeRecord); - - await new Promise((resolve) => setTimeout(resolve, 15000)); - const cred2 = await acmeAgent.credentials.findById( - indyCredentialExchangeRecord.id, - ); - console.log("cred2", cred2); - // Accepted - - ///////////////// - // CREATE PROOF REQUEST - - // Create proof accepted listener - acmeAgent.events.on( - ProofEventTypes.ProofStateChanged, - async ({ payload }: ProofStateChangedEvent) => { - console.log("PROOF RECORD RECEIVED ON ACME:", payload.proofRecord); - if (payload.proofRecord.state === ProofState.Done) { - console.log("PROOF ACCEPTED (ACME)!"); - } - }, - ); - - // Send proof - const proofAttribute = { - name: { - name: "name", - restrictions: [ - { - cred_def_id: - credentialDefinitionResult.credentialDefinitionState - .credentialDefinitionId, - }, - ], - }, - }; - - await acmeAgent.proofs.requestProof({ - protocolVersion: "v2", - connectionId: connection.id, - proofFormats: { - anoncreds: { - name: "proof-request", - version: "1.0", - requested_attributes: proofAttribute, - }, - }, - }); - console.log("PROOF REQUEST SENT"); - - console.log("DONE."); -}; - -export default run; - -void run(); diff --git a/yarn.lock b/yarn.lock index 2a2ceffb2ed..b5915c35dbe 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7739,8 +7739,8 @@ __metadata: "@types/inquirer": ^8.2.6 clear: ^0.1.0 figlet: ^1.5.2 + inquirer: ^8.2.6 loglevel: ^1.8.1 - ts-node: ^10.4.0 bin: cacti-ethereum-connector-status: dist/lib/scripts/get-ethereum-connector-status.js languageName: unknown @@ -29409,7 +29409,7 @@ __metadata: languageName: node linkType: hard -"inquirer@npm:8.2.6": +"inquirer@npm:8.2.6, inquirer@npm:^8.2.6": version: 8.2.6 resolution: "inquirer@npm:8.2.6" dependencies: @@ -47071,7 +47071,7 @@ __metadata: languageName: node linkType: hard -"ts-node@npm:10.9.1, ts-node@npm:^10.4.0, ts-node@npm:^10.8.1": +"ts-node@npm:10.9.1, ts-node@npm:^10.8.1": version: 10.9.1 resolution: "ts-node@npm:10.9.1" dependencies: