From f0a3357e07966ad7a8f553012647be6d48a3ef93 Mon Sep 17 00:00:00 2001 From: Michal Bajer Date: Fri, 3 Nov 2023 19:52:00 +0000 Subject: [PATCH] feat(indy-sdk): replace indy SDK with AFJ - Refactor test ledger `indy-testnet` into `indy-all-in-one`. New package uses the latest indy version, has healtcheck script, updated startup / cleanup scripts. - Remove `indy-sdk-cli` image since it's not used anymore. - Refactor `cactus-example-discounted-asset-trade` to use own aries agent instead of indy connector. This way it doesn't need to use indy-sdk anymore, and python indy connector can be safely removed / upgraded. - Update sample app readme to explain current workflow. - Remove client scripts since `cactus-example-discounted-asset-trade-client` can now be used to interact with the sample app. - Add `cactus-example-discounted-asset-trade-client`. It contains script for setting up test credentials on the ledger, script with interactive menu for interacting with `cactus-example-discounted-asset-trade` sample app, and bunch of helper functions used for writing these apps. Depends on #2859 Depends on #2860 Signed-off-by: Michal Bajer --- .cspell.json | 7 + .dcilintignore | 6 - .../README.md | 75 ++ .../package.json | 79 ++ .../src/main/typescript/index.ts | 1 + .../src/main/typescript/lib/agent-setup.ts | 247 ++++ .../src/main/typescript/lib/connections.ts | 228 ++++ .../src/main/typescript/lib/credentials.ts | 270 +++++ .../src/main/typescript/lib/listeners.ts | 114 ++ .../src/main/typescript/lib/proofs.ts | 92 ++ .../src/main/typescript/public-api.ts | 5 + .../run-discounted-asset-trade-client.ts | 238 ++++ .../typescript/scripts/setup-credentials.ts | 76 ++ .../tsconfig.json | 11 + .../Dockerfile | 15 +- .../README.md | 352 +++--- .../business-logic-asset-trade.ts | 141 +-- .../config/usersetting.yaml | 5 + .../config/validator-registry-config.yaml | 15 - .../docker-compose.yml | 64 - .../indy-agent.ts | 49 + .../indy-endpoints.ts | 48 + .../nginx/nginx.conf | 46 - .../package.json | 3 +- .../read-ledger-state.js | 31 - .../script-cleanup.sh | 11 +- .../script-dockerless-config-patch.sh | 1 - .../script-post-trade-request.sh | 15 - .../script-start-ledgers.sh | 40 +- .../transaction-indy.ts | 131 +-- .../tsconfig.json | 2 +- .../www.ts | 2 + examples/register-indy-data/Dockerfile | 18 - examples/register-indy-data/README.md | 32 - .../register-indy-data/register-indy-data.py | 672 ----------- .../register-indy-data/script-build-docker.sh | 10 - .../cactus_validator_socketio_indy/Dockerfile | 2 +- .../cactus_validator_socketio_indy/README.md | 67 -- .../routing-interface/RequestInfo.ts | 7 +- .../package.json | 1 + tools/docker/indy-all-in-one/Dockerfile | 90 ++ tools/docker/indy-all-in-one/README.md | 50 + .../docker-compose.yaml | 15 +- tools/docker/indy-all-in-one/healthcheck.sh | 15 + .../docker/indy-all-in-one/script-cleanup.sh | 12 + .../indy-all-in-one/script-start-docker.sh | 9 + .../startup.sh | 2 +- tools/docker/indy-sdk-cli/Dockerfile | 66 -- tools/docker/indy-sdk-cli/README.md | 17 - .../docker/indy-sdk-cli/from-indy-sdk/util.js | 55 - .../indy-sdk-cli/from-indy-sdk/utils.py | 63 - tools/docker/indy-testnet/.gitignore | 2 - tools/docker/indy-testnet/Dockerfile | 106 -- tools/docker/indy-testnet/README.md | 35 - tools/docker/indy-testnet/sandbox/.gitkeep | 0 tools/docker/indy-testnet/script-cleanup.sh | 6 - tsconfig.json | 3 + yarn.lock | 1046 ++++++++++++++++- 58 files changed, 3057 insertions(+), 1764 deletions(-) create mode 100644 examples/cactus-example-discounted-asset-trade-client/README.md create mode 100644 examples/cactus-example-discounted-asset-trade-client/package.json create mode 100755 examples/cactus-example-discounted-asset-trade-client/src/main/typescript/index.ts create mode 100644 examples/cactus-example-discounted-asset-trade-client/src/main/typescript/lib/agent-setup.ts create mode 100644 examples/cactus-example-discounted-asset-trade-client/src/main/typescript/lib/connections.ts create mode 100644 examples/cactus-example-discounted-asset-trade-client/src/main/typescript/lib/credentials.ts create mode 100644 examples/cactus-example-discounted-asset-trade-client/src/main/typescript/lib/listeners.ts create mode 100644 examples/cactus-example-discounted-asset-trade-client/src/main/typescript/lib/proofs.ts create mode 100755 examples/cactus-example-discounted-asset-trade-client/src/main/typescript/public-api.ts create mode 100644 examples/cactus-example-discounted-asset-trade-client/src/main/typescript/scripts/run-discounted-asset-trade-client.ts create mode 100644 examples/cactus-example-discounted-asset-trade-client/src/main/typescript/scripts/setup-credentials.ts create mode 100644 examples/cactus-example-discounted-asset-trade-client/tsconfig.json create mode 100644 examples/cactus-example-discounted-asset-trade/indy-agent.ts create mode 100644 examples/cactus-example-discounted-asset-trade/indy-endpoints.ts delete mode 100644 examples/cactus-example-discounted-asset-trade/nginx/nginx.conf delete mode 100644 examples/cactus-example-discounted-asset-trade/read-ledger-state.js delete mode 100755 examples/cactus-example-discounted-asset-trade/script-post-trade-request.sh delete mode 100644 examples/register-indy-data/Dockerfile delete mode 100644 examples/register-indy-data/README.md delete mode 100644 examples/register-indy-data/register-indy-data.py delete mode 100755 examples/register-indy-data/script-build-docker.sh create mode 100644 tools/docker/indy-all-in-one/Dockerfile create mode 100644 tools/docker/indy-all-in-one/README.md rename tools/docker/{indy-testnet => indy-all-in-one}/docker-compose.yaml (54%) create mode 100755 tools/docker/indy-all-in-one/healthcheck.sh create mode 100755 tools/docker/indy-all-in-one/script-cleanup.sh create mode 100755 tools/docker/indy-all-in-one/script-start-docker.sh rename tools/docker/{indy-testnet => indy-all-in-one}/startup.sh (89%) delete mode 100644 tools/docker/indy-sdk-cli/Dockerfile delete mode 100644 tools/docker/indy-sdk-cli/README.md delete mode 100644 tools/docker/indy-sdk-cli/from-indy-sdk/util.js delete mode 100644 tools/docker/indy-sdk-cli/from-indy-sdk/utils.py delete mode 100644 tools/docker/indy-testnet/.gitignore delete mode 100644 tools/docker/indy-testnet/Dockerfile delete mode 100644 tools/docker/indy-testnet/README.md delete mode 100644 tools/docker/indy-testnet/sandbox/.gitkeep delete mode 100755 tools/docker/indy-testnet/script-cleanup.sh diff --git a/.cspell.json b/.cspell.json index fff59e047c..99d894f7c1 100644 --- a/.cspell.json +++ b/.cspell.json @@ -7,9 +7,13 @@ "adminpw", "Albertirsa", "ALLFORTX", + "Anoncreds", + "anoncreds", "ANYFORTX", "APIV", "approveformyorg", + "Askar", + "askar", "Authz", "authzn", "AWSSM", @@ -36,9 +40,12 @@ "couchdb", "COUCHDBADDRESS", "COUCHDBCONFIG", + "Creds", "data", "dclm", "DHTAPI", + "Dids", + "dids", "DockerOde", "ealen", "ecparams", diff --git a/.dcilintignore b/.dcilintignore index d06a458b3d..477004f2ce 100644 --- a/.dcilintignore +++ b/.dcilintignore @@ -7,12 +7,6 @@ tools/docker/besu-all-in-one/supervisord.conf # Cannot be edited due to configuration schema of third party software docs/source/conf.py -# Cannot be edited due to configuration schema of third party software -examples/register-indy-data/register-indy-data.py - -# Cannot be edited due to configuration schema of third party software -tools/docker/indy-testnet/Dockerfile - # Cannot be edited due to configuration schema of third party software packages/cactus-test-tooling/src/main/typescript/keycloak/keycloak-container.ts diff --git a/examples/cactus-example-discounted-asset-trade-client/README.md b/examples/cactus-example-discounted-asset-trade-client/README.md new file mode 100644 index 0000000000..ff42267204 --- /dev/null +++ b/examples/cactus-example-discounted-asset-trade-client/README.md @@ -0,0 +1,75 @@ +# cactus-example-discounted-asset-trade-client +- Client applications and helper libraries for interacting with test indy ledger and Cacti discounted asset trade example app. +- Uses Hyperledger Aries Framework JavaScript (AFJ). +- **Before running any of the script make sure that test indy ledger is running and it's config is available under `/etc/cactus/indy-all-in-one/` (at least `pool_transactions_genesis` should be there.)** + +## Build +- This package will be build as part of main cacti build (`yarn run configure` in root dir), or can be build manually by running `yarn run build` from this directory). + +## Setup Credentials Script +- This script can be used to setup indy credentials before running the example app, or to simply check indy test ledger operational status. +- Script will register employment credential, issue it to agent `Alice`, and check that employment proof is correct. +- Can be run repeatadelly. + +``` bash +# Run the script +yarn setup-credentials + +# Run with debug logs +LOG_LEVEL=DEBUG yarn setup-credentials +``` + +### Sample output + +``` bash +Running with log level INFO +Connecting Alice with Issuer... +Connecting aliceCactiAgent to issuerCactiAgent... +Agents connected! +Register and issue the employment credential... +Register Credential Schema... +Register employment certificate credential schema 'cactiJobCert'... +Register Credential Definition... +Register job certificate credential definition (schemaId: 'did:indy:cacti:test:Th7MpTaRZVRYnPiabds81Y/anoncreds/v0/SCHEMA/cactiJobCert/1.0.0') ... +Issue the credential... +Accepting credential 018e6578-4e52-4ae0-8381-8c935c8a13dc... +Credential accepted! +Credential was issed and accepted by a peer agent! +Verify employment status proof... +Proof request was sent +Accepting proof 5c0986ab-4f1d-4850-a2ff-53c90ce34a12... +Proof request accepted! +Requested proof status: done +Finishing - cleaning up the agents... +All done. +`````` + +## Discounted Asset Trade Client +- Used to interact with discounted asset trade example application. +- Will connect Alice agent to sample application. After that you can choose action to perform. +- Actions: + - `Start the trade`: Will send trade request to example app, asset2 will change owner and payment will be processed on etherem (see `cactus-example-discounted-asset-trade` README for more details) + - `Get this agent credentials`: Get list of Alice credentials. + - `Get assets`: Get example app asset list (both fabric assets and ethereum balances) + - `Exit`: Cleanup and leave. Note - may take few seconds due to ongoing timeouts etc... +- Note: Use arrow keys to restore menu if any async message caused it to disappear. + +``` bash +# Run the script +yarn run-discounted-asset-trade-client + +# Run with debug logs +LOG_LEVEL=DEBUG yarn run-discounted-asset-trade-client +``` + +### Sample output + +``` bash +Running with log level INFO +Connected to the discounted asset trade sample app agent! ID: 5a4f0cf6-b53a-4f3d-9494-112edfdfd626 +Action: (Use arrow keys) +❯ Start the trade + Get this agent credentials + Get assets + Exit +`````` diff --git a/examples/cactus-example-discounted-asset-trade-client/package.json b/examples/cactus-example-discounted-asset-trade-client/package.json new file mode 100644 index 0000000000..f0b73d97a3 --- /dev/null +++ b/examples/cactus-example-discounted-asset-trade-client/package.json @@ -0,0 +1,79 @@ +{ + "name": "@hyperledger/cactus-example-discounted-asset-trade-client", + "version": "2.0.0-alpha.2", + "description": "Client for interacting with discounted asset trade sample app and some tools for setting up indy enviroment", + "keywords": [ + "Hyperledger", + "Cacti", + "Cactus", + "Integration", + "Blockchain", + "Distributed Ledger Technology" + ], + "homepage": "https://github.com/hyperledger/cacti#readme", + "bugs": { + "url": "https://github.com/hyperledger/cacti/issues" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/hyperledger/cacti.git" + }, + "license": "Apache-2.0", + "author": { + "name": "Hyperledger Cacti Contributors", + "email": "cacti@lists.hyperledger.org", + "url": "https://www.hyperledger.org/use/cacti" + }, + "contributors": [ + { + "name": "Please add yourself to the list of contributors", + "email": "your.name@example.com", + "url": "https://example.com" + }, + { + "name": "Michal Bajer", + "email": "michal.bajer@fujitsu.com", + "url": "https://www.fujitsu.com/global/" + } + ], + "main": "dist/lib/main/typescript/index.js", + "module": "dist/lib/main/typescript/index.js", + "types": "dist/lib/main/typescript/index.d.ts", + "bin": { + "run-discounted-asset-trade-client": "dist/lib/main/typescript/scripts/run-discounted-asset-trade-client.js", + "setup-credentials": "dist/lib/main/typescript/scripts/setup-credentials.js" + }, + "files": [ + "dist/*" + ], + "scripts": { + "build": "tsc", + "setup-credentials": "node dist/lib/main/typescript/scripts/setup-credentials.js", + "run-discounted-asset-trade-client": "node dist/lib/main/typescript/scripts/run-discounted-asset-trade-client.js" + }, + "dependencies": { + "@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", + "axios": "1.5.1", + "inquirer": "8.2.6", + "loglevel": "1.8.1" + }, + "devDependencies": { + "@aries-framework/anoncreds": "0.5.0-alpha.58", + "@aries-framework/anoncreds-rs": "0.5.0-alpha.58", + "@aries-framework/askar": "0.5.0-alpha.58", + "@aries-framework/core": "0.5.0-alpha.58", + "@aries-framework/indy-sdk": "0.5.0-alpha.58", + "@aries-framework/indy-vdr": "0.5.0-alpha.58", + "@aries-framework/node": "0.5.0-alpha.58", + "@types/inquirer": "8.2.6" + }, + "engines": { + "node": ">=18", + "npm": ">=8" + }, + "publishConfig": { + "access": "public" + } +} 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 0000000000..87cb558397 --- /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 new file mode 100644 index 0000000000..98b787b48e --- /dev/null +++ b/examples/cactus-example-discounted-asset-trade-client/src/main/typescript/lib/agent-setup.ts @@ -0,0 +1,247 @@ +/** + * Functions for setting up test Aries agents. + */ + +import * as log from "loglevel"; +import { readFileSync } from "fs"; + +import { AskarModule } from "@aries-framework/askar"; +import { + Agent, + InitConfig, + HttpOutboundTransport, + ConnectionsModule, + DidsModule, + TypedArrayEncoder, + KeyType, + CredentialsModule, + V2CredentialProtocol, + 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, +} from "@aries-framework/anoncreds"; +import { AnonCredsRsModule } from "@aries-framework/anoncreds-rs"; +import { anoncreds } from "@hyperledger/anoncreds-nodejs"; + +import { + setupAcceptingCredentialListener, + setupAcceptingProofListener, +} from "../public-api"; + +// Constants +const ALICE_AGENT_NAME = "aliceCactiAgent"; +const ALICE_AGENT_PORT = 3003; +const ISSUER_AGENT_NAME = "issuerCactiAgent"; +const ISSUER_AGENT_PORT = 3004; +const ISSUER_DID_SEED = "000000000000000000000000Steward1"; +const DID_INDY_NAMESPACE = "cacti:test"; + +// Read Genesis transactions +const genesisTransactionsPath = + "/etc/cactus/indy-all-in-one/pool_transactions_genesis"; +log.info( + "Reading Indy genesis transactions from file:", + genesisTransactionsPath, +); +const genesisTransactions = readFileSync( + "/etc/cactus/indy-all-in-one/pool_transactions_genesis", +).toString("utf-8"); + +/** + * Configuration for local indy-all-in-one ledger. + */ +export const localTestNetwork = { + isProduction: false, + genesisTransactions, + indyNamespace: DID_INDY_NAMESPACE, + connectOnStartup: true, +}; + +/** + * Aries JS Agent with Anoncreds/Indy/Askar modules configured. + * This is exact Agent type returned by factories used in this module. + */ +export type AnoncredAgent = Agent<{ + readonly connections: ConnectionsModule; + readonly credentials: CredentialsModule< + V2CredentialProtocol[] + >; + readonly proofs: ProofsModule< + V2ProofProtocol[] + >; + readonly anoncreds: AnonCredsModule; + readonly anoncredsRs: AnonCredsRsModule; + readonly indyVdr: IndyVdrModule; + readonly dids: DidsModule; + readonly askar: AskarModule; +}>; + +/** + * Import endorser DID using it's seed. + * @warn If there's any endorser DID already in a wallet then it will be returned. New one (`seed`) will be ignored! + * + * @param agent Aries agent + * @param seed private DID seed + * + * @returns endorser fully-qualified DID + */ +export async function importExistingIndyDidFromPrivateKey( + agent: AnoncredAgent, + seed: string, +): Promise { + const [endorserDid] = await agent.dids.getCreatedDids({ method: "indy" }); + if (endorserDid) { + log.info("Endorser DID already present in a wallet"); + return endorserDid.did; + } + + const seedBuffer = TypedArrayEncoder.fromString(seed); + const key = await agent.wallet.createKey({ + keyType: KeyType.Ed25519, + privateKey: seedBuffer, + }); + + // did is first 16 bytes of public key encoded as base58 + const unqualifiedIndyDid = TypedArrayEncoder.toBase58( + key.publicKey.slice(0, 16), + ); + const did = `did:indy:${DID_INDY_NAMESPACE}:${unqualifiedIndyDid}`; + + await agent.dids.import({ + did, + }); + + return did; +} + +/** + * Generic function for setting up common Anoncreds/Indy/Askar agent. + * Use only for test purposes! + * + * @param name name of the agent + * @param port port to listen on + * + * @returns newly created Aries agent. + */ +export async function setupAgent( + name: string, + port: number, +): Promise { + const config: InitConfig = { + label: name, + walletConfig: { + id: name, + key: name, + }, + endpoints: [`http://localhost:${port}`], + }; + + const agent = new Agent({ + config, + modules: getAskarAnonCredsIndyModules(), + dependencies: agentDependencies, + }); + + agent.registerOutboundTransport(new HttpOutboundTransport()); + agent.registerInboundTransport(new HttpInboundTransport({ port })); + await agent.initialize(); + + return agent; +} + +/** + * Get Anoncreds/Indy/Askar agent modules. + * + * @returns agent modules + */ +function getAskarAnonCredsIndyModules() { + return { + connections: new ConnectionsModule({ + autoAcceptConnections: true, + }), + + credentials: new CredentialsModule({ + autoAcceptCredentials: AutoAcceptCredential.ContentApproved, + credentialProtocols: [ + new V2CredentialProtocol({ + credentialFormats: [new AnonCredsCredentialFormatService()], + }), + ], + }), + + proofs: new ProofsModule({ + autoAcceptProofs: AutoAcceptProof.ContentApproved, + proofProtocols: [ + new V2ProofProtocol({ + proofFormats: [new AnonCredsProofFormatService()], + }), + ], + }), + + anoncreds: new AnonCredsModule({ + registries: [new IndyVdrAnonCredsRegistry()], + }), + + anoncredsRs: new AnonCredsRsModule({ + anoncreds, + }), + + indyVdr: new IndyVdrModule({ + indyVdr, + networks: [localTestNetwork], + }), + + dids: new DidsModule({ + registrars: [new IndyVdrIndyDidRegistrar()], + resolvers: [new IndyVdrIndyDidResolver()], + }), + + askar: new AskarModule({ ariesAskar }), + } as const; +} + +/** + * Setup Alice agent. + * It will listen and accept new credentials and proof requests. + * + * @returns Alice agent + */ +export async function createAliceAgent(): Promise { + const agent = await setupAgent(ALICE_AGENT_NAME, ALICE_AGENT_PORT); + setupAcceptingCredentialListener(agent); + setupAcceptingProofListener(agent); + return agent; +} + +/** + * Setup Issuer agent. + * It will import endorser DID into wallet to be able to send transactions to the ledger. + * + * @returns Issuer agent + */ +export async function createIssuerAgent(): Promise<{ + agent: AnoncredAgent; + did: string; +}> { + const agent = await setupAgent(ISSUER_AGENT_NAME, ISSUER_AGENT_PORT); + const did = await importExistingIndyDidFromPrivateKey(agent, ISSUER_DID_SEED); + return { + agent, + did, + }; +} diff --git a/examples/cactus-example-discounted-asset-trade-client/src/main/typescript/lib/connections.ts b/examples/cactus-example-discounted-asset-trade-client/src/main/typescript/lib/connections.ts new file mode 100644 index 0000000000..c1cf3981c6 --- /dev/null +++ b/examples/cactus-example-discounted-asset-trade-client/src/main/typescript/lib/connections.ts @@ -0,0 +1,228 @@ +/** + * Functions used for connecting aries agents together. + */ + +import * as log from "loglevel"; +import { + Agent, + ConnectionEventTypes, + ConnectionStateChangedEvent, + DidExchangeState, + OutOfBandRecord, + ConnectionRecord, +} from "@aries-framework/core"; + +// Constants +const WAIT_FOR_CLIENT_ACCEPT_TIMEOUT = 60 * 1000; +const WAIT_FOR_CONNECTION_READY_POLL_INTERVAL = 500; + +/** + * Create connection invitation from an `agent`. + * + * @param agent Aries agent + * + * @returns invitationUrl and outOfBandRecord + */ +export async function createNewConnectionInvitation(agent: Agent): Promise<{ + invitationUrl: string; + outOfBandRecord: OutOfBandRecord; +}> { + const outOfBandRecord = await agent.oob.createInvitation(); + + return { + invitationUrl: outOfBandRecord.outOfBandInvitation.toUrl({ + domain: "https://example.org", + }), + outOfBandRecord, + }; +} + +/** + * Accept connection invitation using it's URL. + * + * @param agent Aries agent + * @param invitationUrl connection invitation + * + * @returns `OutOfBandRecord` + */ +export async function acceptInvitation( + agent: Agent, + invitationUrl: string, +): Promise { + const { outOfBandRecord } = + await agent.oob.receiveInvitationFromUrl(invitationUrl); + + return outOfBandRecord; +} + +/** + * Wait until connection invite is accepted and connection is established. + * This functions comes from AFJ repository. + * + * @param agent Aries agent + * @param outOfBandId connection outOfBandId to wait for + * @returns new `ConnectionRecord` + */ +export async function waitForConnection( + agent: Agent, + outOfBandId: string, +): Promise { + if (!outOfBandId) { + throw new Error("Missing outOfBandId in waitForConnection"); + } + + const getConnectionRecord = (outOfBandId: string) => + new Promise((resolve, reject) => { + const timeoutId = setTimeout( + () => reject(new Error("Missing connection")), + WAIT_FOR_CLIENT_ACCEPT_TIMEOUT, + ); + + // Start listener + agent.events.on( + ConnectionEventTypes.ConnectionStateChanged, + (e) => { + if (e.payload.connectionRecord.outOfBandId !== outOfBandId) return; + log.debug( + "waitForConnection() - received ConnectionStateChanged event for given outOfBandId", + ); + 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); + + return agent.connections.returnWhenIsConnected(connectionRecord.id); +} + +/** + * Search for already established connection with agent by it's label. + * @warn don't trust the label, use this method only for development. + * + * @param agent Aries agent + * @param peerAgentLabel Aries agent label we already conencted to + * + * @returns `ConnectionRecord` or undefined if connection is missing + */ +export async function getConnectionWithPeerAgent( + agent: Agent, + peerAgentLabel: string, +): Promise { + const completedConnections = await agent.connections.findAllByQuery({ + state: DidExchangeState.Completed, + }); + log.debug( + `getConnectionWithPeerAgent() - found ${completedConnections.length} completed connections`, + ); + + return completedConnections + .filter((cr) => { + return cr.theirLabel && cr.theirLabel === peerAgentLabel; + }) + .pop(); +} + +/** + * Connect two agents to each other. + * + * @param firstAgent Aries agent + * @param secondAgent Aries agent + * @returns [firstAgentConnectionRecord, secondAgentConnectionRecord] + */ +export async function connectAgents( + firstAgent: Agent, + secondAgent: Agent, +): Promise { + log.info( + `Connecting ${firstAgent.config.label} to ${secondAgent.config.label}...`, + ); + + let firstAgentConnectionRecord = await getConnectionWithPeerAgent( + firstAgent, + secondAgent.config.label, + ); + let secondAgentConnectionRecord = await getConnectionWithPeerAgent( + secondAgent, + firstAgent.config.label, + ); + + if (firstAgentConnectionRecord && secondAgentConnectionRecord) { + log.info("Agents already connected, using previous connection records..."); + return [firstAgentConnectionRecord, secondAgentConnectionRecord]; + } + + // Create an invitation from the firstAgent + const { outOfBandRecord: firstAgentOOBRecord, invitationUrl } = + await createNewConnectionInvitation(firstAgent); + const isConnectedPromise = waitForConnection( + firstAgent, + firstAgentOOBRecord.id, + ); + + // Accept invitation as the secondAgent + const secondAgentOOBRecord = await acceptInvitation( + secondAgent, + invitationUrl, + ); + + // Wait until connection is done + await isConnectedPromise; + + // Get newly created connection records + firstAgentConnectionRecord = ( + await firstAgent.connections.findAllByOutOfBandId(firstAgentOOBRecord.id) + ).pop(); + secondAgentConnectionRecord = ( + await secondAgent.connections.findAllByOutOfBandId(secondAgentOOBRecord.id) + ).pop(); + + if (firstAgentConnectionRecord && secondAgentConnectionRecord) { + log.info("Agents connected!"); + return [firstAgentConnectionRecord, secondAgentConnectionRecord]; + } + + throw new Error("Could not connect the agents!"); +} + +/** + * Block until given connection is operational. + * + * @param agent Aries agent + * @param outOfBandRecordId connection outOfBandRecordId + * @param timeout operation timeout (will throw exception if timeout exceeded) + */ +export async function waitForConnectionReady( + agent: Agent, + outOfBandRecordId: string, + timeout = WAIT_FOR_CLIENT_ACCEPT_TIMEOUT, +): Promise { + let connection: ConnectionRecord | undefined; + let counter = Math.ceil(timeout / WAIT_FOR_CONNECTION_READY_POLL_INTERVAL); + + do { + counter--; + await new Promise((resolve) => + setTimeout(resolve, WAIT_FOR_CONNECTION_READY_POLL_INTERVAL), + ); + + connection = ( + await agent.connections.findAllByOutOfBandId(outOfBandRecordId) + ).pop(); + } while (counter > 0 && (!connection || !connection.isReady)); + + if (counter <= 0) { + throw new Error("waitForConnectionReady() timeout reached!"); + } +} 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 new file mode 100644 index 0000000000..96c2883392 --- /dev/null +++ b/examples/cactus-example-discounted-asset-trade-client/src/main/typescript/lib/credentials.ts @@ -0,0 +1,270 @@ +/** + * Functions for handling credentials. + */ + +import * as log from "loglevel"; +import { + CredentialState, + CredentialRecordBinding, + CredentialPreviewAttribute, +} from "@aries-framework/core"; +import { AnoncredAgent } from "./agent-setup"; + +// Constants +const WAIT_FOR_ISSUE_ACCEPT_POLL_INTERVAL = 1000; +const WAIT_FOR_ISSUE_ACCEPT_TIMEOUT = 30 * 1000; + +const JOB_CERTIFICATE_SCHEMA_NAME = "cactiJobCert"; +const JOB_CERTIFICATE_SCHEMA_ATTRS = [ + "first_name", + "last_name", + "salary", + "employee_status", + "experience", +]; + +export type JobCertificateSchema = [ + { name: "first_name"; value: string }, + { name: "last_name"; value: string }, + { name: "salary"; value: string }, + { name: "employee_status"; value: string }, + { name: "experience"; value: string }, +]; + +export type AgentCredentialSummary = { + id: string; + schemaId: string; + credentialDefinitionId: string; + connectionId: string | undefined; + credentials: CredentialRecordBinding[]; + credentialAttributes: CredentialPreviewAttribute[] | undefined; +}; + +/** + * Register employment credential schema using specified endorser DID and agent. + * + * @param agent Aries agent + * @param did endorser DID + * + * @returns schema ID + */ +export async function registerCredentialSchema( + agent: AnoncredAgent, + did: string, +): Promise { + log.info( + `Register employment certificate credential schema '${JOB_CERTIFICATE_SCHEMA_NAME}'...`, + ); + + const [createdSchema] = await agent.modules.anoncreds.getCreatedSchemas({ + schemaName: JOB_CERTIFICATE_SCHEMA_NAME, + }); + if (createdSchema) { + log.info("Schema was already registered"); + return createdSchema.schemaId; + } + + const schemaResult = await agent.modules.anoncreds.registerSchema({ + schema: { + attrNames: JOB_CERTIFICATE_SCHEMA_ATTRS, + issuerId: did, + name: JOB_CERTIFICATE_SCHEMA_NAME, + 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.schemaState.schemaId; +} + +/** + * Register employment credential definition using specified endorser DID and agent. + * + * @param agent Aries agent + * @param schemaId job credential schema id + * @param did endorser DID + * + * @returns credentialDefinitionId + */ +export async function registerCredentialDefinition( + agent: AnoncredAgent, + schemaId: string, + did: string, +): Promise { + log.info( + `Register job certificate credential definition (schemaId: '${schemaId}') ...`, + ); + + const [createdCredentialDefinition] = + await agent.modules.anoncreds.getCreatedCredentialDefinitions({ + schemaId, + issuerId: did, + }); + if (createdCredentialDefinition) { + log.info("Credential definition was already registered"); + return createdCredentialDefinition.credentialDefinitionId; + } + + const credentialDefinitionResult = + await agent.modules.anoncreds.registerCredentialDefinition({ + credentialDefinition: { + tag: "default", + issuerId: did, + schemaId: 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.credentialDefinitionState + .credentialDefinitionId; +} + +/** + * Register schema and credential definition (if not done already), and issue new credential to agent + * with specified `connectionId`. + * Will wait until credential is accepted by the peer. + * + * @param issuerAgent Aries agent + * @param credential credential to be issued + * @param connectionId peer agent connection ID + * @param did endorser DID + * @returns schemaId, credentialDefinitionId, credentialId + */ +export async function issueCredential( + issuerAgent: AnoncredAgent, + credential: JobCertificateSchema, + connectionId: string, + did: string, +): Promise<{ + schemaId: string; + credentialDefinitionId: string; + credentialId: string; +}> { + log.info("Register Credential Schema..."); + const schemaId = await registerCredentialSchema(issuerAgent, did); + log.info("Employment credential schemaId:", schemaId); + + log.info("Register Credential Definition..."); + const credentialDefinitionId = await registerCredentialDefinition( + issuerAgent, + schemaId, + did, + ); + log.info( + "Employment credential credentialDefinitionId:", + credentialDefinitionId, + ); + + log.info("Issue the credential..."); + const indyCredentialExchangeRecord = + await issuerAgent.credentials.offerCredential({ + protocolVersion: "v2", + connectionId, + credentialFormats: { + anoncreds: { + credentialDefinitionId, + attributes: credential, + }, + }, + }); + log.info("Employment credential issued:", indyCredentialExchangeRecord.id); + await waitForCredentialAcceptance( + issuerAgent, + indyCredentialExchangeRecord.id, + ); + log.info("Credential was issued and accepted by a peer agent!"); + + return { + schemaId, + credentialDefinitionId, + credentialId: indyCredentialExchangeRecord.id, + }; +} + +/** + * Block until credential was accepted by peer agent. + * + * @param agent Aries agent + * @param credentialId issued credential id + * @param timeout operation timeout (will throw exception if timeout exceeded) + */ +export async function waitForCredentialAcceptance( + agent: AnoncredAgent, + credentialId: string, + timeout = WAIT_FOR_ISSUE_ACCEPT_TIMEOUT, +): Promise { + let credentialState: CredentialState | undefined; + let counter = Math.ceil(timeout / WAIT_FOR_ISSUE_ACCEPT_POLL_INTERVAL); + + do { + counter--; + await new Promise((resolve) => + setTimeout(resolve, WAIT_FOR_ISSUE_ACCEPT_POLL_INTERVAL), + ); + + const credential = await agent.credentials.findById(credentialId); + credentialState = credential?.state; + } while ( + counter > 0 && + (!credentialState || credentialState !== CredentialState.Done) + ); + + if (counter <= 0) { + throw new Error("waitForCredentialAcceptance() timeout reached!"); + } +} + +/** + * Get summary of given agent credentials. + * + * @param agent Aries agent + * @returns list of credentials + */ +export async function getAgentCredentials( + agent: AnoncredAgent, +): Promise { + 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/lib/listeners.ts b/examples/cactus-example-discounted-asset-trade-client/src/main/typescript/lib/listeners.ts new file mode 100644 index 0000000000..92959c4a1b --- /dev/null +++ b/examples/cactus-example-discounted-asset-trade-client/src/main/typescript/lib/listeners.ts @@ -0,0 +1,114 @@ +/** + * Functions used for listening for ledger events. + */ + +import * as log from "loglevel"; +import { + CredentialStateChangedEvent, + CredentialEventTypes, + CredentialState, + ProofEventTypes, + ProofStateChangedEvent, + ProofState, + CredentialExchangeRecord, + ProofExchangeRecord, +} from "@aries-framework/core"; + +import { AnoncredAgent } from "../public-api"; + +/** + * Method to accept credential or decline it when error occurred. + * + * @param agent Aries agent + * @param credentialRecord received credential + */ +async function acceptCredential( + agent: AnoncredAgent, + credentialRecord: CredentialExchangeRecord, +) { + try { + log.info(`Accepting credential ${credentialRecord.id}...`); + + await agent.credentials.acceptOffer({ + credentialRecordId: credentialRecord.id, + }); + + log.info("Credential accepted!"); + } catch (error) { + log.error("Could not accept credential offer! Declining it..."); + agent.credentials.declineOffer(credentialRecord.id); + } +} + +/** + * Method to accept proof requests or decline it when error occurred or matching credential is missing. + * + * @param agent Aries agent + * @param proofRecord received proof + */ +async function acceptProof( + agent: AnoncredAgent, + proofRecord: ProofExchangeRecord, +) { + try { + log.info(`Accepting proof ${proofRecord.id}...`); + + const requestedCredentials = await agent.proofs.selectCredentialsForRequest( + { + proofRecordId: proofRecord.id, + }, + ); + await agent.proofs.acceptRequest({ + proofRecordId: proofRecord.id, + proofFormats: requestedCredentials.proofFormats, + }); + + log.info("Proof request accepted!"); + } catch (error) { + log.error("Could not accept proof request! Declining it..."); + await agent.proofs.declineRequest({ + proofRecordId: proofRecord.id, + sendProblemReport: true, + }); + } +} + +/** + * Setup listener that will accept all credentials send to the agent. + * + * @param agent Aries agent + */ +export function setupAcceptingCredentialListener(agent: AnoncredAgent) { + agent.events.on( + CredentialEventTypes.CredentialStateChanged, + async ({ payload }) => { + log.debug("Received credentialRecord:", payload.credentialRecord); + + switch (payload.credentialRecord.state) { + case CredentialState.OfferReceived: + await acceptCredential(agent, payload.credentialRecord); + break; + } + }, + ); +} + +/** + * Setup listener that will accept all proof requests send to the agent. + * + * @param agent Aries agent + */ +export const setupAcceptingProofListener = (agent: AnoncredAgent) => { + agent.events.on( + ProofEventTypes.ProofStateChanged, + async ({ payload }: ProofStateChangedEvent) => { + log.debug("Received proofRecord:", payload.proofRecord); + + switch (payload.proofRecord.state) { + case ProofState.RequestReceived: + await acceptProof(agent, payload.proofRecord); + break; + } + }, + ); +}; diff --git a/examples/cactus-example-discounted-asset-trade-client/src/main/typescript/lib/proofs.ts b/examples/cactus-example-discounted-asset-trade-client/src/main/typescript/lib/proofs.ts new file mode 100644 index 0000000000..ac1dcd5867 --- /dev/null +++ b/examples/cactus-example-discounted-asset-trade-client/src/main/typescript/lib/proofs.ts @@ -0,0 +1,92 @@ +/** + * Functions for handling proofs. + */ + +import * as log from "loglevel"; +import { + ProofEventTypes, + ProofStateChangedEvent, + ProofState, + ProofExchangeRecord, +} from "@aries-framework/core"; +import { AnoncredAgent } from "./agent-setup"; + +// Constants +const WAIT_FOR_PROOF_TIMEOUT = 60 * 1000; + +/** + * Sends employment proof request to the peer agent (under connectionId), waits for proof to be accepted. + * Function will timout after prederermined amount of time. + * @note it returns if any proof was accepted, not necessarily one we've sent. + * + * @param agent Aries agent + * @param credentialDefinitionId employment credential definition id + * @param connectionId peer agent connection id + * + * @returns accepted ProofExchangeRecord id + */ +export async function checkCredentialProof( + agent: AnoncredAgent, + credentialDefinitionId: string, + connectionId: string, +): Promise { + // Create proof accepted listener + const isProofOK = new Promise((resolve, reject) => { + const timeoutId = setTimeout( + () => + reject( + new Error( + "Timeout reached - could not receive proof confirmation from peer", + ), + ), + WAIT_FOR_PROOF_TIMEOUT, + ); + + // Start listener + agent.events.on( + ProofEventTypes.ProofStateChanged, + async ({ payload }: ProofStateChangedEvent) => { + log.debug("Received proofRecord:", payload.proofRecord); + + const { state } = payload.proofRecord; + if ( + state === ProofState.Done || + state === ProofState.Abandoned || + state === ProofState.Declined + ) { + clearTimeout(timeoutId); + log.info("Requested proof status:", state); + resolve(payload.proofRecord); + } + }, + ); + }); + + // Send proof request + const proofAttributes = { + employee_status: { + name: "employee_status", + restrictions: [ + { + "attr::employee_status::value": "Permanent", + cred_def_id: credentialDefinitionId, + }, + ], + }, + }; + + await agent.proofs.requestProof({ + protocolVersion: "v2", + connectionId, + proofFormats: { + anoncreds: { + name: "proof-request", + version: "1.0", + requested_attributes: proofAttributes, + }, + }, + }); + log.info("Proof request was sent"); + + return isProofOK; +} 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 0000000000..9dabe3a24b --- /dev/null +++ b/examples/cactus-example-discounted-asset-trade-client/src/main/typescript/public-api.ts @@ -0,0 +1,5 @@ +export * from "./lib/agent-setup"; +export * from "./lib/connections"; +export * from "./lib/credentials"; +export * from "./lib/listeners"; +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 0000000000..3a49885bb8 --- /dev/null +++ b/examples/cactus-example-discounted-asset-trade-client/src/main/typescript/scripts/run-discounted-asset-trade-client.ts @@ -0,0 +1,238 @@ +#!/usr/bin/env node + +/** + * Client App for interacting with discounted asset trade application. + * Make sure example app is running before starting this client! + * Client will establish connection with sample app and present menu with possible actions. + */ + +import * as log from "loglevel"; +import inquirer from "inquirer"; +import axios from "axios"; +import { + AnoncredAgent, + createAliceAgent, + createNewConnectionInvitation, + getAgentCredentials, + waitForConnection, +} from "../public-api"; + +// Logger setup +const logLevel = process.env.LOG_LEVEL ?? "INFO"; +log.setDefaultLevel(logLevel as log.LogLevelDesc); +console.log("Running with log level", logLevel); + +// Constants +const FROM_ETH_ACCOUNT_ADDR = "0xec709e1774f0ce4aba47b52a499f9abaaa159f71"; +const ESCROW_ETH_ACCOUNT_ADDR = "0x36e146d5afab61ab125ee671708eeb380aea05b6"; +const TO_ETH_ACCOUNT_ADDR = "0x9d624f7995e8bd70251f8265f2f9f2b49f169c55"; + +/** + * Main menu actions + */ +enum PromptOptions { + StartTrade = "Start the trade", + GetCredentials = "Get this agent credentials", + GetAssets = "Get assets", + Exit = "Exit", +} + +/** + * Connection ID to identify this agent on BLP side. + * Must be set during this script startup. + */ +let blpConnectionId: string | undefined; + +/** + * Creates an invitation, sends it to BLP, awaits for connection to be established. + * Sets global blpConnectionId on success. + * + * @param clientAgent this app agent + */ +async function connectAgentToBLP(clientAgent: AnoncredAgent) { + 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 + log.debug("Invitation link:", invitationUrl); + const connectResponse = await axios.post( + "http://localhost:5034/api/v1/bl/indy/connect", + { + invitationUrl, + }, + ); + log.debug("Indy connect response:", connectResponse.data); + + blpConnectionId = connectResponse.data.blpConnectionId; + if (!blpConnectionId) { + throw new Error("No this agents connectionId received from the BLP!"); + } + + // Wait for connection + await isConnectedPromise; + log.info( + "Connected to the discounted asset trade sample app agent! ID:", + blpConnectionId, + ); +} + +/** + * Sends trade request to the discounted asset trade sample app. + */ +async function sendTradeRequest() { + if (!blpConnectionId) { + throw new Error("No this agents connectionId received from the BLP!"); + } + + const connectResponse = await axios.post( + "http://localhost:5034/api/v1/bl/trades/", + { + businessLogicID: "guks32pf", + tradeParams: [ + "0xec709e1774f0ce4aba47b52a499f9abaaa159f71", + "0x9d624f7995e8bd70251f8265f2f9f2b49f169c55", + "Brad", + "Cathy", + "asset2", + blpConnectionId, + ], + authParams: ["<>"], + }, + ); + log.info("Trade request sent! Response:", connectResponse.data); +} + +/** + * Print this agent credentials from a wallet (in a simplified form). + * + * @param agent this app agent + */ +async function printAgentCredentials(agent: AnoncredAgent) { + const credentials = await getAgentCredentials(agent); + log.info(JSON.stringify(credentials, undefined, 2)); +} + +/** + * Gets asset summary from BLP (both ethereum and fabric). + */ +async function getAssetsFromSampleApp() { + // Read ethereum balances + const fromAccountResponse = await axios.get( + `http://localhost:5034/api/v1/bl/balance/${FROM_ETH_ACCOUNT_ADDR}`, + ); + log.info("\n# Ethereum fromAccount:"); + log.info(fromAccountResponse.data); + + const escrowAccountResponse = await axios.get( + `http://localhost:5034/api/v1/bl/balance/${ESCROW_ETH_ACCOUNT_ADDR}`, + ); + log.info("\n# Ethereum escrowAccount:"); + log.info(escrowAccountResponse.data); + + const toAccountResponse = await axios.get( + `http://localhost:5034/api/v1/bl/balance/${TO_ETH_ACCOUNT_ADDR}`, + ); + log.info("\n# Ethereum toAccount:"); + log.info(toAccountResponse.data); + + // Read fabric assets + const fabricResponse = await axios.get( + "http://localhost:5034/api/v1/bl/fabric-asset/", + ); + log.info("\n# Fabric:"); + log.info(fabricResponse.data); +} + +/** + * Show menu prompt and wait for action select. + * + * @returns action selected + */ +async function getPromptChoice() { + return inquirer.prompt({ + type: "list", + prefix: "", + name: "menu", + message: "Action:", + choices: Object.values(PromptOptions), + }); +} + +/** + * Main application loop, will print menu with actions. + * + * @param agent this app agent + */ +async function menuLoop(agent: AnoncredAgent) { + 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; + } + if (axios.isAxiosError(error)) { + log.error( + `Request error: ${error.name} ${error.message} - ${JSON.stringify( + error.response?.data, + )}`, + ); + } else { + log.error("Menu action error:", error); + } + } + } +} + +/** + * Main application logic. + */ +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) { + if (axios.isAxiosError(error)) { + log.error( + `Request error: ${error.name} ${error.message} - ${JSON.stringify( + error.response?.data, + )}`, + ); + } else { + log.error("Client app error:", error); + } + } finally { + log.info("Exiting the client app..."); + aliceAgent.shutdown(); + } +} + +// Run the main logic +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 new file mode 100644 index 0000000000..466348b423 --- /dev/null +++ b/examples/cactus-example-discounted-asset-trade-client/src/main/typescript/scripts/setup-credentials.ts @@ -0,0 +1,76 @@ +#!/usr/bin/env node + +/** + * Simple script for setting up employment credential on the ledger and issuing one to Alice. + * Alice can later use it when interacting with discounted asset trade app. + * Script can also be used to verify whether test indy ledger is operational. + */ + +import * as log from "loglevel"; +import { + createAliceAgent, + createIssuerAgent, + connectAgents, + issueCredential, + checkCredentialProof, +} from "../public-api"; + +// Logger setup +const logLevel = process.env.LOG_LEVEL ?? "INFO"; +log.setDefaultLevel(logLevel as log.LogLevelDesc); +console.log("Running with log level", logLevel); + +/** + * Main setup script logic. + * Creates agents for Alice and Issuer, connects them, registers credentials, issues it to Alice, and verify the proof. + */ +async function run() { + const aliceAgent = await createAliceAgent(); + log.debug("Alice agent created"); + + const { agent: issuerAgent, did: issuerDid } = await createIssuerAgent(); + log.debug("Issuer agent created."); + log.debug("Issuer endorsing DID:", issuerDid); + + try { + log.info("Connecting Alice with Issuer..."); + const [aliceAgentConRecord, issuerAgentConRecord] = await connectAgents( + aliceAgent, + issuerAgent, + ); + log.debug("Alice connection ID:", aliceAgentConRecord.id); + log.debug("Issuer connection ID:", issuerAgentConRecord.id); + + log.info("Register and issue the employment credential..."); + 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, + issuerDid, + ); + + log.info("Verify employment status proof..."); + await checkCredentialProof( + issuerAgent, + credentialDefinitionId, + issuerAgentConRecord.id, + ); + } catch (error) { + log.error("Error when running setup scenario:", error); + } finally { + log.info("Finishing - cleaning up the agents..."); + await aliceAgent.shutdown(); + await issuerAgent.shutdown(); + } + + log.info("All done."); +} + +// Run the script logic +run(); diff --git a/examples/cactus-example-discounted-asset-trade-client/tsconfig.json b/examples/cactus-example-discounted-asset-trade-client/tsconfig.json new file mode 100644 index 0000000000..eb4d409fa9 --- /dev/null +++ b/examples/cactus-example-discounted-asset-trade-client/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "composite": true, + "outDir": "./dist/lib/", + "declarationDir": "dist/lib", + "rootDir": "./src", + "tsBuildInfoFile": "../../.build-cache/cactus-example-discounted-asset-trade-client.tsbuildinfo" + }, + "include": ["./src"] +} diff --git a/examples/cactus-example-discounted-asset-trade/Dockerfile b/examples/cactus-example-discounted-asset-trade/Dockerfile index de05eec284..61a5698b21 100644 --- a/examples/cactus-example-discounted-asset-trade/Dockerfile +++ b/examples/cactus-example-discounted-asset-trade/Dockerfile @@ -1,25 +1,12 @@ FROM cactus-cmd-socketio-server:latest ARG NPM_PKG_VERSION=latest -ARG INDY_SDK_PKG_VERSION=1.16.0-dev-1649 - ENV APP_HOME=/root/cactus WORKDIR ${APP_HOME} -# Required by indy-sdk -RUN apt-get update \ - && apt-get install -y libsodium23 \ - libssl1.1 \ - libzmq5 \ - && rm -rf /var/lib/apt/lists/* - -# Copy indy sdk lib from base ubuntu image -# Note - indy_sdk:latest must be ABI compatible with this image OS -COPY --from=indy-sdk-cli:latest /usr/lib/libindy.so /usr/lib/ - COPY ./package.json ./dist/yarn.lock ./ -RUN yarn add "${CACTUS_CMD_SOCKETIO_PATH}" "@hyperledger/cactus-verifier-client@${NPM_PKG_VERSION}" "indy-sdk@${INDY_SDK_PKG_VERSION}" \ +RUN yarn add "${CACTUS_CMD_SOCKETIO_PATH}" \ --production --ignore-engines --non-interactive --cache-folder ./.yarnCache && \ rm -rf ./.yarnCache diff --git a/examples/cactus-example-discounted-asset-trade/README.md b/examples/cactus-example-discounted-asset-trade/README.md index b0aa4c0630..3f0e40fe2c 100644 --- a/examples/cactus-example-discounted-asset-trade/README.md +++ b/examples/cactus-example-discounted-asset-trade/README.md @@ -22,7 +22,10 @@ Alice knows that Acme Corp. provides digital certificates. She asks Acme Corp. t ### When Alice Uses the Service -Alice will use credentials and other Indy formats such as schema and definition to create an employee proof that she will present when purchasing the asset. Alice then sends a purchase order and her employee proof to the Cactus Node Server via an End User Application. The employee proofs consist of proof requests and proofs on Hyperledger Indy. The Cactus Node server receives the schema and definition from the Indy ledger via Validator and uses this information to verify the proof with the BLP. Once verified, the BLP will decide what she should pay based on the price list and then proceed with the business logic using cactus as an escrow to transfer ETH currencies and asset ownership tokens to each other. +- Alice will use her client application to connect with discounted-asset-trade BLP application. This will create anoncreds connection between her and the BLP app. +- Alice will send a purchase order to the BLP application. +- BLP will request the proof of employment from Alice client application. +- Once verified, the BLP will decide what she should pay based on the price list and then proceed with the business logic using cactus as an escrow to transfer ETH currencies and asset ownership tokens to each other. ## Setup Overview @@ -36,25 +39,6 @@ Alice will use credentials and other Indy formats such as schema and definition - Validator for ethereum ledger. - Started as part of discounted asset trade BLP. -### indy-sdk-cli-base-image - -- Base image for indy validator. -- It will build the image and immediately exit on run. - -### indy-validator - -- Validator for indy ledger. -- Assumes ledger runs at `172.16.0.2` -- Docker network: `indy-testnet_indy_net` -- Accessed only by nginx proxy container. - -### indy-validator-nginx - -- Load balancer / gateway for indy validator. -- Use it's endpoint to talk to indy validator. -- Uses config from `./nginx/nginx.conf` -- Docker network: `indy-testnet_indy_net`, `cactus-example-discounted-asset-trade-net` - ### cmd-socketio-base-image - Base image for `cactus-example-discounted-asset-trade` BLP. @@ -67,12 +51,6 @@ Alice will use credentials and other Indy formats such as schema and definition - Use it's endpoint (`localhost:5034`) to interact the bussiness logic. - Docker network: `cactus-example-discounted-asset-trade-net` -### register-indy-data - -- Setup application. -- Will generate proof and store it in local configuration on startup. -- This application can also be used to send requests to the BLP. - ## Indy Schema ![Indy node pool and validator](./image/indy-setup-schema.svg) @@ -99,7 +77,55 @@ Alice will use credentials and other Indy formats such as schema and definition - On success, this should start three containers: - `geth1` - `asset_trade_faio2x_testnet` - - `indy-testnet-pool` + - `asset_trade_indy_all_in_one` + +1. Setup Indy credentials: + - Before running the sample application we need to register employment credential and issue it to Alice (user of our app). + - Use `setup-credentials` script from `cactus-example-discounted-asset-trade-client`. + +```bash +# In separat shell (can be used later for client app) +cd ./examples/cactus-example-discounted-asset-trade-client +yarn setup-credentials +popd +``` + +- Copy the credential definition ID from the script output into this example application BLP configuration. + +```bash +# setup-credentials script output +Running with log level INFO +Connecting Alice with Issuer... +Connecting aliceCactiAgent to issuerCactiAgent... +Agents connected! +Register and issue the employment credential... +Register Credential Schema... +Register employment certificate credential schema 'cactiJobCert'... +Employment credential schemaId: did:indy:cacti:test:Th7MpTaRZVRYnPiabds81Y/anoncreds/v0/SCHEMA/cactiJobCert/1.0.0 +Register Credential Definition... +Register job certificate credential definition (schemaId: 'did:indy:cacti:test:Th7MpTaRZVRYnPiabds81Y/anoncreds/v0/SCHEMA/cactiJobCert/1.0.0') ... +# COPY THIS >> +Employment credential credentialDefinitionId: did:indy:cacti:test:Th7MpTaRZVRYnPiabds81Y/anoncreds/v0/CLAIM_DEF/11/default +# << +Issue the credential... +Employment credential issued: 7f93ba15-98b2-4667-a7cf-ecec3059e9d4 +Accepting credential eb69032d-ec73-4fa1-bd83-1ff52a0dc4b5... +Credential accepted! +Credential was issed and accepted by a peer agent! +Verify employment status proof... +Proof request was sent +Accepting proof 4d03e479-073a-4f51-98e4-befd7ba34345... +Proof request accepted! +Requested proof status: done +Finishing - cleaning up the agents... +All done. + +# Replace __CREDENTIAL_DEFINITION_ID__ in config file with actual credentialDefinitionId +sed -i 's#__CREDENTIAL_DEFINITION_ID__#did:indy:cacti:test:Th7MpTaRZVRYnPiabds81Y/anoncreds/v0/CLAIM_DEF/11/default#g' "./etc/cactus/usersetting.yaml" + +# ... or do it manually in text editor +vim ./etc/cactus/usersetting.yaml +``` 1. Launch discounted-asset-trade and validators from local `docker-compose.yml` (use separate console for that, docker-compose will block your prompt): @@ -119,11 +145,6 @@ Alice will use credentials and other Indy formats such as schema and definition ... cmd-socketio-base-dummy exited with code 0 ... - indy-sdk-cli-base-dummy exited with code 0 - ... - register-indy-data | Done. - register-indy-data exited with code 0 - ... cactus-example-discounted-asset-trade-blp | [2022-01-31T16:00:56.208] [INFO] www - listening on *: 5034 ``` @@ -131,133 +152,151 @@ Alice will use credentials and other Indy formats such as schema and definition For development purposes, it might be useful to run the sample application outside of docker-compose environment. -1. Install Indy SDK required by this sample app: - - [Installing the SDK](https://github.com/hyperledger/indy-sdk#installing-the-sdk) - - [Build the SDK from source](https://github.com/hyperledger/indy-sdk#how-to-build-indy-sdk-from-source) - - Or use these steps for Ubuntu 20.04: - ```bash - sudo apt-get install ca-certificates -y \ - && sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys CE7709D068DB5E88 \ - && sudo add-apt-repository "deb https://repo.sovrin.org/sdk/deb bionic stable" \ - && sudo apt-get update \ - && sudo apt-get install -y \ - libindy \ - libnullpay \ - libvcx \ - indy-cli \ - && sudo rm -f /etc/apt/sources.list.d/sovrin.list* - ``` -1. Add indy-sdk node package: `yarn add indy-sdk@1.16.0-dev-1649` (or edit `package.json` directly) 1. Configure cactus and start the ledgers as described above. 1. Run `./script-dockerless-config-patch.sh` from `cactus-example-discounted-asset-trade/` directory. This will patch the configs and copy it to global location. -1. Start Indy validator (in separate cmd window). - 1. ```bash - docker build tools/docker/indy-sdk-cli -t indy-sdk-cli && - pushd packages-python/cactus_validator_socketio_indy/ && sh ./setup_indy.sh && popd && - docker build packages-python/cactus_validator_socketio_indy/ -t indy-validator && - docker run -v/etc/cactus/:/etc/cactus --rm --net="indy-testnet_indy_net" -p 10080:8000 indy-validator - ``` 1. Start asset-trade: `npm run start-dockerless` ## How to use this application -1. (Optional) Check the balance on Ethereum and the asset ownership on Fabric using the following script: - - ``` - node ./read-ledger-state.js - ``` - - The result looks like the following (simplified output): - - ``` - # Ethereum fromAccount: - 1e+26 - - # Ethereum escrowAccount: - 0 - - # Ethereum toAccount: - 0 - - - # Fabric: - [ - { - ... - }, - { - ID: 'asset2', - color: 'red', - size: 5, - owner: 'Brad', - appraisedValue: 400 - }, - ... - ] - ``` - -1. Run the transaction execution: - - ``` - ./script-post-trade-request.sh - ``` - - ... or send request manually: - - ``` - docker run --rm -ti -v "$(pwd)/etc/cactus/":"/etc/cactus/" --net="host" register-indy-data - ``` - - **After sending the requests** - - - The transactions are executed by order. - - When the following log appears on the BLP console, the transactions are completed (you may need to scroll a bit to find it). - - ``` - [INFO] BusinessLogicAssetTrade - ##INFO: completed asset-trade, businessLogicID: guks32pf, tradeID: *******-001 - ``` - -1. (Optional) Check the balance on Ethereum and the asset ownership on Fabric using the following script - - ``` - node ./read-ledger-state.js - ``` - - The result looks like the following (simplified output). In the following case, 50 coins from `fromAccount` was transferred to `toAccount`, and the asset ownership ("owner") was transferred from Brad to Cathy. - - ``` - # Ethereum fromAccount: - 100000184999999999999999975 - - # Ethereum escrowAccount: - 0 - - # Ethereum toAccount: - 25 - - - # Fabric: - [ - { - ... - }, - { - ID: 'asset2', - color: 'red', - size: 5, - owner: 'Cathy', - appraisedValue: 400 - }, - ... - ] - ``` +- Use `run-discounted-asset-trade-client` script from `cactus-example-discounted-asset-trade-client` to interact with this application. + +```bash +# In separat shell +cd ./examples/cactus-example-discounted-asset-trade-client +yarn run-discounted-asset-trade-client + +# Sample output +Running with log level INFO +Connected to the discounted asset trade sample app agent! ID: 19949a1e-0ef6-449b-9c37-256449258b51 +Action: (Use arrow keys) +❯ Start the trade + Get this agent credentials + Get assets + Exit +``` + +1. (Optional) Check credentials in Alice wallet by selecting `Get this agent credentials`. + +```bash +Action: Get this agent credentials +[ + { + "id": "eb69032d-ec73-4fa1-bd83-1ff52a0dc4b5", + "schemaId": "did:indy:cacti:test:Th7MpTaRZVRYnPiabds81Y/anoncreds/v0/SCHEMA/cactiJobCert/1.0.0", + # Note: This credential matches one we'll be requesting in discounted asset trade example + "credentialDefinitionId": "did:indy:cacti:test:Th7MpTaRZVRYnPiabds81Y/anoncreds/v0/CLAIM_DEF/11/default", + "connectionId": "32134b50-a245-4de5-8408-f35fcb069373", + "credentials": [ + { + "credentialRecordType": "anoncreds", + "credentialRecordId": "dd6aba0c-8674-451d-a063-a630004be1dd" + } + ], + "credentialAttributes": [ + { + "mime-type": "text/plain", + "name": "first_name", + "value": "Alice" + }, + { + "mime-type": "text/plain", + "name": "last_name", + "value": "Garcia" + }, + { + "mime-type": "text/plain", + "name": "salary", + "value": "2400" + }, + { + "mime-type": "text/plain", + "name": "employee_status", + # Note: Alice is a permanent employee + "value": "Permanent" + }, + { + "mime-type": "text/plain", + "name": "experience", + "value": "10" + } + ] + } +] +``` + +1. (Optional) Check the balance on Ethereum and the asset ownership on Fabric by selecting `Get assets`. + +```bash +Action: Get assets + +# Ethereum fromAccount: +1.00005515e+26 + +# Ethereum escrowAccount: +0 + +# Ethereum toAccount: +0 + +# Fabric: +[ + { + ... + }, + { + ID: 'asset2', + color: 'red', + size: 5, + owner: 'Brad', + appraisedValue: 400 + }, + ... +] +``` + +1. Run the transaction execution by selecting `Start the trade` + +```bash +Action: Start the trade +Trade request sent! Response: { tradeID: '20231103185232057-001' } +``` + +1. (Optional) Check the final balance on Ethereum and the asset ownership on Fabric by selecting `Get assets`. + +```bash +Action: Get assets + +# Ethereum fromAccount: +1.000057e+26 + +# Ethereum escrowAccount: +0 + +# Ethereum toAccount: +25 + +# Fabric: +[ + { + ... + }, + { + ID: 'asset2', + color: 'red', + size: 5, + owner: 'Cathy', + appraisedValue: 400 + }, + ... +] ## How to stop the application and Docker containers 1. Press `Ctrl+C` in `docker-compose` console to stop the application. 1. Run cleanup script ``` - sudo ./script-cleanup.sh + sudo ./script-cleanup.sh # for root owned files + ./script-cleanup.sh # for user owner files ``` #### Manual cleanup instructions @@ -268,17 +307,20 @@ For development purposes, it might be useful to run the sample application outsi ``` 1. Stop the docker containers of Ethereum, Fabric and Indy - - `docker stop geth1 asset_trade_faio2x_testnet indy-testnet-pool` - - `docker rm geth1 asset_trade_faio2x_testnet indy-testnet-pool` + - `docker stop geth1 asset_trade_faio2x_testnet asset_trade_indy_all_in_one` + - `docker rm geth1 asset_trade_faio2x_testnet asset_trade_indy_all_in_one` + +1. Clear indy-all-in-one -1. Clear indy testnet sandbox ``` - pushd ../../tools/docker/indy-testnet/ + pushd ../../tools/docker/indy-all-in-one/ ./script-cleanup.sh popd ``` -#### Possible improvements -- Ethereum events are duplicated, causing trade to proceed even if previous step was not successfull. - - Handle this case properly - ignore duplciated events, move forward only if current step was completed. - - Investigate and fix duplicated events in Verifier / Ethereum connector (or use openapi ethereum connector). +1. Remove geth files + ``` + pushd ../../tools/docker/geth-testnet/ + rm -fr ./data-geth1/geth/ + popd + ``` diff --git a/examples/cactus-example-discounted-asset-trade/business-logic-asset-trade.ts b/examples/cactus-example-discounted-asset-trade/business-logic-asset-trade.ts index e2f6ed9385..9b23867198 100644 --- a/examples/cactus-example-discounted-asset-trade/business-logic-asset-trade.ts +++ b/examples/cactus-example-discounted-asset-trade/business-logic-asset-trade.ts @@ -15,7 +15,7 @@ import { BusinessLogicInquireAssetTradeStatus } from "./business-logic-inquire-a import { TxInfoData } from "./tx-info-data"; import { BusinessLogicBase } from "@hyperledger/cactus-cmd-socketio-server"; import { transferOwnership } from "./transaction-fabric"; -import { getDataFromIndy } from "./transaction-indy"; +import { isEmploymentCredentialProofValid } from "./transaction-indy"; import { LedgerEvent, ConfigUtil, @@ -44,11 +44,6 @@ const moduleName = "BusinessLogicAssetTrade"; const logger = getLogger(`${moduleName}`); logger.level = config.logLevel; -const indy = require("indy-sdk"); -const assert = require("assert"); -const identifierSchema = "schema"; -const identifierCredDef = "credDef"; - interface TransactionStatusData { stateInfo: number | undefined; transactionStatus: { @@ -81,10 +76,8 @@ export class BusinessLogicAssetTrade extends BusinessLogicBase { requestInfo.tradeInfo.ethereumAccountTo = req.body.tradeParams[1]; requestInfo.tradeInfo.fabricAccountFrom = req.body.tradeParams[2]; requestInfo.tradeInfo.fabricAccountTo = req.body.tradeParams[3]; - //requestInfo.tradeInfo.tradingValue = req.body.tradeParams[4]; requestInfo.tradeInfo.assetID = req.body.tradeParams[4]; - requestInfo.tradeInfo.proofJson = JSON.parse(req.body.tradeParams[5]); - // requestInfo.authInfo.company = req.body.authParams[0]; + requestInfo.tradeInfo.indyAgentConId = req.body.tradeParams[5]; // set TradeID requestInfo.setTradeID(tradeID); @@ -96,23 +89,19 @@ export class BusinessLogicAssetTrade extends BusinessLogicBase { this.Pricing(requestInfo) .then((result) => { requestInfo = result; - // Create trade information const tradeInfo: TradeInfo = new TradeInfo( requestInfo.businessLogicID, requestInfo.tradeID, ); - // Save transaction value transactionInfo.setRequestInfo(1, requestInfo); this.transactionInfoManagement.addTransactionInfo(transactionInfo); - // trade status update this.transactionInfoManagement.setStatus( tradeInfo, AssetTradeStatus.UnderEscrow, ); - this.firstTransaction(requestInfo, tradeInfo); }) .catch((err) => { @@ -167,9 +156,16 @@ export class BusinessLogicAssetTrade extends BusinessLogicBase { // price list const priceList = { default: "50", employee: "25" }; - logger.debug(JSON.stringify(requestInfo.tradeInfo.proofJson)); - const isPreferredCustomer = await this.isPreferredCustomer( - requestInfo.tradeInfo.proofJson, + const credentialDefinitionId = + config?.assetTradeInfo?.indy?.credentialDefinitionId; + if (!credentialDefinitionId) { + throw new Error( + "Missing employment credentialDefinitionId! Can't proof employment status!", + ); + } + const isPreferredCustomer = await isEmploymentCredentialProofValid( + requestInfo.tradeInfo.indyAgentConId, + credentialDefinitionId, ); // decide the price from result of isPreferredCustomer @@ -184,119 +180,6 @@ export class BusinessLogicAssetTrade extends BusinessLogicBase { return requestInfo; } - async isPreferredCustomer(input_obj: { - tradeInfo: string; - proof_request: string; - proof: string; - }): Promise { - let proofRequestJson; - let proofJson; - try { - proofRequestJson = JSON.parse(input_obj["proof_request"]); - proofJson = JSON.parse(input_obj["proof"]); - } catch (err) { - logger.error( - "Error while reading proof and proof request. returning false.", - ); - return false; - } - - // get schema & credential definition from indy - // now verifierGetEntitiesFromLedger don't get revRegDefs & revRegs - // did is null. If it is null, indy.buidlGetSchemaRequest API get data by default param. - const [schemasJson, credDefsJson, revRegDefsJson, revRegsJson] = - await this.verifierGetEntitiesFromLedger(null, proofJson["identifiers"]); - - assert( - "Permanent" === - proofJson["requested_proof"]["revealed_attrs"]["attr1_referent"]["raw"], - ); - - logger.debug( - `##isPreferredCustomer verifierGetEntitiesFromLedger schemasJson : ${JSON.stringify( - schemasJson, - )}`, - ); - logger.debug( - `##isPreferredCustomer verifierGetEntitiesFromLedger credDefsJson : ${JSON.stringify( - credDefsJson, - )}`, - ); - logger.debug( - `##isPreferredCustomer verifierGetEntitiesFromLedger revRegDefsJson : ${JSON.stringify( - revRegDefsJson, - )}`, - ); - logger.debug( - `##isPreferredCustomer verifierGetEntitiesFromLedger revRegsJson : ${JSON.stringify( - revRegsJson, - )}`, - ); - - try { - const verif_result = await indy.verifierVerifyProof( - proofRequestJson, - proofJson, - schemasJson, - credDefsJson, - revRegDefsJson, - revRegsJson, - ); - logger.debug("verify proof: " + (verif_result ? "ok" : "not ok")); - return verif_result; - } catch (err) { - logger.error( - "error raised during indy.verifierVerifyProof() invocation. defaulting to false (= NO DISCOUNT)", - ); - logger.error(err); - return false; - } - } - - async verifierGetEntitiesFromLedger( - did: string | null, - identifiers: { - [keyof: string]: { schema_id: string; cred_def_id: string }; - }, - ): Promise< - [ - Record, - Record, - Record, - Record, - ] - > { - const schemas: { [keyof: string]: string } = {}; - const credDefs: { [keyof: string]: string } = {}; - const revRegDefs = {}; - const revRegs = {}; - - for (const referent of Object.keys(identifiers)) { - const item = identifiers[referent]; - const args_request_getSchema = { did: did, schemaId: item["schema_id"] }; - const responseSchema: { - data: string[]; - } = await getDataFromIndy(args_request_getSchema, identifierSchema); - const [receivedSchemaId, receivedSchema] = responseSchema["data"]; - schemas[receivedSchemaId] = JSON.parse(receivedSchema); - - const args_request_getCredDef = { - did: did, - schemaId: item["cred_def_id"], - }; - const responseCredDef: { - data: string[]; - } = await getDataFromIndy(args_request_getCredDef, identifierCredDef); - - const [receivedCredDefId, receivedCredDef] = responseCredDef["data"]; - credDefs[receivedCredDefId] = JSON.parse(receivedCredDef); - } - - logger.debug("finish get Data from indy"); - - return [schemas, credDefs, revRegDefs, revRegs]; - } - /** * Eth Escrow */ diff --git a/examples/cactus-example-discounted-asset-trade/config/usersetting.yaml b/examples/cactus-example-discounted-asset-trade/config/usersetting.yaml index dafa0f2206..72f8740528 100644 --- a/examples/cactus-example-discounted-asset-trade/config/usersetting.yaml +++ b/examples/cactus-example-discounted-asset-trade/config/usersetting.yaml @@ -19,6 +19,8 @@ appRouters: routerJs: /root/cactus/dist/balance.js - path: /api/v1/bl/fabric-asset/ routerJs: /root/cactus/dist/fabric-asset.js + - path: /api/v1/bl/indy/ + routerJs: /root/cactus/dist/indy-endpoints.js # BLP Config assetTradeInfo: @@ -46,6 +48,9 @@ assetTradeInfo: channelName: mychannel chaincodeID: basic + indy: + credentialDefinitionId: "__CREDENTIAL_DEFINITION_ID__" + ethereum: validatorID: 84jUisrs gethURL: ws://localhost:8546 diff --git a/examples/cactus-example-discounted-asset-trade/config/validator-registry-config.yaml b/examples/cactus-example-discounted-asset-trade/config/validator-registry-config.yaml index 6dfa188b3b..eaac33e158 100644 --- a/examples/cactus-example-discounted-asset-trade/config/validator-registry-config.yaml +++ b/examples/cactus-example-discounted-asset-trade/config/validator-registry-config.yaml @@ -1,18 +1,3 @@ -ledgerPluginInfo: - - validatorID: 3PfTJw8g - validatorType: legacy-socketio - validatorURL: http://indy-validator-nginx:10080 - validatorKeyPath: /etc/cactus/validator_socketio_indy/CA/connector.crt - maxCounterRequestID: 100 - syncFunctionTimeoutMillisecond: 5000 - socketOptions: - rejectUnauthorized: false - reconnection: false - timeout: 20000 - ledgerInfo: - ledgerAbstract: "Indy Ledger" - apiInfo: [] - signTxInfo: fabric: mspID: Org1MSP diff --git a/examples/cactus-example-discounted-asset-trade/docker-compose.yml b/examples/cactus-example-discounted-asset-trade/docker-compose.yml index 626f280439..23cd987c28 100644 --- a/examples/cactus-example-discounted-asset-trade/docker-compose.yml +++ b/examples/cactus-example-discounted-asset-trade/docker-compose.yml @@ -12,48 +12,6 @@ services: context: ../../packages/cactus-cmd-socketio-server/ command: ["echo", "OK - Exit"] - indy-sdk-cli-base-image: - # Build base image and immediately exit - container_name: indy-sdk-cli-base-dummy - image: indy-sdk-cli - build: - context: ../../tools/docker/indy-sdk-cli - command: ["echo", "OK - Exit"] - - indy-validator: - container_name: cactus-example-discounted-asset-trade-indy-validator - image: cactus_validator_socketio_indy - environment: - - TEST_POOL_IP=172.16.0.2 - depends_on: - - indy-sdk-cli-base-image - build: - context: ../../packages-python/cactus_validator_socketio_indy - dockerfile: Dockerfile - ports: - - "8000:8000" - volumes: - - type: bind - source: ./etc/cactus - target: /etc/cactus - networks: - - indy-testnet_indy_net - - indy-validator-nginx: - container_name: cactus-example-discounted-asset-trade-indy-validator-nginx - image: nginx:1.20-alpine - volumes: - - type: bind - source: "./nginx/nginx.conf" - target: "/etc/nginx/nginx.conf" - depends_on: - - indy-validator - ports: - - "10080:10080" - networks: - - indy-testnet_indy_net - - cactus-example-discounted-asset-trade-net - cactus-example-discounted-asset-trade-blp: container_name: cactus-example-discounted-asset-trade-blp image: cactus-example-discounted-asset-trade-blp @@ -64,36 +22,14 @@ services: networks: - cactus-example-discounted-asset-trade-net depends_on: - - indy-validator-nginx - cmd-socketio-base-image - - indy-sdk-cli-base-image - volumes: - - type: bind - source: ./etc/cactus - target: /etc/cactus - - register-indy-data: - container_name: register-indy-data - image: register-indy-data - environment: - - TEST_POOL_IP=172.16.0.2 - build: - context: ../register-indy-data - networks: - - indy-testnet_indy_net - depends_on: - - cactus-example-discounted-asset-trade-blp volumes: - type: bind source: ./etc/cactus target: /etc/cactus - # One-off command executed in container that will store a proof in /etc/cactus - command: ["--proof_only"] networks: fabric-all-in-one_testnet-2x: external: true - indy-testnet_indy_net: - external: true cactus-example-discounted-asset-trade-net: driver: bridge diff --git a/examples/cactus-example-discounted-asset-trade/indy-agent.ts b/examples/cactus-example-discounted-asset-trade/indy-agent.ts new file mode 100644 index 0000000000..80feaf5377 --- /dev/null +++ b/examples/cactus-example-discounted-asset-trade/indy-agent.ts @@ -0,0 +1,49 @@ +/** + * Defines Indy Aries JS Agent that will be used to verify proofs. + * TODO - Initialize Indy connector instead of agent here (once indy connector is ready) + */ + +import { getLogger } from "log4js"; +import { ConfigUtil } from "@hyperledger/cactus-cmd-socketio-server"; +import { + setupAgent, + AnoncredAgent, +} from "@hyperledger/cactus-example-discounted-asset-trade-client"; + +const config: any = ConfigUtil.getConfig(); +const moduleName = "indy-agent"; +const logger = getLogger(`${moduleName}`); +logger.level = config.logLevel; + +const BLP_AGENT_NAME = "cactiDiscountedAssetTradeAgent"; +const BLP_AGENT_PORT = 5035; + +// Single BLP indy agent instance +let blpAgent: AnoncredAgent | undefined = undefined; + +/** + * Create indy agent for this BLP app + */ +export async function initIndyAgent(): Promise { + if (!blpAgent) { + blpAgent = await setupAgent(BLP_AGENT_NAME, BLP_AGENT_PORT); + logger.info("initIndyAgent() done."); + } else { + logger.info("initIndyAgent() Indy agent already initialized"); + } +} + +/** + * Get instance of indy agent + */ +export async function getIndyAgent(): Promise { + if (!blpAgent) { + await initIndyAgent(); + } + + if (blpAgent) { + return blpAgent; + } else { + throw new Error("Could not initialize new indy agent!"); + } +} diff --git a/examples/cactus-example-discounted-asset-trade/indy-endpoints.ts b/examples/cactus-example-discounted-asset-trade/indy-endpoints.ts new file mode 100644 index 0000000000..ea1bf7c78a --- /dev/null +++ b/examples/cactus-example-discounted-asset-trade/indy-endpoints.ts @@ -0,0 +1,48 @@ +/** + * Endpoints for interacting with this sample app Indy agent. + */ + +import { Router, NextFunction, Request, Response } from "express"; +import escapeHtml from "escape-html"; +import { getLogger } from "log4js"; +import { ConfigUtil } from "@hyperledger/cactus-cmd-socketio-server"; +import { connectToClientAgent } from "./transaction-indy"; + +const config: any = ConfigUtil.getConfig(); +const moduleName = "indy-endpoints"; +const logger = getLogger(`${moduleName}`); +logger.level = config.logLevel; + +const router: Router = Router(); + +/** + * POST + * Connect to the client indy agent. + * Caller must supply it's invitationUrl and accept the connection. + */ +router.post( + "/connect", + async (req: Request, res: Response, next: NextFunction) => { + try { + const invitationUrl = req.body.invitationUrl as string; + if (!invitationUrl || typeof invitationUrl !== "string") { + throw new Error(`Missing invitationUrl in the request body`); + } + + logger.debug("Connecting to Indy agent with invitation:", invitationUrl); + const blpConnectionId = await connectToClientAgent(invitationUrl); + + res.status(200).json({ + message: "Invitation accepted", + blpConnectionId, + }); + } catch (err) { + res.status(500).send({ + error: escapeHtml(err), + }); + next(err); + } + }, +); + +export default router; diff --git a/examples/cactus-example-discounted-asset-trade/nginx/nginx.conf b/examples/cactus-example-discounted-asset-trade/nginx/nginx.conf deleted file mode 100644 index 4d80ea5edc..0000000000 --- a/examples/cactus-example-discounted-asset-trade/nginx/nginx.conf +++ /dev/null @@ -1,46 +0,0 @@ -# Based on default nginx:1.20-alpine config - -user nginx; -worker_processes auto; - -#error_log /dev/stdout info; -error_log /var/log/nginx/error.log notice; -pid /var/run/nginx.pid; - -events { - worker_connections 1024; -} - -http { - include /etc/nginx/mime.types; - default_type application/octet-stream; - - log_format main '$remote_addr - $remote_user [$time_local] "$request" ' - '$status $body_bytes_sent "$http_referer" ' - '"$http_user_agent" "$http_x_forwarded_for"'; - - #access_log /dev/stdout; - access_log /var/log/nginx/access.log main; - sendfile on; - keepalive_timeout 65; - - map $http_upgrade $connection_upgrade { - default upgrade; - '' close; - } - - server { - listen 10080; - charset utf-8; - - location / { - proxy_pass http://indy-validator:8000; - proxy_http_version 1.1; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection $connection_upgrade; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header Host $host; - proxy_read_timeout 120s; - } - } -} diff --git a/examples/cactus-example-discounted-asset-trade/package.json b/examples/cactus-example-discounted-asset-trade/package.json index 05515f59e3..e2f45e56cc 100644 --- a/examples/cactus-example-discounted-asset-trade/package.json +++ b/examples/cactus-example-discounted-asset-trade/package.json @@ -19,10 +19,10 @@ "@hyperledger/cactus-common": "2.0.0-alpha.2", "@hyperledger/cactus-core": "2.0.0-alpha.2", "@hyperledger/cactus-core-api": "2.0.0-alpha.2", + "@hyperledger/cactus-example-discounted-asset-trade-client": "2.0.0-alpha.2", "@hyperledger/cactus-plugin-keychain-memory": "2.0.0-alpha.2", "@hyperledger/cactus-plugin-ledger-connector-ethereum": "2.0.0-alpha.2", "@hyperledger/cactus-plugin-ledger-connector-fabric": "2.0.0-alpha.2", - "@hyperledger/cactus-verifier-client": "2.0.0-alpha.2", "@types/node": "14.18.54", "axios": "1.5.1", "body-parser": "1.20.2", @@ -52,7 +52,6 @@ "@types/elliptic": "6.4.14", "@types/escape-html": "1.0.1", "@types/express": "4.17.19", - "@types/indy-sdk": "1.16.29", "@types/jsonwebtoken": "9.0.2", "@types/jsrsasign": "10.5.8", "@types/uuid": "9.0.6" diff --git a/examples/cactus-example-discounted-asset-trade/read-ledger-state.js b/examples/cactus-example-discounted-asset-trade/read-ledger-state.js deleted file mode 100644 index e35c097c1a..0000000000 --- a/examples/cactus-example-discounted-asset-trade/read-ledger-state.js +++ /dev/null @@ -1,31 +0,0 @@ -const axios = require("axios"); - -async function main() { - // Read ethereum balances - const fromAccountResponse = await axios.get( - "http://localhost:5034/api/v1/bl/balance/0xec709e1774f0ce4aba47b52a499f9abaaa159f71", - ); - console.log("\n# Ethereum fromAccount:"); - console.log(fromAccountResponse.data); - - const escrowAccountResponse = await axios.get( - "http://localhost:5034/api/v1/bl/balance/0x36e146d5afab61ab125ee671708eeb380aea05b6", - ); - console.log("\n# Ethereum escrowAccount:"); - console.log(escrowAccountResponse.data); - - const toAccountResponse = await axios.get( - "http://localhost:5034/api/v1/bl/balance/0x9d624f7995e8bd70251f8265f2f9f2b49f169c55", - ); - console.log("\n# Ethereum toAccount:"); - console.log(toAccountResponse.data); - - // Read fabric assets - const fabricResponse = await axios.get( - "http://localhost:5034/api/v1/bl/fabric-asset/", - ); - console.log("\n# Fabric:"); - console.log(fabricResponse.data); -} - -main(); diff --git a/examples/cactus-example-discounted-asset-trade/script-cleanup.sh b/examples/cactus-example-discounted-asset-trade/script-cleanup.sh index 0f9c532dfd..da35417c4d 100755 --- a/examples/cactus-example-discounted-asset-trade/script-cleanup.sh +++ b/examples/cactus-example-discounted-asset-trade/script-cleanup.sh @@ -4,18 +4,19 @@ echo ">> Remove the config files on your machine" rm -rf ./etc/cactus/ +rm -rf /etc/cactus/indy-all-in-one/ echo ">> Stop the docker containers of Ethereum, Fabric and Indy" -docker stop geth1 asset_trade_faio2x_testnet indy-testnet-pool -docker rm geth1 asset_trade_faio2x_testnet indy-testnet-pool $(docker container ls -q --all --filter name=geth-testnet_init-chain) +docker stop geth1 asset_trade_faio2x_testnet asset_trade_indy_all_in_one +docker rm geth1 asset_trade_faio2x_testnet asset_trade_indy_all_in_one $(docker container ls -q --all --filter name=geth-testnet_init-chain) docker compose rm -f echo ">> Clear docker networks" -docker network rm geth1net geth-testnet_default fabric-all-in-one_testnet-2x geth-testnet_default indy-testnet_indy_net +docker network rm geth1net geth-testnet_default fabric-all-in-one_testnet-2x geth-testnet_default indy-all-in-one_indy_aio_net docker network rm $(docker network ls -q --filter name=cactus-example-discounted-asset-trade) -echo ">> Clear indy testnet sandbox" -pushd ../../tools/docker/indy-testnet/ +echo ">> Clear indy-all-in-one" +pushd ../../tools/docker/indy-all-in-one/ ./script-cleanup.sh popd diff --git a/examples/cactus-example-discounted-asset-trade/script-dockerless-config-patch.sh b/examples/cactus-example-discounted-asset-trade/script-dockerless-config-patch.sh index 9e4d125b9c..bc97a6d99c 100755 --- a/examples/cactus-example-discounted-asset-trade/script-dockerless-config-patch.sh +++ b/examples/cactus-example-discounted-asset-trade/script-dockerless-config-patch.sh @@ -16,7 +16,6 @@ sed -i 's/geth1/localhost/g' "${COMMON_CACTUS_CONFIG}/connector-go-ethereum-sock echo "Patch validator-registry-config.yaml..." sed -i 's/ethereum-validator/localhost/g' "${COMMON_CACTUS_CONFIG}/validator-registry-config.yaml" -sed -i 's/indy-validator-nginx/localhost/g' "${COMMON_CACTUS_CONFIG}/validator-registry-config.yaml" echo "Patch path to asset-trade modules." current_pwd=$(pwd) diff --git a/examples/cactus-example-discounted-asset-trade/script-post-trade-request.sh b/examples/cactus-example-discounted-asset-trade/script-post-trade-request.sh deleted file mode 100755 index f5e1618f08..0000000000 --- a/examples/cactus-example-discounted-asset-trade/script-post-trade-request.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/env bash -# Copyright 2020-2022 Hyperledger Cactus Contributors -# SPDX-License-Identifier: Apache-2.0 - -echo "Build register-indy-data container" -pushd ../register-indy-data -sh ./script-build-docker.sh -popd - -echo "Run register-indy-data " -docker run --rm \ - -ti \ - -v "$(pwd)/etc/cactus/":"/etc/cactus/" \ - --net="host" \ - register-indy-data diff --git a/examples/cactus-example-discounted-asset-trade/script-start-ledgers.sh b/examples/cactus-example-discounted-asset-trade/script-start-ledgers.sh index 6f6e1daecd..a1ab0d9aa7 100755 --- a/examples/cactus-example-discounted-asset-trade/script-start-ledgers.sh +++ b/examples/cactus-example-discounted-asset-trade/script-start-ledgers.sh @@ -5,7 +5,7 @@ set -e ROOT_DIR="../.." # Path to cactus root dir -WAIT_TIME=30 # How often to check container status +WAIT_TIME=15 # How often to check container status CONFIG_VOLUME_PATH="./etc/cactus" # Docker volume with shared configuration # Fabric Env Variables @@ -17,6 +17,9 @@ export CACTUS_FABRIC_ALL_IN_ONE_COUCH_VERSION_FABRIC="0.4" export CACTUS_FABRIC_ALL_IN_ONE_COUCH_VERSION="3.2.2" export CACTUS_FABRIC_TEST_LOOSE_MEMBERSHIP=1 +# Indy Env Variables +export CACTUS_INDY_ALL_IN_ONE_NAME="asset_trade_indy_all_in_one" + # Cert options CERT_CURVE_NAME="prime256v1" CERT_COUNTRY="JP" @@ -120,23 +123,28 @@ function copy_ethereum_validator_config() { function start_indy_testnet() { echo ">> start_indy_testnet()" - pushd "${ROOT_DIR}/tools/docker/indy-testnet" - echo ">> Start Indy pool..." - docker-compose build - docker-compose up -d + pushd "${ROOT_DIR}/tools/docker/indy-all-in-one" + ./script-start-docker.sh popd -} -function copy_indy_validator_config() { - echo ">> copy_indy_validator_config()" - cp -fr ${ROOT_DIR}/packages-python/cactus_validator_socketio_indy/config/* "${CONFIG_VOLUME_PATH}/validator_socketio_indy/" - echo ">> copy_indy_validator_config() done." + # Wait for fabric cotnainer to become healthy + health_status="$(docker inspect -f '{{.State.Health.Status}}' ${CACTUS_INDY_ALL_IN_ONE_NAME})" + while ! [ "${health_status}" == "healthy" ] + do + echo "Waiting for indy container... current status => ${health_status}" + sleep $WAIT_TIME + health_status="$(docker inspect -f '{{.State.Health.Status}}' ${CACTUS_INDY_ALL_IN_ONE_NAME})" + done + echo ">> Indy test ledger started." } -function copy_indy_validator_ca() { - echo ">> copy_indy_validator_ca()" - generate_certificate "IndyCactusValidator" "${CONFIG_VOLUME_PATH}/validator_socketio_indy/CA/" - echo ">> copy_indy_validator_ca() done." +function copy_indy_ledger_config() { + echo ">> copy_indy_ledger_config()" + mkdir -p "${CONFIG_VOLUME_PATH}/indy-all-in-one/" + mkdir -p "/etc/cactus/indy-all-in-one/" + cp -fr "/tmp/indy-all-in-one/pool_transactions_genesis" "${CONFIG_VOLUME_PATH}/indy-all-in-one/" + cp -fr "/tmp/indy-all-in-one/pool_transactions_genesis" "/etc/cactus/indy-all-in-one/" + echo ">> copy_indy_ledger_config() done." } function start_ledgers() { @@ -159,10 +167,8 @@ function start_ledgers() { copy_ethereum_validator_config # Start Indy - mkdir -p "${CONFIG_VOLUME_PATH}/validator_socketio_indy" start_indy_testnet - copy_indy_validator_ca - copy_indy_validator_config + copy_indy_ledger_config } start_ledgers diff --git a/examples/cactus-example-discounted-asset-trade/transaction-indy.ts b/examples/cactus-example-discounted-asset-trade/transaction-indy.ts index 28d93c9689..ec4d6db383 100644 --- a/examples/cactus-example-discounted-asset-trade/transaction-indy.ts +++ b/examples/cactus-example-discounted-asset-trade/transaction-indy.ts @@ -1,88 +1,75 @@ /* - * Copyright 2022 Hyperledger Cactus Contributors - * SPDX-License-Identifier: Apache-2.0 - * - * transaction-indy.ts + * TODO - Replace these methods with their counterparts in Indy connector (when it's ready). + * For now we import utility functions from @hyperledger/cactus-example-discounted-asset-trade-client for simplicity. */ +import { getLogger } from "log4js"; +import { ConfigUtil } from "@hyperledger/cactus-cmd-socketio-server"; import { - LPInfoHolder, - ConfigUtil, -} from "@hyperledger/cactus-cmd-socketio-server"; -import { ISendRequestResultV1 } from "@hyperledger/cactus-core-api"; - -import { - VerifierFactory, - VerifierFactoryConfig, -} from "@hyperledger/cactus-verifier-client"; + acceptInvitation, + checkCredentialProof, + waitForConnectionReady, +} from "@hyperledger/cactus-example-discounted-asset-trade-client"; +import { getIndyAgent } from "./indy-agent"; const config: any = ConfigUtil.getConfig(); -import { getLogger } from "log4js"; -const moduleName = "TransactionIndy"; + +const moduleName = "transaction-indy"; const logger = getLogger(`${moduleName}`); logger.level = config.logLevel; -const xConnectInfo = new LPInfoHolder(); -const verifierFactory = new VerifierFactory( - xConnectInfo.ledgerPluginInfo as VerifierFactoryConfig, - config.logLevel, -); - -export function getDataFromIndy( - arg_request: { - did: string | null; - schemaId: string; - }, - identifier: string, -): Promise<{ data: string[] }> { - return new Promise(async (resolve, reject) => { - try { - logger.debug(`getDataFromIndy: arg_request: ${arg_request}`); - sendRequest(arg_request, identifier).then((result) => { - logger.debug(`##getDataFromIndy: result: ${JSON.stringify(result)}`); - - return resolve(result); - }); - } catch (err) { - logger.error(err); - return reject(err); - } - }); -} +/** + * Connect remote client indy agent using it's invitation URL. + * Wait until connection is established and ready to use. + * + * @param invitationUrl anoncreds invitation URL. + * @returns connection ID of newly created connection + */ +export async function connectToClientAgent( + invitationUrl: string, +): Promise { + logger.info("Accepting invitation from client agent..."); -function sendRequest( - arg_request: Record, - identifier: string, -): Promise<{ data: string[] }> { - return new Promise(async (resolve, reject) => { - try { - logger.debug(`##sendRequest: arg_request: ${arg_request}`); + const blpAgent = await getIndyAgent(); + const outOfBandRecord = await acceptInvitation(blpAgent, invitationUrl); + await waitForConnectionReady(blpAgent, outOfBandRecord.id); - let commandName = ""; + logger.debug( + "connectToClientAgent() - outOfBandRecord ID:", + outOfBandRecord.id, + ); + const [connection] = await blpAgent.connections.findAllByOutOfBandId( + outOfBandRecord.id, + ); - if (identifier === "schema") { - commandName = "get_schema"; - } else if (identifier === "credDef") { - commandName = "get_cred_def"; - } + if (!connection) { + throw Error( + "Could not establish a connection to remote client indy agent!", + ); + } + logger.debug("connectToClientAgent() - connection ID:", connection.id); - const contract = { - channelName: "mychannel", - contractName: "indysomething", - }; // NOTE: Since contract does not need to be specified, specify an empty object. - const method = { type: "evaluateTransaction", command: commandName }; + return connection.id; +} - const args = { args: arg_request }; +/** + * Request and verify employment proof from client agent connected with specified ID. + * + * @param indyAgentConId client agent connection ID. + * @param credentialDefinitionId employment credential definition ID. + * @returns true if agent is an employee, false otherwise + */ +export async function isEmploymentCredentialProofValid( + indyAgentConId: string, + credentialDefinitionId: string, +) { + const blpAgent = await getIndyAgent(); + const proof = await checkCredentialProof( + blpAgent, + credentialDefinitionId, + indyAgentConId, + ); + logger.debug("Received employment proof response:", proof); - verifierFactory - .getVerifier("3PfTJw8g") - .sendSyncRequest(contract, method, args) - .then((result) => { - return resolve(result as ISendRequestResultV1>); - }); - } catch (err) { - logger.error(err); - return reject(err); - } - }); + return proof.state === "done"; } diff --git a/examples/cactus-example-discounted-asset-trade/tsconfig.json b/examples/cactus-example-discounted-asset-trade/tsconfig.json index 8fc752a3bc..d6c0d1c312 100644 --- a/examples/cactus-example-discounted-asset-trade/tsconfig.json +++ b/examples/cactus-example-discounted-asset-trade/tsconfig.json @@ -30,7 +30,7 @@ "path": "../../packages/cactus-plugin-ledger-connector-ethereum/tsconfig.json" }, { - "path": "../../packages/cactus-verifier-client/tsconfig.json" + "path": "../../examples/cactus-example-discounted-asset-trade-client/tsconfig.json" } ] } diff --git a/examples/cactus-example-discounted-asset-trade/www.ts b/examples/cactus-example-discounted-asset-trade/www.ts index 9067e44f70..a6f51b6775 100644 --- a/examples/cactus-example-discounted-asset-trade/www.ts +++ b/examples/cactus-example-discounted-asset-trade/www.ts @@ -2,11 +2,13 @@ import { BusinessLogicAssetTrade } from "./business-logic-asset-trade"; import { startCactusSocketIOServer } from "@hyperledger/cactus-cmd-socketio-server"; import { initFabricConnector } from "./fabric-connector"; import { initEthereumConnector } from "./ethereum-connector"; +import { initIndyAgent } from "./indy-agent"; async function startBLP() { try { await initFabricConnector(); await initEthereumConnector(); + await initIndyAgent(); startCactusSocketIOServer({ id: "guks32pf", diff --git a/examples/register-indy-data/Dockerfile b/examples/register-indy-data/Dockerfile deleted file mode 100644 index 9874c98268..0000000000 --- a/examples/register-indy-data/Dockerfile +++ /dev/null @@ -1,18 +0,0 @@ -# Simple tool for setup and sending requests to cactus-example-discounted-asset-trade sample app -# Run as part of docker-compose or remember to use host network - -FROM indy-sdk-cli - -# Default IP for test indy pool on localhost -ENV TEST_POOL_IP 172.16.0.2 - -USER root -RUN mkdir -p "/etc/cactus/" && chown -R indy "/etc/cactus/" -VOLUME [ "/etc/cactus/" ] - -USER indy -WORKDIR /home/indy -COPY --chown=indy:indy './register-indy-data.py' './src/' -RUN cp 'from-indy-sdk/utils.py' './src/' - -ENTRYPOINT [ "python3", "-m", "src.register-indy-data" ] diff --git a/examples/register-indy-data/README.md b/examples/register-indy-data/README.md deleted file mode 100644 index 96a2937d28..0000000000 --- a/examples/register-indy-data/README.md +++ /dev/null @@ -1,32 +0,0 @@ -# register-indy-data - -Simple tool for indy setup and sending requests to `cactus-example-discounted-asset-trade` sample app. - -# Build -- Use script to build base container `indy-sdk-cli` and tool container `register-indy-data` -``` -./script-build-docker.sh -``` - -# Usage -- First, ensure indy test pool is already running and docker network `indy-testnet_indy_net` was created. - -### Send cactus-example-discounted-asset-trade request -``` -docker run --rm -ti -v/etc/cactus/:/etc/cactus/ --net="indy-testnet_indy_net" register-indy-data -``` - -### Recreate the proof and send cactus-example-discounted-asset-trade request -``` -docker run --rm -ti -v/etc/cactus/:/etc/cactus/ --net="indy-testnet_indy_net" register-indy-data --force -``` - -### Generate proof only -``` -docker run --rm -ti -v/etc/cactus/:/etc/cactus/ --net="indy-testnet_indy_net" register-indy-data --proof_only -``` - -### Recreate the proof only -``` -docker run --rm -ti -v/etc/cactus/:/etc/cactus/ --net="indy-testnet_indy_net" register-indy-data --proof_only --force -``` diff --git a/examples/register-indy-data/register-indy-data.py b/examples/register-indy-data/register-indy-data.py deleted file mode 100644 index ea140b3575..0000000000 --- a/examples/register-indy-data/register-indy-data.py +++ /dev/null @@ -1,672 +0,0 @@ -import time - -from indy import anoncreds, did, ledger, pool, wallet, blob_storage - -import json -import logging - -import argparse -import os -import sys -from ctypes import * -from os.path import dirname, isfile - -from indy.error import ErrorCode, IndyError - -from src.utils import get_pool_genesis_txn_path, run_coroutine, PROTOCOL_VERSION, ensure_previous_request_applied - -#use Requests -import requests - - -logger = logging.getLogger(__name__) -logging.basicConfig(level=logging.INFO) - -# http request parameters -# http_req_params = { -# "url": "http://localhost:5034/api/v1/bl/trades/", -# "businessLogicID": "guks32pf", -# "tradeParams": ["0xec709e1774f0ce4aba47b52a499f9abaaa159f71", -# "0x9d624f7995e8bd70251f8265f2f9f2b49f169c55", -# "fuser01", "fuser02", 50, "CAR1"], -# "authParams": ["<>"] -# } -http_req_params = { - "url": "http://localhost:5034/api/v1/bl/trades/", - "businessLogicID": "guks32pf", - "tradeParams": ["0xec709e1774f0ce4aba47b52a499f9abaaa159f71", - "0x9d624f7995e8bd70251f8265f2f9f2b49f169c55", - "Brad", "Cathy", "asset2"], - "authParams": ["<>"] -} - -proof_file_path = "/etc/cactus/validator_socketio_indy/myproof.json" - -#parser = argparse.ArgumentParser(description='Run python getting-started scenario (Alice/Faber)') -parser = argparse.ArgumentParser(description='Run python getting-started scenario (Alice/Acme/Thrift)') -parser.add_argument('-t', '--storage_type', help='load custom wallet storage plug-in') -parser.add_argument('-l', '--library', help='dynamic library to load for plug-in') -parser.add_argument('-e', '--entrypoint', help='entry point for dynamic library') -parser.add_argument('-c', '--config', help='entry point for dynamic library') -parser.add_argument('-s', '--creds', help='entry point for dynamic library') -parser.add_argument('-p', '--proof_only', help="create only the proof, don't start the cartrade", action='store_true') -parser.add_argument('-f', '--force', help="force recreate the proof (even if already exists)", action='store_true') - -args = parser.parse_args() - -# check if we need to dyna-load a custom wallet storage plug-in -if args.storage_type: - if not (args.library and args.entrypoint): - parser.print_help() - sys.exit(0) - stg_lib = CDLL(args.library) - result = stg_lib[args.entrypoint]() - if result != 0: - print("Error unable to load wallet storage", result) - parser.print_help() - sys.exit(0) - - # for postgres storage, also call the storage init (non-standard) - if args.storage_type == "postgres_storage": - try: - print("Calling init_storagetype() for postgres:", args.config, args.creds) - init_storagetype = stg_lib["init_storagetype"] - c_config = c_char_p(args.config.encode('utf-8')) - c_credentials = c_char_p(args.creds.encode('utf-8')) - result = init_storagetype(c_config, c_credentials) - print(" ... returns ", result) - except RuntimeError as e: - print("Error initializing storage, ignoring ...", e) - - print("Success, loaded wallet storage", args.storage_type) - - -async def run(): - logger.info("Getting started -> started") - - if (not isfile(proof_file_path)) or args.force: - # Create dir for proof if doesn't already exist - os.makedirs(dirname(proof_file_path), exist_ok=True) - - pool_ = { - 'name': 'pool1' - } - logger.info("Open Pool Ledger: {}".format(pool_['name'])) - pool_['genesis_txn_path'] = get_pool_genesis_txn_path(pool_['name']) - pool_['config'] = json.dumps({"genesis_txn": str(pool_['genesis_txn_path'])}) - - # Set protocol version 2 to work with Indy Node 1.4 - await pool.set_protocol_version(PROTOCOL_VERSION) - - try: - await pool.create_pool_ledger_config(pool_['name'], pool_['config']) - except IndyError as ex: - if ex.error_code == ErrorCode.PoolLedgerConfigAlreadyExistsError: - pass - pool_['handle'] = await pool.open_pool_ledger(pool_['name'], None) - - logger.info("==============================") - #logger.info("=== Getting Trust Anchor credentials for Faber, Acme, Thrift and Government ==") - logger.info("=== Getting Trust Anchor credentials for Acme ==") - logger.info("------------------------------") - - steward = { - 'name': "Sovrin Steward", - 'wallet_config': json.dumps({'id': 'sovrin_steward_wallet'}), - 'wallet_credentials': json.dumps({'key': 'steward_wallet_key'}), - 'pool': pool_['handle'], - 'seed': '000000000000000000000000Steward1' - } - - await create_wallet(steward) - - logger.info("\"Sovrin Steward\" -> Create and store in Wallet DID from seed") - steward['did_info'] = json.dumps({'seed': steward['seed']}) - steward['did'], steward['key'] = await did.create_and_store_my_did(steward['wallet'], steward['did_info']) - - logger.info("==============================") - logger.info("== Getting Trust Anchor credentials - Government getting Verinym ==") - logger.info("------------------------------") - - government = { - 'name': 'Government', - 'wallet_config': json.dumps({'id': 'government_wallet'}), - 'wallet_credentials': json.dumps({'key': 'government_wallet_key'}), - 'pool': pool_['handle'], - 'role': 'TRUST_ANCHOR' - } - - await getting_verinym(steward, government) - - logger.info("==============================") - logger.info("== Getting Trust Anchor credentials - Acme getting Verinym ==") - logger.info("------------------------------") - - acme = { - 'name': 'Acme', - 'wallet_config': json.dumps({'id': 'acme_wallet'}), - 'wallet_credentials': json.dumps({'key': 'acme_wallet_key'}), - 'pool': pool_['handle'], - 'role': 'TRUST_ANCHOR' - } - - await getting_verinym(steward, acme) - - logger.info("==============================") - logger.info("== Getting Trust Anchor credentials - Thrift getting Verinym ==") - logger.info("------------------------------") - - thrift = { - 'name': 'Thrift', - 'wallet_config': json.dumps({'id': 'thrift_wallet'}), - 'wallet_credentials': json.dumps({'key': 'thrift_wallet_key'}), - 'pool': pool_['handle'], - 'role': 'TRUST_ANCHOR' - } - - await getting_verinym(steward, thrift) - - logger.info("==============================") - logger.info("=== Credential Schemas Setup ==") - logger.info("------------------------------") - - logger.info("\"Government\" -> Create \"Job-Certificate\" Schema") - job_certificate = { - 'name': 'Job-Certificate', - 'version': '0.2', - 'attributes': ['first_name', 'last_name', 'salary', 'employee_status', 'experience'] - } - (government['job_certificate_schema_id'], government['job_certificate_schema']) = \ - await anoncreds.issuer_create_schema(government['did'], job_certificate['name'], job_certificate['version'], - json.dumps(job_certificate['attributes'])) - job_certificate_schema_id = government['job_certificate_schema_id'] - - logger.info("\"Government\" -> Send \"Job-Certificate\" Schema to Ledger") - await send_schema(government['pool'], government['wallet'], government['did'], government['job_certificate_schema']) - - - time.sleep(1) # sleep 1 second before getting schema - - - logger.info("==============================") - logger.info("=== Acme Credential Definition Setup ==") - logger.info("------------------------------") - - logger.info("\"Acme\" -> Get from Ledger \"Job-Certificate\" Schema") - (acme['job_certificate_schema_id'], acme['job_certificate_schema']) = \ - await get_schema(acme['pool'], acme['did'], job_certificate_schema_id) - - logger.info("\"Acme\" -> Create and store in Wallet \"Acme Job-Certificate\" Credential Definition") - job_certificate_cred_def = { - 'tag': 'TAG1', - 'type': 'CL', - 'config': {"support_revocation": False} - } - (acme['job_certificate_cred_def_id'], acme['job_certificate_cred_def']) = \ - await anoncreds.issuer_create_and_store_credential_def(acme['wallet'], acme['did'], - acme['job_certificate_schema'], - job_certificate_cred_def['tag'], - job_certificate_cred_def['type'], - json.dumps(job_certificate_cred_def['config'])) - - logger.info("\"Acme\" -> Send \"Acme Job-Certificate\" Credential Definition to Ledger") - await send_cred_def(acme['pool'], acme['wallet'], acme['did'], acme['job_certificate_cred_def']) - - logger.info("\"Acme\" -> Creates Revocation Registry") - acme['tails_writer_config'] = json.dumps({'base_dir': "/tmp/indy_acme_tails", 'uri_pattern': ''}) - tails_writer = await blob_storage.open_writer('default', acme['tails_writer_config']) - acme['revoc_reg_id'] = None - #(acme['revoc_reg_id'], acme['revoc_reg_def'], acme['revoc_reg_entry']) = \ - # await anoncreds.issuer_create_and_store_revoc_reg(acme['wallet'], acme['did'], 'CL_ACCUM', 'TAG1', - # acme['job_certificate_cred_def_id'], - # json.dumps({'max_cred_num': 5, - # 'issuance_type': 'ISSUANCE_ON_DEMAND'}), - # tails_writer) - - #logger.info("\"Acme\" -> Post Revocation Registry Definition to Ledger") - #acme['revoc_reg_def_request'] = await ledger.build_revoc_reg_def_request(acme['did'], acme['revoc_reg_def']) - #await ledger.sign_and_submit_request(acme['pool'], acme['wallet'], acme['did'], acme['revoc_reg_def_request']) - - #logger.info("\"Acme\" -> Post Revocation Registry Entry to Ledger") - #acme['revoc_reg_entry_request'] = \ - # await ledger.build_revoc_reg_entry_request(acme['did'], acme['revoc_reg_id'], 'CL_ACCUM', - # acme['revoc_reg_entry']) - #await ledger.sign_and_submit_request(acme['pool'], acme['wallet'], acme['did'], acme['revoc_reg_entry_request']) - - - logger.info("==============================") - logger.info("== Alice setup ==") - logger.info("------------------------------") - - alice = { - 'name': 'Alice', - 'wallet_config': json.dumps({'id': 'alice_wallet'}), - 'wallet_credentials': json.dumps({'key': 'alice_wallet_key'}), - 'pool': pool_['handle'], - } - await create_wallet(alice) - (alice['did'], alice['key']) = await did.create_and_store_my_did(alice['wallet'], "{}") - - logger.info("\"Alice\" -> Create and store \"Alice\" Master Secret in Wallet") - alice['master_secret_id'] = await anoncreds.prover_create_master_secret(alice['wallet'], None) - - - logger.info("==============================") - logger.info("== Apply for the job with Acme - Getting Job-Certificate Credential ==") - logger.info("------------------------------") - - logger.info("\"Acme\" -> Create \"Job-Certificate\" Credential Offer for Alice") - acme['job_certificate_cred_offer'] = \ - await anoncreds.issuer_create_credential_offer(acme['wallet'], acme['job_certificate_cred_def_id']) - - logger.info("\"Acme\" -> Send \"Job-Certificate\" Credential Offer to Alice") - alice['job_certificate_cred_offer'] = acme['job_certificate_cred_offer'] - - job_certificate_cred_offer_object = json.loads(alice['job_certificate_cred_offer']) - - logger.info("\"Alice\" -> Get \"Acme Job-Certificate\" Credential Definition from Ledger") - (alice['acme_job_certificate_cred_def_id'], alice['acme_job_certificate_cred_def']) = \ - await get_cred_def(alice['pool'], alice['did'], job_certificate_cred_offer_object['cred_def_id']) - - logger.info("\"Alice\" -> Create and store in Wallet \"Job-Certificate\" Credential Request for Acme") - (alice['job_certificate_cred_request'], alice['job_certificate_cred_request_metadata']) = \ - await anoncreds.prover_create_credential_req(alice['wallet'], alice['did'], - alice['job_certificate_cred_offer'], - alice['acme_job_certificate_cred_def'], alice['master_secret_id']) - - logger.info("\"Alice\" -> Send \"Job-Certificate\" Credential Request to Acme") - alice['job_certificate_cred_values'] = json.dumps({ - "first_name": {"raw": "Alice", "encoded": "245712572474217942457235975012103335"}, - "last_name": {"raw": "Garcia", "encoded": "312643218496194691632153761283356127"}, - "employee_status": {"raw": "Permanent", "encoded": "2143135425425143112321314321"}, - "salary": {"raw": "2400", "encoded": "2400"}, - "experience": {"raw": "10", "encoded": "10"} - }) - acme['job_certificate_cred_request'] = alice['job_certificate_cred_request'] - acme['job_certificate_cred_values'] = alice['job_certificate_cred_values'] - - logger.info("\"Acme\" -> Create \"Job-Certificate\" Credential for Alice") - acme['blob_storage_reader_cfg_handle'] = await blob_storage.open_reader('default', acme['tails_writer_config']) - acme['job_certificate_cred'], acme['job_certificate_cred_rev_id'], acme['alice_cert_rev_reg_delta'] = \ - await anoncreds.issuer_create_credential(acme['wallet'], acme['job_certificate_cred_offer'], - acme['job_certificate_cred_request'], - acme['job_certificate_cred_values'], - acme['revoc_reg_id'], - acme['blob_storage_reader_cfg_handle']) - - #logger.info("\"Acme\" -> Post Revocation Registry Delta to Ledger") - #acme['revoc_reg_entry_req'] = \ - # await ledger.build_revoc_reg_entry_request(acme['did'], acme['revoc_reg_id'], 'CL_ACCUM', - # acme['alice_cert_rev_reg_delta']) - #await ledger.sign_and_submit_request(acme['pool'], acme['wallet'], acme['did'], acme['revoc_reg_entry_req']) - - logger.info("\"Acme\" -> Send \"Job-Certificate\" Credential to Alice") - alice['job_certificate_cred'] = acme['job_certificate_cred'] - job_certificate_cred_object = json.loads(alice['job_certificate_cred']) - - #logger.info("\"Alice\" -> Gets RevocationRegistryDefinition for \"Job-Certificate\" Credential from Acme") - #alice['acme_revoc_reg_des_req'] = \ - # await ledger.build_get_revoc_reg_def_request(alice['did'], - # job_certificate_cred_object['rev_reg_id']) - #alice['acme_revoc_reg_des_resp'] = \ - # await ensure_previous_request_applied(alice['pool'], alice['acme_revoc_reg_des_req'], - # lambda response: response['result']['data'] is not None) - #(alice['acme_revoc_reg_def_id'], alice['acme_revoc_reg_def_json']) = \ - # await ledger.parse_get_revoc_reg_def_response(alice['acme_revoc_reg_des_resp']) - alice['acme_revoc_reg_def_json'] = None - - logger.info("\"Alice\" -> Store \"Job-Certificate\" Credential") - await anoncreds.prover_store_credential(alice['wallet'], None, alice['job_certificate_cred_request_metadata'], - alice['job_certificate_cred'], - alice['acme_job_certificate_cred_def'], alice['acme_revoc_reg_def_json']) - - logger.info("Creating Credential in Getting started -> done") - - logger.info("==============================") - logger.info("=== Apply for the loan with Thrift ==") - logger.info("==============================") - - async def apply_loan_basic(): - # This method will be called twice: once with a valid Job-Certificate and - # the second time after the Job-Certificate has been revoked. - logger.info("==============================") - logger.info("== Apply for the loan with Thrift - Job-Certificate proving ==") - logger.info("------------------------------") - - #logger.info("\"Thrift\" -> Create \"Loan-Application-Basic\" Proof Request") - logger.info("\"Alice\" -> Create \"Loan-Application-Basic\" Proof Request") - nonce = await anoncreds.generate_nonce() - #thrift['apply_loan_proof_request'] = json.dumps({ - alice['apply_loan_proof_request'] = json.dumps({ - 'nonce': nonce, - 'name': 'Loan-Application-Basic', - 'version': '0.1', - 'requested_attributes': { - 'attr1_referent': { - 'name': 'employee_status', - 'restrictions': [{'cred_def_id': acme['job_certificate_cred_def_id']}] - } - }, - 'requested_predicates': { - 'predicate1_referent': { - 'name': 'salary', - 'p_type': '>=', - 'p_value': 2000, - 'restrictions': [{'cred_def_id': acme['job_certificate_cred_def_id']}] - }, - 'predicate2_referent': { - 'name': 'experience', - 'p_type': '>=', - 'p_value': 1, - 'restrictions': [{'cred_def_id': acme['job_certificate_cred_def_id']}] - } - }#, - # 'non_revoked': {'to': int(time.time())} - }) - - #logger.info("\"Thrift\" -> Send \"Loan-Application-Basic\" Proof Request to Alice") - #alice['apply_loan_proof_request'] = thrift_apply_loan_proof_request - logger.info("Creating Proof Request in Getting started -> done") - - logger.info("\"Alice\" -> Get credentials for \"Loan-Application-Basic\" Proof Request") - - search_for_apply_loan_proof_request = \ - await anoncreds.prover_search_credentials_for_proof_req(alice['wallet'], - alice['apply_loan_proof_request'], None) - - cred_for_attr1 = await get_credential_for_referent(search_for_apply_loan_proof_request, 'attr1_referent') - cred_for_predicate1 = await get_credential_for_referent(search_for_apply_loan_proof_request, - 'predicate1_referent') - cred_for_predicate2 = await get_credential_for_referent(search_for_apply_loan_proof_request, - 'predicate2_referent') - - await anoncreds.prover_close_credentials_search_for_proof_req(search_for_apply_loan_proof_request) - - alice['creds_for_apply_loan_proof'] = {cred_for_attr1['referent']: cred_for_attr1, - cred_for_predicate1['referent']: cred_for_predicate1, - cred_for_predicate2['referent']: cred_for_predicate2} - - # requested_timestamp = int(json.loads(alice['apply_loan_proof_request'])['non_revoked']['to']) - requested_timestamp = None - alice['schemas_for_loan_app'], alice['cred_defs_for_loan_app'], alice['revoc_states_for_loan_app'] = \ - await prover_get_entities_from_ledger(alice['pool'], alice['did'], - alice['creds_for_apply_loan_proof'], - alice['name'], None, requested_timestamp) - - logger.info("\"Alice\" -> Create \"Loan-Application-Basic\" Proof") - revoc_states_for_loan_app = json.loads(alice['revoc_states_for_loan_app']) - timestamp_for_attr1 = get_timestamp_for_attribute(cred_for_attr1, revoc_states_for_loan_app) - timestamp_for_predicate1 = get_timestamp_for_attribute(cred_for_predicate1, revoc_states_for_loan_app) - timestamp_for_predicate2 = get_timestamp_for_attribute(cred_for_predicate2, revoc_states_for_loan_app) - alice['apply_loan_requested_creds'] = json.dumps({ - 'self_attested_attributes': {}, - 'requested_attributes': { - 'attr1_referent': {'cred_id': cred_for_attr1['referent'], 'revealed': True, - 'timestamp': timestamp_for_attr1} - }, - 'requested_predicates': { - 'predicate1_referent': {'cred_id': cred_for_predicate1['referent'], - 'timestamp': timestamp_for_predicate1}, - 'predicate2_referent': {'cred_id': cred_for_predicate2['referent'], - 'timestamp': timestamp_for_predicate2} - } - }) - alice['apply_loan_proof'] = \ - await anoncreds.prover_create_proof(alice['wallet'], alice['apply_loan_proof_request'], - alice['apply_loan_requested_creds'], alice['master_secret_id'], - alice['schemas_for_loan_app'], alice['cred_defs_for_loan_app'], - alice['revoc_states_for_loan_app']) - - logger.info("Creating Proof in Getting started -> done") - - logger.info("\"Alice\" -> Send \"Loan-Application-Basic\" Proof to Thrift") - logger.info(json.dumps(alice['apply_loan_proof'])) - # logger.info("USER_PROOF_REQUEST: " + json.dumps(alice['apply_loan_proof_request'])) - # logger.info("USER_PROOF: " + json.dumps(alice['apply_loan_proof'])) - # logger.info('{ "proof_request": ' + json.dumps(alice['apply_loan_proof_request']) + ', "proof": ' + json.dumps(alice['apply_loan_proof']) + ' }') - - # request_str = '{ "proof_request": ' + json.dumps(alice['apply_loan_proof_request']) + ', "proof": ' + json.dumps(alice['apply_loan_proof']) + ' }' - # logger.info(request_str) - - ##request_json = { "proof_request": json.dumps(alice['apply_loan_proof_request']), "proof": json.dumps(alice['apply_loan_proof'])} - request_json = { "proof_request": alice['apply_loan_proof_request'], "proof": alice['apply_loan_proof']} - logger.info(json.dumps(request_json)) - - # create_user_proof_file(proof_file_path, json.dumps(request_str)) - create_user_proof_file(proof_file_path, json.dumps(request_json)) - - await apply_loan_basic() - - if not args.proof_only: - request_discounted_cartrade(proof_file_path) - - print("Done.") - -def wallet_config(operation, wallet_config_str): - if not args.storage_type: - return wallet_config_str - wallet_config_json = json.loads(wallet_config_str) - wallet_config_json['storage_type'] = args.storage_type - if args.config: - wallet_config_json['storage_config'] = json.loads(args.config) - # print(operation, json.dumps(wallet_config_json)) - return json.dumps(wallet_config_json) - - -def wallet_credentials(operation, wallet_credentials_str): - if not args.storage_type: - return wallet_credentials_str - wallet_credentials_json = json.loads(wallet_credentials_str) - if args.creds: - wallet_credentials_json['storage_credentials'] = json.loads(args.creds) - # print(operation, json.dumps(wallet_credentials_json)) - return json.dumps(wallet_credentials_json) - - -async def create_wallet(identity): - logger.info("\"{}\" -> Create wallet".format(identity['name'])) - try: - await wallet.create_wallet(wallet_config("create", identity['wallet_config']), - wallet_credentials("create", identity['wallet_credentials'])) - except IndyError as ex: - if ex.error_code == ErrorCode.PoolLedgerConfigAlreadyExistsError: - pass - identity['wallet'] = await wallet.open_wallet(wallet_config("open", identity['wallet_config']), - wallet_credentials("open", identity['wallet_credentials'])) - - -async def getting_verinym(from_, to): - await create_wallet(to) - - (to['did'], to['key']) = await did.create_and_store_my_did(to['wallet'], "{}") - - from_['info'] = { - 'did': to['did'], - 'verkey': to['key'], - 'role': to['role'] or None - } - - await send_nym(from_['pool'], from_['wallet'], from_['did'], from_['info']['did'], - from_['info']['verkey'], from_['info']['role']) - - -async def send_nym(pool_handle, wallet_handle, _did, new_did, new_key, role): - nym_request = await ledger.build_nym_request(_did, new_did, new_key, None, role) - await ledger.sign_and_submit_request(pool_handle, wallet_handle, _did, nym_request) - - -async def send_schema(pool_handle, wallet_handle, _did, schema): - schema_request = await ledger.build_schema_request(_did, schema) - await ledger.sign_and_submit_request(pool_handle, wallet_handle, _did, schema_request) - - -async def send_cred_def(pool_handle, wallet_handle, _did, cred_def_json): - cred_def_request = await ledger.build_cred_def_request(_did, cred_def_json) - await ledger.sign_and_submit_request(pool_handle, wallet_handle, _did, cred_def_request) - - -async def get_schema(pool_handle, _did, schema_id): - get_schema_request = await ledger.build_get_schema_request(_did, schema_id) - get_schema_response = await ensure_previous_request_applied( - pool_handle, get_schema_request, lambda response: response['result']['data'] is not None) - return await ledger.parse_get_schema_response(get_schema_response) - - -async def get_cred_def(pool_handle, _did, cred_def_id): - get_cred_def_request = await ledger.build_get_cred_def_request(_did, cred_def_id) - get_cred_def_response = \ - await ensure_previous_request_applied(pool_handle, get_cred_def_request, - lambda response: response['result']['data'] is not None) - return await ledger.parse_get_cred_def_response(get_cred_def_response) - - -async def get_credential_for_referent(search_handle, referent): - credentials = json.loads( - await anoncreds.prover_fetch_credentials_for_proof_req(search_handle, referent, 10)) - return credentials[0]['cred_info'] - - -def get_timestamp_for_attribute(cred_for_attribute, revoc_states): - if cred_for_attribute['rev_reg_id'] in revoc_states: - return int(next(iter(revoc_states[cred_for_attribute['rev_reg_id']]))) - else: - return None - - -async def prover_get_entities_from_ledger(pool_handle, _did, identifiers, actor, timestamp_from=None, - timestamp_to=None): - schemas = {} - cred_defs = {} - rev_states = {} - for item in identifiers.values(): - logger.info("\"{}\" -> Get Schema from Ledger".format(actor)) - (received_schema_id, received_schema) = await get_schema(pool_handle, _did, item['schema_id']) - schemas[received_schema_id] = json.loads(received_schema) - - logger.info("\"{}\" -> Get Claim Definition from Ledger".format(actor)) - (received_cred_def_id, received_cred_def) = await get_cred_def(pool_handle, _did, item['cred_def_id']) - cred_defs[received_cred_def_id] = json.loads(received_cred_def) - - if 'rev_reg_id' in item and item['rev_reg_id'] is not None: - # Create Revocations States - logger.info("\"{}\" -> Get Revocation Registry Definition from Ledger".format(actor)) - get_revoc_reg_def_request = await ledger.build_get_revoc_reg_def_request(_did, item['rev_reg_id']) - - get_revoc_reg_def_response = \ - await ensure_previous_request_applied(pool_handle, get_revoc_reg_def_request, - lambda response: response['result']['data'] is not None) - (rev_reg_id, revoc_reg_def_json) = await ledger.parse_get_revoc_reg_def_response(get_revoc_reg_def_response) - - logger.info("\"{}\" -> Get Revocation Registry Delta from Ledger".format(actor)) - if not timestamp_to: timestamp_to = int(time.time()) - get_revoc_reg_delta_request = \ - await ledger.build_get_revoc_reg_delta_request(_did, item['rev_reg_id'], timestamp_from, timestamp_to) - get_revoc_reg_delta_response = \ - await ensure_previous_request_applied(pool_handle, get_revoc_reg_delta_request, - lambda response: response['result']['data'] is not None) - (rev_reg_id, revoc_reg_delta_json, t) = \ - await ledger.parse_get_revoc_reg_delta_response(get_revoc_reg_delta_response) - - tails_reader_config = json.dumps( - {'base_dir': dirname(json.loads(revoc_reg_def_json)['value']['tailsLocation']), - 'uri_pattern': ''}) - blob_storage_reader_cfg_handle = await blob_storage.open_reader('default', tails_reader_config) - - logger.info('%s - Create Revocation State', actor) - rev_state_json = \ - await anoncreds.create_revocation_state(blob_storage_reader_cfg_handle, revoc_reg_def_json, - revoc_reg_delta_json, t, item['cred_rev_id']) - rev_states[rev_reg_id] = {t: json.loads(rev_state_json)} - - return json.dumps(schemas), json.dumps(cred_defs), json.dumps(rev_states) - - -async def verifier_get_entities_from_ledger(pool_handle, _did, identifiers, actor, timestamp=None): - schemas = {} - cred_defs = {} - rev_reg_defs = {} - rev_regs = {} - for item in identifiers: - logger.info("\"{}\" -> Get Schema from Ledger".format(actor)) - (received_schema_id, received_schema) = await get_schema(pool_handle, _did, item['schema_id']) - schemas[received_schema_id] = json.loads(received_schema) - - logger.info("\"{}\" -> Get Claim Definition from Ledger".format(actor)) - (received_cred_def_id, received_cred_def) = await get_cred_def(pool_handle, _did, item['cred_def_id']) - cred_defs[received_cred_def_id] = json.loads(received_cred_def) - - if 'rev_reg_id' in item and item['rev_reg_id'] is not None: - # Get Revocation Definitions and Revocation Registries - logger.info("\"{}\" -> Get Revocation Definition from Ledger".format(actor)) - get_revoc_reg_def_request = await ledger.build_get_revoc_reg_def_request(_did, item['rev_reg_id']) - - get_revoc_reg_def_response = \ - await ensure_previous_request_applied(pool_handle, get_revoc_reg_def_request, - lambda response: response['result']['data'] is not None) - (rev_reg_id, revoc_reg_def_json) = await ledger.parse_get_revoc_reg_def_response(get_revoc_reg_def_response) - - logger.info("\"{}\" -> Get Revocation Registry from Ledger".format(actor)) - if not timestamp: timestamp = item['timestamp'] - get_revoc_reg_request = \ - await ledger.build_get_revoc_reg_request(_did, item['rev_reg_id'], timestamp) - get_revoc_reg_response = \ - await ensure_previous_request_applied(pool_handle, get_revoc_reg_request, - lambda response: response['result']['data'] is not None) - (rev_reg_id, rev_reg_json, timestamp2) = await ledger.parse_get_revoc_reg_response(get_revoc_reg_response) - - rev_regs[rev_reg_id] = {timestamp2: json.loads(rev_reg_json)} - rev_reg_defs[rev_reg_id] = json.loads(revoc_reg_def_json) - - return json.dumps(schemas), json.dumps(cred_defs), json.dumps(rev_reg_defs), json.dumps(rev_regs) - -def create_user_proof_file(json_file, user_proof): - logger.info(f"called create_user_proof_file()") - with open(json_file, 'w') as file: - file.write(user_proof) - logger.info(f"Saved proof to {json_file}") - -def request_discounted_cartrade(json_file): - # read json file - json_str = "" - with open(json_file, 'r') as file: - data = json.load(file) - json_str = json.dumps(data) - - # append data of json file to http req param - http_req_params["tradeParams"].append(json_str) - - # logger.info(f"http_params: url: {http_req_params['url']}") - # logger.info(f"http_params: businessLogicID: {http_req_params['businessLogicID']}") - # logger.info(f"http_params: tradeParams: {http_req_params['tradeParams']}") - # logger.info(f"http_params: authParams: {http_req_params['authParams']}") - - logger.info(f"http_params") - - req_url = http_req_params["url"] - req_header = {'Content-Type': 'application/json'} - req_body = {'businessLogicID': http_req_params["businessLogicID"], - 'tradeParams': http_req_params["tradeParams"], - 'authParams': http_req_params["authParams"]} - - logger.info(f"req_body: {req_body}") - - - # response = requests.post( - # http_req_params["url"], - # json.dumps({'businessLogicID': http_req_params["businessLogicID"], - # 'tradeParams': http_req_params["tradeParams"], - # 'authParams': http_req_params["authParams"]}), - # headers={'Content-Type': 'application/json'}) - - # send request - response = requests.post(req_url, headers=req_header, data=json.dumps(req_body)) - logger.info("return requests.post()") - logger.info("http_params: authParams: {}".format(http_req_params["authParams"])) - print(f"return requests.post()") - print(f"resp: {response}") - print(f"resp.text: {response.text}") - print(f"##----") - -if __name__ == '__main__': - run_coroutine(run) - time.sleep(1) # FIXME waiting for libindy thread complete diff --git a/examples/register-indy-data/script-build-docker.sh b/examples/register-indy-data/script-build-docker.sh deleted file mode 100755 index 0b2314bb03..0000000000 --- a/examples/register-indy-data/script-build-docker.sh +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright 2020-2022 Hyperledger Cactus Contributors -# SPDX-License-Identifier: Apache-2.0 - -echo "# Build base image for this tool - indy-sdk-cli" -pushd ../../tools/docker/indy-sdk-cli/ -docker build . -t indy-sdk-cli -popd - -echo "# Build register-indy-data tool" -docker build . -t register-indy-data diff --git a/packages-python/cactus_validator_socketio_indy/Dockerfile b/packages-python/cactus_validator_socketio_indy/Dockerfile index b9da60ae4c..8f601ea27a 100644 --- a/packages-python/cactus_validator_socketio_indy/Dockerfile +++ b/packages-python/cactus_validator_socketio_indy/Dockerfile @@ -1,4 +1,4 @@ -FROM indy-sdk-cli +FROM ghcr.io/hyperledger/indy-node-container/indy_node:1.12.6-ubuntu18-main USER root RUN apt-get update \ diff --git a/packages-python/cactus_validator_socketio_indy/README.md b/packages-python/cactus_validator_socketio_indy/README.md index 891ccc65fa..76d4afbad4 100644 --- a/packages-python/cactus_validator_socketio_indy/README.md +++ b/packages-python/cactus_validator_socketio_indy/README.md @@ -34,73 +34,6 @@ # Copy the contents of requirements.txt to setup.py install_requires list (adjust formatting accordingly). ``` -## Test - -- Use `testcli/testsock.js` to check basic communication pattern with the validator. - -### How-To - -1. Start indy testnet pool (follow instructions from `../../tools/docker/indy-testnet/` README). It should create docker network `indy-testnet_indy_net`, pool should be available at `172.16.0.2`. -1. Generate proof and store it in local `/etc/cactus`: - ``` - rm -r /etc/cactus/validator_socketio_indy/* - cd ../../examples/register-indy-data/ - ./script-build-docker.sh - docker run --rm -ti -v/etc/cactus/:/etc/cactus/ --net="host" register-indy-data --proof_only - ``` -1. Copy indy validator config - ``` - cp -rf ./config/* /etc/cactus/validator_socketio_indy/ - ``` -1. Generate validator certificate using OpenSSL tool - ``` - mkdir -p "/etc/cactus/validator_socketio_indy/CA/" - openssl ecparam -genkey -name "prime256v1" -out "/etc/cactus/validator_socketio_indy/CA/connector.priv" - openssl req -new -sha256 -key "/etc/cactus/validator_socketio_indy/CA/connector.priv" \ - -out "/etc/cactus/validator_socketio_indy/CA/connector.csr" \ - -subj "/C=JP/ST=Tokyo/L=Minato-Ku/O=CactusSamples/CN=IndyValidator" - openssl req -x509 -sha256 -days 365 -key "/etc/cactus/validator_socketio_indy/CA/connector.priv" \ - -in "/etc/cactus/validator_socketio_indy/CA/connector.csr" \ - -out "/etc/cactus/validator_socketio_indy/CA/connector.crt" - ``` -1. Build and run validator container: - - ``` - docker build . -t indy-validator - - docker run -v/etc/cactus/:/etc/cactus --rm --net="indy-testnet_indy_net" -p 10080:8000 indy-validator - ``` - -1. Open separate console, install dependencies and run the testing script: - - ``` - cd testcli/ - ln -s /etc/cactus/validator_socketio_indy/CA/connector.crt . - npm install - node testsock.js - ``` - - Output should look like this: - - ``` - connect - AVE5voPzdLLEcm5kAAAD - websocket - call nop! - call request2. get schema request. - #[recv]response, res: [object Object] - call verify() - ##signsignature: .... - Authentication OK - ##decoded: { - result: [ - 'Apyv5EV88KoZRqtXMmaeXV:2:Job-Certificate:0.2', - '{"ver":"1.0","id":"Apyv5EV88KoZRqtXMmaeXV:2:Job-Certificate:0.2","name":"Job-Certificate","version":"0.2","attrNames":["experience","last_name","salary","first_name","employee_status"],"seqNo":19}' - ] - } - OK - Done. - ``` - ## Manual Test - Validator used by `cactus-example-discounted-asset-trade` sample app. diff --git a/packages/cactus-cmd-socketio-server/src/main/typescript/routing-interface/RequestInfo.ts b/packages/cactus-cmd-socketio-server/src/main/typescript/routing-interface/RequestInfo.ts index 6d2878be47..40a6be9ba9 100644 --- a/packages/cactus-cmd-socketio-server/src/main/typescript/routing-interface/RequestInfo.ts +++ b/packages/cactus-cmd-socketio-server/src/main/typescript/routing-interface/RequestInfo.ts @@ -7,11 +7,6 @@ // transaction information -export class ProofJsonObj { - tradeInfo = ""; - proof_request = ""; - proof = ""; -} export class TradeInfo { ethereumAccountFrom: string = ""; ethereumAccountTo: string = ""; @@ -19,7 +14,7 @@ export class TradeInfo { fabricAccountTo: string = ""; tradingValue: string = ""; assetID: string = ""; - proofJson: ProofJsonObj = new ProofJsonObj(); + indyAgentConId: string = ""; } // authorization information diff --git a/packages/cactus-plugin-ledger-connector-iroha/package.json b/packages/cactus-plugin-ledger-connector-iroha/package.json index ca1f68086d..c91c55368e 100644 --- a/packages/cactus-plugin-ledger-connector-iroha/package.json +++ b/packages/cactus-plugin-ledger-connector-iroha/package.json @@ -63,6 +63,7 @@ "axios": "1.5.1", "express": "4.18.2", "fast-safe-stringify": "2.1.1", + "grpc": "1.24.11", "iroha-helpers": "1.5.0", "key-encoder": "2.0.3", "openapi-types": "7.0.1", diff --git a/tools/docker/indy-all-in-one/Dockerfile b/tools/docker/indy-all-in-one/Dockerfile new file mode 100644 index 0000000000..f787471df8 --- /dev/null +++ b/tools/docker/indy-all-in-one/Dockerfile @@ -0,0 +1,90 @@ +# Runs indy pool for testing purpose +# Original source - https://github.com/hyperledger/indy-vdr/blob/main/ci/indy-pool.dockerfile +# Changes marked with `EDIT` + +# EDIT - use stable indy release +FROM ghcr.io/hyperledger/indy-node-container/indy_node:1.12.6-ubuntu18-main +RUN pip3 install "supervisor~=4.2" + +# EDIT - change UID to simplify host dir mount +ARG UID=1000 +RUN usermod -u $UID indy +ENV UID=$UID + +RUN echo "[supervisord]\n\ +logfile = /tmp/supervisord.log\n\ +logfile_maxbytes = 50MB\n\ +logfile_backups=10\n\ +logLevel = error\n\ +pidfile = /tmp/supervisord.pid\n\ +nodaemon = true\n\ +minfds = 1024\n\ +minprocs = 200\n\ +umask = 022\n\ +user = indy\n\ +identifier = supervisor\n\ +directory = /tmp\n\ +nocleanup = true\n\ +childlogdir = /tmp\n\ +strip_ansi = false\n\ +\n\ +[program:node1]\n\ +command=start_indy_node Node1 0.0.0.0 9701 0.0.0.0 9702\n\ +directory=/home/indy\n\ +stdout_logfile=/tmp/node1.log\n\ +stderr_logfile=/tmp/node1.log\n\ +\n\ +[program:node2]\n\ +command=start_indy_node Node2 0.0.0.0 9703 0.0.0.0 9704\n\ +directory=/home/indy\n\ +stdout_logfile=/tmp/node2.log\n\ +stderr_logfile=/tmp/node2.log\n\ +\n\ +[program:node3]\n\ +command=start_indy_node Node3 0.0.0.0 9705 0.0.0.0 9706\n\ +directory=/home/indy\n\ +stdout_logfile=/tmp/node3.log\n\ +stderr_logfile=/tmp/node3.log\n\ +\n\ +[program:node4]\n\ +command=start_indy_node Node4 0.0.0.0 9707 0.0.0.0 9708\n\ +directory=/home/indy\n\ +stdout_logfile=/tmp/node4.log\n\ +stderr_logfile=/tmp/node4.log\n"\ + >> /etc/supervisord.conf + +RUN mkdir -p \ + /etc/indy \ + /var/lib/indy/backup \ + /var/lib/indy/plugins \ + /var/lib/indy/sandbox \ + /var/log/indy \ + && chown -R indy:root /etc/indy /var/lib/indy /var/log/indy + +# EDIT - Setup healthcheck +COPY ./healthcheck.sh /bin/healthcheck +RUN chmod +x /bin/healthcheck +HEALTHCHECK --interval=5s --timeout=10s --start-period=45s --retries=60 CMD /bin/healthcheck + +USER indy + +RUN echo "LEDGER_DIR = '/var/lib/indy'\n\ +LOG_DIR = '/var/log/indy'\n\ +KEYS_DIR = '/var/lib/indy'\n\ +GENESIS_DIR = '/var/lib/indy'\n\ +BACKUP_DIR = '/var/lib/indy/backup'\n\ +PLUGINS_DIR = '/var/lib/indy/plugins'\n\ +NODE_INFO_DIR = '/var/lib/indy'\n\ +NETWORK_NAME = 'sandbox'\n"\ + >> /etc/indy/indy_config.py + +ARG pool_ip=127.0.0.1 + +# EDIT - Store pool ip in environment variable +ENV POOL_IP=$pool_ip + +EXPOSE 9701 9702 9703 9704 9705 9706 9707 9708 + +# EDIT - Use different entry script- generate indy pool just once +COPY --chown=indy 'startup.sh' '/usr/bin/' +CMD [ "/usr/bin/startup.sh" ] diff --git a/tools/docker/indy-all-in-one/README.md b/tools/docker/indy-all-in-one/README.md new file mode 100644 index 0000000000..22a11cd004 --- /dev/null +++ b/tools/docker/indy-all-in-one/README.md @@ -0,0 +1,50 @@ +# indy-all-in-one + +An all in one Indy ledger image. + +- Image is based on the upstream - https://github.com/hyperledger/indy-vdr/blob/main/ci/indy-pool.dockerfile +- This docker image is for `testing` and `development` only. +- **Do NOT use in production!** + +## Usage + +### Docker Compose + +```bash +./script-start-docker.sh + +# or +mkdir -p "/tmp/indy-all-in-one/" +docker-compose build && docker-compose up -d +``` + +### Docker + +```bash +# Build +DOCKER_BUILDKIT=1 docker build ./tools/docker/indy-all-in-one/ -t cactus_indy_all_in_one + +# Run +docker run --rm --name indy-all-in-one --detach -p 9703:9703 -p 9704:9704 -p 9705:9705 -p 9706:9706 -p 9707:9707 -p 9708:9708 -v /tmp/indy-all-in-one/:/var/lib/indy/sandbox/ cactus_indy_all_in_one +``` + +### Cleanup + +```bash +./script-cleanup.sh + +# or +docker compose down +rm -fr /tmp/indy-all-in-one/* +sudo find ~/.afj/data/wallet/ -iname '*cacti*' -exec rm -fr {} \; +``` + +## Test + +### cactus-example-discounted-asset-trade-client +- `cactus-example-discounted-asset-trade-client` can be used to quickly check if this ledger is working correctly. +- Use `setup-credentials` from that package to register, issue and proof employment credential between `Issuer` and `Alice` agents. +- Run `cactus-example-discounted-asset-trade` for complete example scenario. + +### Typescript Setup Class +- There's no typescript setup class yet (TODO) \ No newline at end of file diff --git a/tools/docker/indy-testnet/docker-compose.yaml b/tools/docker/indy-all-in-one/docker-compose.yaml similarity index 54% rename from tools/docker/indy-testnet/docker-compose.yaml rename to tools/docker/indy-all-in-one/docker-compose.yaml index 37ddb20e4b..61bc718b78 100644 --- a/tools/docker/indy-testnet/docker-compose.yaml +++ b/tools/docker/indy-all-in-one/docker-compose.yaml @@ -1,11 +1,14 @@ version: "3" services: - indy-testnet-pool: - container_name: ${CACTUS_INDY_TESTNET_NAME:-indy-testnet-pool} - image: ${CACTUS_INDY_TESTNET_IMAGE_NAME:-indy-testnet-pool} + indy-all-in-one: + container_name: ${CACTUS_INDY_ALL_IN_ONE_NAME:-indy-all-in-one} + image: ${CACTUS_INDY_ALL_IN_ONE_IMAGE_NAME:-indy-all-in-one} build: context: ./ + args: + - pool_ip=172.16.0.2 + - UID=${UID:-1000} ports: - "9701:9701" - "9702:9702" @@ -16,13 +19,13 @@ services: - "9707:9707" - "9708:9708" networks: - indy_net: + indy_aio_net: ipv4_address: 172.16.0.2 volumes: - - ./sandbox:/var/lib/indy/sandbox/ + - /tmp/indy-all-in-one/:/var/lib/indy/sandbox/ networks: - indy_net: + indy_aio_net: driver: bridge ipam: driver: default diff --git a/tools/docker/indy-all-in-one/healthcheck.sh b/tools/docker/indy-all-in-one/healthcheck.sh new file mode 100755 index 0000000000..0662c04dd7 --- /dev/null +++ b/tools/docker/indy-all-in-one/healthcheck.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env sh + +# Fail on first wrong command +set -e + +echo "Indy Ledger Healtcheck..." + +# Check health +txCount=$(read_ledger --type pool --count) +if [ "$txCount" -gt "0" ]; then + echo "Healtcheck OK." +else + echo "Wrong response from ledger tx count: ${txCount}" + exit 1 +fi diff --git a/tools/docker/indy-all-in-one/script-cleanup.sh b/tools/docker/indy-all-in-one/script-cleanup.sh new file mode 100755 index 0000000000..446122eaa4 --- /dev/null +++ b/tools/docker/indy-all-in-one/script-cleanup.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env sh + +echo "# Stop running indy" +docker compose down + +echo "# Clean Indy data" +rm -fr /tmp/indy-all-in-one/* + +echo "# Remove cacti wallets from '~/.afj' (Aries JS Framework)" +sudo find ~/.afj/data/wallet/ -iname '*cacti*' -exec rm -fr {} \; + +echo "# OK" \ No newline at end of file diff --git a/tools/docker/indy-all-in-one/script-start-docker.sh b/tools/docker/indy-all-in-one/script-start-docker.sh new file mode 100755 index 0000000000..45fef44d97 --- /dev/null +++ b/tools/docker/indy-all-in-one/script-start-docker.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env sh + +echo "# Create /tmp/indy-all-in-one/" +mkdir -p "/tmp/indy-all-in-one/" + +echo "# Start docker environment for Indy all-in-one" +docker-compose build && docker-compose up -d + +echo "# OK" \ No newline at end of file diff --git a/tools/docker/indy-testnet/startup.sh b/tools/docker/indy-all-in-one/startup.sh similarity index 89% rename from tools/docker/indy-testnet/startup.sh rename to tools/docker/indy-all-in-one/startup.sh index b3277c6f69..d0067407f0 100755 --- a/tools/docker/indy-testnet/startup.sh +++ b/tools/docker/indy-all-in-one/startup.sh @@ -6,4 +6,4 @@ if [ ! -e '/var/lib/indy/sandbox/pool_transactions_genesis' ]; then generate_indy_pool_transactions --nodes 4 --clients 5 --nodeNum 1 2 3 4 --ips="${POOL_IP},${POOL_IP},${POOL_IP},${POOL_IP}" fi -/usr/bin/supervisord +/usr/local/bin/supervisord diff --git a/tools/docker/indy-sdk-cli/Dockerfile b/tools/docker/indy-sdk-cli/Dockerfile deleted file mode 100644 index d7cf5c01e2..0000000000 --- a/tools/docker/indy-sdk-cli/Dockerfile +++ /dev/null @@ -1,66 +0,0 @@ -# Indy-SDK CLI Image -# Contains node and python environments and indy SDK, can be used as base for indy development. - -FROM ubuntu:bionic-20230530 - -ENV DEBIAN_FRONTEND 'noninteractive' - -WORKDIR /home/setup - -RUN apt-get update \ - && apt-get install -y \ - gnupg \ - software-properties-common \ - python3-apt \ - curl \ - dirmngr \ - apt-transport-https \ - lsb-release \ - ca-certificates \ - gcc \ - g++ \ - make \ - && rm -rf /var/lib/apt/lists/* - -# NodeJS - Updated to use the new NodeSource installation method -ENV NODE_MAJOR=16 -RUN curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /usr/share/keyrings/nodesource-archive-keyring.gpg \ - && echo "deb [arch=amd64 signed-by=/usr/share/keyrings/nodesource-archive-keyring.gpg] https://deb.nodesource.com/node_$NODE_MAJOR.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list - -# Indy-sdk -RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys CE7709D068DB5E88 \ - && add-apt-repository "deb https://repo.sovrin.org/sdk/deb bionic stable" \ - && apt-get update && apt-get install -y \ - nodejs \ - libindy \ - libnullpay \ - libvcx \ - indy-cli \ - && npm install indy-sdk \ - && npm cache clean --force \ - && rm -rf /var/lib/apt/lists/* - -# Python 3.8 -# WARNING -# update-alternatives here is convinient, but can cause troubles with some missing os packages (like python3-apt) -# in case of any errors, remove it and use explicit python3.8 -RUN apt-get update \ - && apt-get install -y python3.8 \ - && update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.8 2 \ - && apt-get install -y python3-pip \ - && pip3 install --upgrade pip \ - && pip3 install \ - python3-indy \ - requests \ - && rm -rf /var/lib/apt/lists/* - -RUN groupadd indy && useradd -m indy -g indy - -# TODO - utils.py as part of validator / separate python package -COPY --chown=indy:indy from-indy-sdk /home/indy/from-indy-sdk - -# User should run their scripts as indy -USER indy -WORKDIR /home/indy - -CMD [ "/bin/bash" ] diff --git a/tools/docker/indy-sdk-cli/README.md b/tools/docker/indy-sdk-cli/README.md deleted file mode 100644 index f7df88eef6..0000000000 --- a/tools/docker/indy-sdk-cli/README.md +++ /dev/null @@ -1,17 +0,0 @@ -# Indy SDK Cli -- Base image with working Indy SDK environment. - -## Features -- Indy SDK C-callable libraries (`libindy`, `libnullpay`, `libvcx`, `indy-cli`) -- Python 3.8 and `python3-indy` wrapper library. -- nodejs 12 and npm `indy-sdk` wrapper library. -- JS and Python `utils` helper module in `/home/indy/from-indy-sdk`. -- Used as base image for other indy tools in Cactus. - -## Build -``` -docker build . -t indy-sdk-cli -``` - -## Notes -- In case of `gpg: keyserver receive failed: Cannot assign requested address` error - retry until it succeeds. This is some spurious error with keyserver connection. diff --git a/tools/docker/indy-sdk-cli/from-indy-sdk/util.js b/tools/docker/indy-sdk-cli/from-indy-sdk/util.js deleted file mode 100644 index 4b8954516d..0000000000 --- a/tools/docker/indy-sdk-cli/from-indy-sdk/util.js +++ /dev/null @@ -1,55 +0,0 @@ -"use strict"; -const mkdirp = require('mkdirp'); -const fs = require('fs'); -const os = require('os'); - -async function getPoolGenesisTxnPath(poolName) { - let path = `${os.tmpdir()}/indy/${poolName}.txn`; - await savePoolGenesisTxnFile(path); - return path -}; - -async function poolGenesisTxnData() { - let poolIp = process.env.TEST_POOL_IP || "127.0.0.1"; - return `{"reqSignature": {}, "txn": {"data": {"data": {"alias": "Node1", "blskey": "4N8aUNHSgjQVgkpm8nhNEfDf6txHznoYREg9kirmJrkivgL4oSEimFF6nsQ6M41QvhM2Z33nves5vfSn9n1UwNFJBYtWVnHYMATn76vLuL3zU88KyeAYcHfsih3He6UHcXDxcaecHVz6jhCYz1P2UZn2bDVruL5wXpehgBfBaLKm3Ba", "blskey_pop": "RahHYiCvoNCtPTrVtP7nMC5eTYrsUA8WjXbdhNc8debh1agE9bGiJxWBXYNFbnJXoXhWFMvyqhqhRoq737YQemH5ik9oL7R4NTTCz2LEZhkgLJzB3QRQqJyBNyv7acbdHrAT8nQ9UkLbaVL9NBpnWXBTw4LEMePaSHEw66RzPNdAX1", "client_ip": "${poolIp}", "client_port": 9702, "node_ip": "${poolIp}", "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": "${poolIp}", "client_port": 9704, "node_ip": "${poolIp}", "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": "${poolIp}", "client_port": 9706, "node_ip": "${poolIp}", "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": "${poolIp}", "client_port": 9708, "node_ip": "${poolIp}", "node_port": 9707, "services": ["VALIDATOR"]}, "dest": "4PS3EDQ3dW1tci1Bp6543CfuuebjFrg36kLAUcskGfaA"}, "metadata": {"from": "TWwCRQRZ2ZHMJFn9TzLp7W"}, "type": "0"}, "txnMetadata": {"seqNo": 4, "txnId": "aa5e817d7cc626170eca175822029339a444eb0ee8f0bd20d3b0b76e566fb008"}, "ver": "1"}`; -} - -async function savePoolGenesisTxnFile(filePath) { - let data = await poolGenesisTxnData(); - await mkdir(filePath); - return fs.writeFileSync(filePath, data, 'utf8'); -} - -async function mkdir(filePath) { - return new Promise((resolve, reject) => { - let folderPath = filePath.split('/').slice(0, filePath.split('/').length - 1).join('/'); - mkdirp(folderPath, function(err, res) { - if(err) reject(err); - else resolve(res); - }) - }) -} - -function pathToIndyClientHome() { - return require('os').homedir() + "/.indy_client" -} - -function sleep(duration){ - return new Promise(resolve => { - setTimeout(resolve,duration) - }) -} - -function getCurrentTimeInSeconds() { - return Math.floor(Date.now() / 1000) -} - -module.exports = { - getPoolGenesisTxnPath, - getPathToIndyClientHome: pathToIndyClientHome, - sleep, - getCurrentTimeInSeconds -} \ No newline at end of file diff --git a/tools/docker/indy-sdk-cli/from-indy-sdk/utils.py b/tools/docker/indy-sdk-cli/from-indy-sdk/utils.py deleted file mode 100644 index 40cd90f2dd..0000000000 --- a/tools/docker/indy-sdk-cli/from-indy-sdk/utils.py +++ /dev/null @@ -1,63 +0,0 @@ -import asyncio -import json -from os import environ -from pathlib import Path -from tempfile import gettempdir - -import time -from indy import ledger - - -PROTOCOL_VERSION = 2 - - -def path_home() -> Path: - return Path.home().joinpath(".indy_client") - - -def get_pool_genesis_txn_path(pool_name): - path_temp = Path(gettempdir()).joinpath("indy") - path = path_temp.joinpath("{}.txn".format(pool_name)) - save_pool_genesis_txn_file(path) - return path - - -def pool_genesis_txn_data(): - pool_ip = environ.get("TEST_POOL_IP", "127.0.0.1") - - return "\n".join([ - '{{"reqSignature":{{}},"txn":{{"data":{{"data":{{"alias":"Node1","blskey":"4N8aUNHSgjQVgkpm8nhNEfDf6txHznoYREg9kirmJrkivgL4oSEimFF6nsQ6M41QvhM2Z33nves5vfSn9n1UwNFJBYtWVnHYMATn76vLuL3zU88KyeAYcHfsih3He6UHcXDxcaecHVz6jhCYz1P2UZn2bDVruL5wXpehgBfBaLKm3Ba","blskey_pop":"RahHYiCvoNCtPTrVtP7nMC5eTYrsUA8WjXbdhNc8debh1agE9bGiJxWBXYNFbnJXoXhWFMvyqhqhRoq737YQemH5ik9oL7R4NTTCz2LEZhkgLJzB3QRQqJyBNyv7acbdHrAT8nQ9UkLbaVL9NBpnWXBTw4LEMePaSHEw66RzPNdAX1","client_ip":"{}","client_port":9702,"node_ip":"{}","node_port":9701,"services":["VALIDATOR"]}},"dest":"Gw6pDLhcBcoQesN72qfotTgFa7cbuqZpkX3Xo6pLhPhv"}},"metadata":{{"from":"Th7MpTaRZVRYnPiabds81Y"}},"type":"0"}},"txnMetadata":{{"seqNo":1,"txnId":"fea82e10e894419fe2bea7d96296a6d46f50f93f9eeda954ec461b2ed2950b62"}},"ver":"1"}}'.format( - pool_ip, pool_ip), - '{{"reqSignature":{{}},"txn":{{"data":{{"data":{{"alias":"Node2","blskey":"37rAPpXVoxzKhz7d9gkUe52XuXryuLXoM6P6LbWDB7LSbG62Lsb33sfG7zqS8TK1MXwuCHj1FKNzVpsnafmqLG1vXN88rt38mNFs9TENzm4QHdBzsvCuoBnPH7rpYYDo9DZNJePaDvRvqJKByCabubJz3XXKbEeshzpz4Ma5QYpJqjk","blskey_pop":"Qr658mWZ2YC8JXGXwMDQTzuZCWF7NK9EwxphGmcBvCh6ybUuLxbG65nsX4JvD4SPNtkJ2w9ug1yLTj6fgmuDg41TgECXjLCij3RMsV8CwewBVgVN67wsA45DFWvqvLtu4rjNnE9JbdFTc1Z4WCPA3Xan44K1HoHAq9EVeaRYs8zoF5","client_ip":"{}","client_port":9704,"node_ip":"{}","node_port":9703,"services":["VALIDATOR"]}},"dest":"8ECVSk179mjsjKRLWiQtssMLgp6EPhWXtaYyStWPSGAb"}},"metadata":{{"from":"EbP4aYNeTHL6q385GuVpRV"}},"type":"0"}},"txnMetadata":{{"seqNo":2,"txnId":"1ac8aece2a18ced660fef8694b61aac3af08ba875ce3026a160acbc3a3af35fc"}},"ver":"1"}}'.format( - pool_ip, pool_ip), - '{{"reqSignature":{{}},"txn":{{"data":{{"data":{{"alias":"Node3","blskey":"3WFpdbg7C5cnLYZwFZevJqhubkFALBfCBBok15GdrKMUhUjGsk3jV6QKj6MZgEubF7oqCafxNdkm7eswgA4sdKTRc82tLGzZBd6vNqU8dupzup6uYUf32KTHTPQbuUM8Yk4QFXjEf2Usu2TJcNkdgpyeUSX42u5LqdDDpNSWUK5deC5","blskey_pop":"QwDeb2CkNSx6r8QC8vGQK3GRv7Yndn84TGNijX8YXHPiagXajyfTjoR87rXUu4G4QLk2cF8NNyqWiYMus1623dELWwx57rLCFqGh7N4ZRbGDRP4fnVcaKg1BcUxQ866Ven4gw8y4N56S5HzxXNBZtLYmhGHvDtk6PFkFwCvxYrNYjh","client_ip":"{}","client_port":9706,"node_ip":"{}","node_port":9705,"services":["VALIDATOR"]}},"dest":"DKVxG2fXXTU8yT5N7hGEbXB3dfdAnYv1JczDUHpmDxya"}},"metadata":{{"from":"4cU41vWW82ArfxJxHkzXPG"}},"type":"0"}},"txnMetadata":{{"seqNo":3,"txnId":"7e9f355dffa78ed24668f0e0e369fd8c224076571c51e2ea8be5f26479edebe4"}},"ver":"1"}}'.format( - pool_ip, pool_ip), - '{{"reqSignature":{{}},"txn":{{"data":{{"data":{{"alias":"Node4","blskey":"2zN3bHM1m4rLz54MJHYSwvqzPchYp8jkHswveCLAEJVcX6Mm1wHQD1SkPYMzUDTZvWvhuE6VNAkK3KxVeEmsanSmvjVkReDeBEMxeDaayjcZjFGPydyey1qxBHmTvAnBKoPydvuTAqx5f7YNNRAdeLmUi99gERUU7TD8KfAa6MpQ9bw","blskey_pop":"RPLagxaR5xdimFzwmzYnz4ZhWtYQEj8iR5ZU53T2gitPCyCHQneUn2Huc4oeLd2B2HzkGnjAff4hWTJT6C7qHYB1Mv2wU5iHHGFWkhnTX9WsEAbunJCV2qcaXScKj4tTfvdDKfLiVuU2av6hbsMztirRze7LvYBkRHV3tGwyCptsrP","client_ip":"{}","client_port":9708,"node_ip":"{}","node_port":9707,"services":["VALIDATOR"]}},"dest":"4PS3EDQ3dW1tci1Bp6543CfuuebjFrg36kLAUcskGfaA"}},"metadata":{{"from":"TWwCRQRZ2ZHMJFn9TzLp7W"}},"type":"0"}},"txnMetadata":{{"seqNo":4,"txnId":"aa5e817d7cc626170eca175822029339a444eb0ee8f0bd20d3b0b76e566fb008"}},"ver":"1"}}'.format( - pool_ip, pool_ip) - ]) - - -def save_pool_genesis_txn_file(path): - data = pool_genesis_txn_data() - - path.parent.mkdir(parents=True, exist_ok=True) - - with open(str(path), "w+") as f: - f.writelines(data) - - -def run_coroutine(coroutine, loop=None): - if loop is None: - loop = asyncio.get_event_loop() - loop.run_until_complete(coroutine()) - - -async def ensure_previous_request_applied(pool_handle, checker_request, checker): - for _ in range(3): - response = json.loads(await ledger.submit_request(pool_handle, checker_request)) - try: - if checker(response): - return json.dumps(response) - except TypeError: - pass - time.sleep(5) diff --git a/tools/docker/indy-testnet/.gitignore b/tools/docker/indy-testnet/.gitignore deleted file mode 100644 index aaaab80887..0000000000 --- a/tools/docker/indy-testnet/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -sandbox/* -!sandbox/.gitkeep \ No newline at end of file diff --git a/tools/docker/indy-testnet/Dockerfile b/tools/docker/indy-testnet/Dockerfile deleted file mode 100644 index fca263019a..0000000000 --- a/tools/docker/indy-testnet/Dockerfile +++ /dev/null @@ -1,106 +0,0 @@ -# Runs indy pool for testing purpose -# Original source - https://github.com/hyperledger/indy-sdk/blob/master/ci/indy-pool.dockerfile -# Changes marked with `EDIT` - -FROM ubuntu:16.04 - -ARG uid=1000 - -# Install environment -RUN apt-get update -y && apt-get install -y \ - git \ - wget \ - python3.5 \ - python3-pip \ - python-setuptools \ - python3-nacl \ - apt-transport-https \ - ca-certificates \ - supervisor - -RUN pip3 install -U \ - pip==9.0.3 \ - setuptools - -RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys CE7709D068DB5E88 || \ - apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys CE7709D068DB5E88 -ARG indy_stream=master -RUN echo "deb https://repo.sovrin.org/deb xenial $indy_stream" >> /etc/apt/sources.list - -RUN useradd -ms /bin/bash -u $uid indy - -ARG indy_plenum_ver=1.12.1~dev989 -ARG indy_node_ver=1.12.1~dev1172 -ARG python3_indy_crypto_ver=0.4.5 -ARG indy_crypto_ver=0.4.5 -ARG python3_pyzmq_ver=18.1.0 -ARG python3_orderedset_ver=2.0 -ARG python3_psutil_ver=5.4.3 -ARG python3_pympler_ver=0.5 - -RUN apt-get update -y && apt-get install -y \ - python3-pyzmq=${python3_pyzmq_ver} \ - indy-plenum=${indy_plenum_ver} \ - indy-node=${indy_node_ver} \ - python3-indy-crypto=${python3_indy_crypto_ver} \ - libindy-crypto=${indy_crypto_ver} \ - python3-orderedset=${python3_orderedset_ver} \ - python3-psutil=${python3_psutil_ver} \ - python3-pympler=${python3_pympler_ver} \ - vim - -RUN echo "[supervisord]\n\ -logfile = /tmp/supervisord.log\n\ -logfile_maxbytes = 50MB\n\ -logfile_backups=10\n\ -logLevel = error\n\ -pidfile = /tmp/supervisord.pid\n\ -nodaemon = true\n\ -minfds = 1024\n\ -minprocs = 200\n\ -umask = 022\n\ -user = indy\n\ -identifier = supervisor\n\ -directory = /tmp\n\ -nocleanup = true\n\ -childlogdir = /tmp\n\ -strip_ansi = false\n\ -\n\ -[program:node1]\n\ -command=start_indy_node Node1 0.0.0.0 9701 0.0.0.0 9702\n\ -directory=/home/indy\n\ -stdout_logfile=/tmp/node1.log\n\ -stderr_logfile=/tmp/node1.log\n\ -\n\ -[program:node2]\n\ -command=start_indy_node Node2 0.0.0.0 9703 0.0.0.0 9704\n\ -directory=/home/indy\n\ -stdout_logfile=/tmp/node2.log\n\ -stderr_logfile=/tmp/node2.log\n\ -\n\ -[program:node3]\n\ -command=start_indy_node Node3 0.0.0.0 9705 0.0.0.0 9706\n\ -directory=/home/indy\n\ -stdout_logfile=/tmp/node3.log\n\ -stderr_logfile=/tmp/node3.log\n\ -\n\ -[program:node4]\n\ -command=start_indy_node Node4 0.0.0.0 9707 0.0.0.0 9708\n\ -directory=/home/indy\n\ -stdout_logfile=/tmp/node4.log\n\ -stderr_logfile=/tmp/node4.log\n"\ ->> /etc/supervisord.conf - -USER indy - -RUN awk '{if (index($1, "NETWORK_NAME") != 0) {print("NETWORK_NAME = \"sandbox\"")} else print($0)}' /etc/indy/indy_config.py> /tmp/indy_config.py -RUN mv /tmp/indy_config.py /etc/indy/indy_config.py - -# EDIT - Use different default pool IP -ARG pool_ip=172.16.0.2 -ENV POOL_IP=$pool_ip -EXPOSE 9701 9702 9703 9704 9705 9706 9707 9708 - -# EDIT - Use different entry script- generate indy pool just once -COPY --chown=indy 'startup.sh' '/usr/bin/' -CMD [ "/usr/bin/startup.sh" ] diff --git a/tools/docker/indy-testnet/README.md b/tools/docker/indy-testnet/README.md deleted file mode 100644 index f54ae8b12a..0000000000 --- a/tools/docker/indy-testnet/README.md +++ /dev/null @@ -1,35 +0,0 @@ -# Indy TestNet Pool - -## Abstract -- Docker compose file can be used to build and start test indy pool. -- Pool is available in docker bridge network indy_net (`172.16.0.0/24`) -- Image is based on the upstream - https://github.com/hyperledger/indy-sdk/blob/1.6.x/ci/indy-pool.dockerfile - -## How to build -``` -docker-compose build -``` - -## How to start -- `-d` will cause the containers to run in detached mode, can be removed. -``` -docker-compose up -d -``` - -## How to stop -``` -docker-compose down -``` - -## Test - Generate Proof -- You can test the setup by generating a proof using our helper tool in `../../../examples/register-indy-data/` -- Follow build instructions described in `register-indy-data` README. -- Run container to generate proof only, use force flag to overwrite possible leftovers from previous runs. It will save the proof in `/etc/cactus/validator_socketio_indy/myproof.json` -``` -docker run --rm -ti -v/etc/cactus/:/etc/cactus/ --net="host" register-indy-data --force --proof_only -``` - -## Cleanup -``` -./script-cleanup.sh -``` diff --git a/tools/docker/indy-testnet/sandbox/.gitkeep b/tools/docker/indy-testnet/sandbox/.gitkeep deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/tools/docker/indy-testnet/script-cleanup.sh b/tools/docker/indy-testnet/script-cleanup.sh deleted file mode 100755 index f0574dea10..0000000000 --- a/tools/docker/indy-testnet/script-cleanup.sh +++ /dev/null @@ -1,6 +0,0 @@ -# Copyright 2020-2022 Hyperledger Cactus Contributors -# SPDX-License-Identifier: Apache-2.0 - -echo "# Clean Indy sandbox" -find ./sandbox/ ! -name .gitkeep ! -name sandbox -exec rm -fr {} \; -echo "# OK" \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index 5f2373c806..7e67e58009 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -151,6 +151,9 @@ { "path": "./examples/cactus-example-discounted-asset-trade/tsconfig.json" }, + { + "path": "./examples/cactus-example-discounted-asset-trade-client/tsconfig.json" + }, { "path": "./examples/cactus-example-cbdc-bridging-backend/tsconfig.json" }, diff --git a/yarn.lock b/yarn.lock index cc8c8449c6..49ab8e5156 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5,6 +5,34 @@ __metadata: version: 6 cacheKey: 8 +"@2060.io/ffi-napi@npm:4.0.8, @2060.io/ffi-napi@npm:^4.0.8": + version: 4.0.8 + resolution: "@2060.io/ffi-napi@npm:4.0.8" + dependencies: + "@2060.io/ref-napi": ^3.0.6 + debug: ^4.1.1 + get-uv-event-loop-napi-h: ^1.0.5 + node-addon-api: ^3.0.0 + node-gyp: latest + node-gyp-build: ^4.2.1 + ref-struct-di: ^1.1.0 + checksum: 7c2318776b6482032e51046255ed8830069a7e602f839df333b678ebf7b79f490b4cd88117745cb40c8813f31aa0cb973822ad57e1abbc1bac1fd48063b51b79 + languageName: node + linkType: hard + +"@2060.io/ref-napi@npm:3.0.6, @2060.io/ref-napi@npm:^3.0.6": + version: 3.0.6 + resolution: "@2060.io/ref-napi@npm:3.0.6" + dependencies: + debug: ^4.1.1 + get-symbol-from-current-process-h: ^1.0.2 + node-addon-api: ^3.0.0 + node-gyp: latest + node-gyp-build: ^4.2.1 + checksum: e4fd11e846d890151ac8d7d56304455bbad096e329c41c50453db87b0c14940bbc5e081b700f2e12650b86a9a964095c822b9549a42f11567e0d7f10a2285d93 + languageName: node + linkType: hard + "@aashutoshrathi/word-wrap@npm:^1.2.3": version: 1.2.6 resolution: "@aashutoshrathi/word-wrap@npm:1.2.6" @@ -571,6 +599,129 @@ __metadata: languageName: node linkType: hard +"@aries-framework/anoncreds-rs@npm:0.5.0-alpha.58": + version: 0.5.0-alpha.58 + resolution: "@aries-framework/anoncreds-rs@npm:0.5.0-alpha.58" + dependencies: + "@aries-framework/anoncreds": 0.5.0-alpha.58+17854790 + "@aries-framework/core": 0.5.0-alpha.58+17854790 + class-transformer: ^0.5.1 + class-validator: 0.14.0 + rxjs: ^7.2.0 + tsyringe: ^4.8.0 + peerDependencies: + "@hyperledger/anoncreds-shared": ^0.2.0-dev.4 + checksum: 8df978697e94920c1c65cb8bb6ecd5634d0e88ce175f5634f629d5aecffb4e7f6d30235cf848e59053d367c07737f2ad4ef3e1663738c6518aa8b45d29d2c627 + languageName: node + linkType: hard + +"@aries-framework/anoncreds@npm:0.5.0-alpha.58, @aries-framework/anoncreds@npm:0.5.0-alpha.58+17854790": + version: 0.5.0-alpha.58 + resolution: "@aries-framework/anoncreds@npm:0.5.0-alpha.58" + dependencies: + "@aries-framework/core": 0.5.0-alpha.58+17854790 + bn.js: ^5.2.1 + class-transformer: 0.5.1 + class-validator: 0.14.0 + reflect-metadata: ^0.1.13 + checksum: 33e3762764c026c861e73eda33d6ccbe0899c66cf7f0ba4bf520f4c2c72781631c4cd03ca7c9487eb6e8569e06c7c223161edaaa03b62b51069e0f4146d64ca3 + languageName: node + linkType: hard + +"@aries-framework/askar@npm:0.5.0-alpha.58": + version: 0.5.0-alpha.58 + resolution: "@aries-framework/askar@npm:0.5.0-alpha.58" + dependencies: + "@aries-framework/core": 0.5.0-alpha.58+17854790 + bn.js: ^5.2.1 + class-transformer: 0.5.1 + class-validator: 0.14.0 + rxjs: ^7.2.0 + tsyringe: ^4.8.0 + peerDependencies: + "@hyperledger/aries-askar-shared": ^0.2.0-dev.1 + checksum: a64ee751a0c3e822b163044c7dbd183eed5153e9b14ffa196bbb1a320d0e25ce285a614eef7919dab275b6555aee164c020bc28e6b1cb6172696eda7ea0dbae9 + languageName: node + linkType: hard + +"@aries-framework/core@npm:0.5.0-alpha.58, @aries-framework/core@npm:0.5.0-alpha.58+17854790": + version: 0.5.0-alpha.58 + resolution: "@aries-framework/core@npm:0.5.0-alpha.58" + dependencies: + "@digitalcredentials/jsonld": ^5.2.1 + "@digitalcredentials/jsonld-signatures": ^9.3.1 + "@digitalcredentials/vc": ^1.1.2 + "@multiformats/base-x": ^4.0.1 + "@stablelib/ed25519": ^1.0.2 + "@stablelib/random": ^1.0.1 + "@stablelib/sha256": ^1.0.1 + "@types/node-fetch": 2.6.2 + "@types/ws": ^8.5.4 + abort-controller: ^3.0.0 + big-integer: ^1.6.51 + borc: ^3.0.0 + buffer: ^6.0.3 + class-transformer: 0.5.1 + class-validator: 0.14.0 + did-resolver: ^4.1.0 + lru_map: ^0.4.1 + luxon: ^3.3.0 + make-error: ^1.3.6 + object-inspect: ^1.10.3 + query-string: ^7.0.1 + reflect-metadata: ^0.1.13 + rxjs: ^7.2.0 + tsyringe: ^4.8.0 + uuid: ^9.0.0 + varint: ^6.0.0 + web-did-resolver: ^2.0.21 + checksum: a22fb956536a25d1534201be9ac32462714695d237749caf09ffaec4e2e967a7869a30db9da218e52e8d7f33ea60f02fcabad8faf1743d6000482bb6521415ac + languageName: node + linkType: hard + +"@aries-framework/indy-sdk@npm:0.5.0-alpha.58": + version: 0.5.0-alpha.58 + resolution: "@aries-framework/indy-sdk@npm:0.5.0-alpha.58" + dependencies: + "@aries-framework/anoncreds": 0.5.0-alpha.58+17854790 + "@aries-framework/core": 0.5.0-alpha.58+17854790 + "@stablelib/ed25519": ^1.0.3 + "@types/indy-sdk": 1.16.27 + class-transformer: 0.5.1 + class-validator: 0.14.0 + rxjs: ^7.2.0 + tsyringe: ^4.8.0 + checksum: 6823f2cdb5401736d64f72dee80e5ec543547b0778d83c0392304f63b093ec049c17fe6d1ce9792ae8912e4888a8a85e3449ad2f0963713ae3199f395770ea9e + languageName: node + linkType: hard + +"@aries-framework/indy-vdr@npm:0.5.0-alpha.58": + version: 0.5.0-alpha.58 + resolution: "@aries-framework/indy-vdr@npm:0.5.0-alpha.58" + dependencies: + "@aries-framework/anoncreds": 0.5.0-alpha.58+17854790 + "@aries-framework/core": 0.5.0-alpha.58+17854790 + peerDependencies: + "@hyperledger/indy-vdr-shared": ^0.2.0-dev.3 + checksum: 4d120f313d344ec5b720eac07628cf0725ab86d8818b400e4c856e2f578c89c8f649e16f863a975b143239ff5ed0503e0d01f4d8a78b7f46c04f36339ff33865 + languageName: node + linkType: hard + +"@aries-framework/node@npm:0.5.0-alpha.58": + version: 0.5.0-alpha.58 + resolution: "@aries-framework/node@npm:0.5.0-alpha.58" + dependencies: + "@2060.io/ffi-napi": ^4.0.8 + "@2060.io/ref-napi": ^3.0.6 + "@aries-framework/core": 0.5.0-alpha.58+17854790 + "@types/express": ^4.17.15 + express: ^4.17.1 + node-fetch: ^2.6.1 + ws: ^8.13.0 + checksum: 52b32e188b869a0368aeda47cb2042c638cf35c59e1070209f81166aa1e4a23c1aa68b8f574332756c481ba7bd837bbda4bff156931622a72a6b8f28402f5ce8 + languageName: node + linkType: hard + "@assemblyscript/loader@npm:^0.10.1": version: 0.10.1 resolution: "@assemblyscript/loader@npm:0.10.1" @@ -4848,6 +4999,81 @@ __metadata: languageName: node linkType: hard +"@digitalbazaar/security-context@npm:^1.0.0": + version: 1.0.1 + resolution: "@digitalbazaar/security-context@npm:1.0.1" + checksum: acba0adbee983d5c3fac7e0f4d710888493edbf88d76adf94831e947becfd25640df74195616ba9c1607c396b20b91166e0a065a8cf04a08d3d2f2f068425d2f + languageName: node + linkType: hard + +"@digitalcredentials/http-client@npm:^1.0.0": + version: 1.2.2 + resolution: "@digitalcredentials/http-client@npm:1.2.2" + dependencies: + ky: ^0.25.1 + ky-universal: ^0.8.2 + checksum: d0bf12225ad73c8e3a32b52d13a41322e4c5a6c3a3e6bb1ec620410cf56cb7ebce5626ae12c9a0ea13dd78fc66b27b1901d4215ecc4a19f2be8d477e05ebeede + languageName: node + linkType: hard + +"@digitalcredentials/jsonld-signatures@npm:^9.3.1": + version: 9.3.2 + resolution: "@digitalcredentials/jsonld-signatures@npm:9.3.2" + dependencies: + "@digitalbazaar/security-context": ^1.0.0 + "@digitalcredentials/jsonld": ^6.0.0 + fast-text-encoding: ^1.0.3 + isomorphic-webcrypto: ^2.3.8 + serialize-error: ^8.0.1 + checksum: e3e093fe52bfab78b0e5556ba17678e6d1f884f75763c04b5e17af0450576ac21ba05b074fb1385ee357aa6eee0915f77c370b05e79405c5bf8a7726b90d8356 + languageName: node + linkType: hard + +"@digitalcredentials/jsonld@npm:^5.2.1": + version: 5.2.2 + resolution: "@digitalcredentials/jsonld@npm:5.2.2" + dependencies: + "@digitalcredentials/http-client": ^1.0.0 + "@digitalcredentials/rdf-canonize": ^1.0.0 + canonicalize: ^1.0.1 + lru-cache: ^6.0.0 + checksum: 3d62a7da7c671f585ed81aae73f9682626487463d6f7661b41108652835daeca818a1af10ae464b314dd8241347f3dcaa343c0f396ffe7e7ffa50dce2ef52e15 + languageName: node + linkType: hard + +"@digitalcredentials/jsonld@npm:^6.0.0": + version: 6.0.0 + resolution: "@digitalcredentials/jsonld@npm:6.0.0" + dependencies: + "@digitalcredentials/http-client": ^1.0.0 + "@digitalcredentials/rdf-canonize": ^1.0.0 + canonicalize: ^1.0.1 + lru-cache: ^6.0.0 + checksum: 67392a90861b487e23e7984ad89c3ce7a9ecc4b1c4af0cfae62bb301501e78eef84c83588ef02117a1d19936c5ee129e5937320c235ef3ee8fc2bdd5e5f4195c + languageName: node + linkType: hard + +"@digitalcredentials/rdf-canonize@npm:^1.0.0": + version: 1.0.0 + resolution: "@digitalcredentials/rdf-canonize@npm:1.0.0" + dependencies: + fast-text-encoding: ^1.0.3 + isomorphic-webcrypto: ^2.3.8 + checksum: 20aea6a88de62508431c2892e4258a02ac4376061fb261dc8beef67d4dfaffbb45efc50eb808526f9f5a4dd5fa10b38c6072c957c82cc0229d3ab1b2143a605d + languageName: node + linkType: hard + +"@digitalcredentials/vc@npm:^1.1.2": + version: 1.1.2 + resolution: "@digitalcredentials/vc@npm:1.1.2" + dependencies: + "@digitalcredentials/jsonld": ^5.2.1 + "@digitalcredentials/jsonld-signatures": ^9.3.1 + credentials-context: ^2.0.0 + checksum: 62920201c94d951462ab262907d64a4b48a90c71dbf88424687b483c5cb230f37274673769d1e83d7cc78ecfca1a7864876ba8b5eb374e7df5fac26c99dcf15a + languageName: node + linkType: hard + "@discoveryjs/json-ext@npm:0.5.7": version: 0.5.7 resolution: "@discoveryjs/json-ext@npm:0.5.7" @@ -6561,6 +6787,51 @@ __metadata: languageName: node linkType: hard +"@hyperledger/anoncreds-nodejs@npm:0.2.0-dev.4": + version: 0.2.0-dev.4 + resolution: "@hyperledger/anoncreds-nodejs@npm:0.2.0-dev.4" + dependencies: + "@2060.io/ffi-napi": 4.0.8 + "@2060.io/ref-napi": 3.0.6 + "@hyperledger/anoncreds-shared": 0.2.0-dev.4 + "@mapbox/node-pre-gyp": ^1.0.11 + ref-array-di: 1.2.2 + ref-struct-di: 1.1.1 + checksum: 59212179553fa10711a162c10a34793a1db7d6dcb407b16f09796aa19d70041ba3694e77cb044a0dde0ec0c373851ca62f0fc51c459bcc93b0317d034cd80f52 + languageName: node + linkType: hard + +"@hyperledger/anoncreds-shared@npm:0.2.0-dev.4": + version: 0.2.0-dev.4 + resolution: "@hyperledger/anoncreds-shared@npm:0.2.0-dev.4" + checksum: 9081a3a5eb847407f71b5cec043f013096e654025921748f5957177396c72e62a4fafb5b51dcf37c66274ae1cc5fa04bbde599ac39f9dae2ccee5b7306ceaaa1 + languageName: node + linkType: hard + +"@hyperledger/aries-askar-nodejs@npm:0.2.0-dev.1": + version: 0.2.0-dev.1 + resolution: "@hyperledger/aries-askar-nodejs@npm:0.2.0-dev.1" + dependencies: + "@2060.io/ffi-napi": 4.0.8 + "@2060.io/ref-napi": 3.0.6 + "@hyperledger/aries-askar-shared": 0.2.0-dev.1 + "@mapbox/node-pre-gyp": ^1.0.10 + node-cache: ^5.1.2 + ref-array-di: ^1.2.2 + ref-struct-di: ^1.1.1 + checksum: 40857e538e96f9fba19858fcc6dfc7489e2d4b49632ae56e3c21074967f388335fd05b17ea5c3fc35bddb544a17a633360ae5355308da8d0121a961ad355ab43 + languageName: node + linkType: hard + +"@hyperledger/aries-askar-shared@npm:0.2.0-dev.1": + version: 0.2.0-dev.1 + resolution: "@hyperledger/aries-askar-shared@npm:0.2.0-dev.1" + dependencies: + buffer: ^6.0.3 + checksum: cca77b5554986d561c1ec4512a6b598b0fd161d38238fe5ffee44f75054953a097604ca7f8af74b30a287981d3052f014193f082d0a51595037a0e4f168d6e00 + languageName: node + linkType: hard + "@hyperledger/cacti-example-cbdc-bridging-frontend@workspace:examples/cactus-example-cbdc-bridging-frontend": version: 0.0.0-use.local resolution: "@hyperledger/cacti-example-cbdc-bridging-frontend@workspace:examples/cactus-example-cbdc-bridging-frontend" @@ -7202,6 +7473,30 @@ __metadata: languageName: unknown linkType: soft +"@hyperledger/cactus-example-discounted-asset-trade-client@2.0.0-alpha.2, @hyperledger/cactus-example-discounted-asset-trade-client@workspace:examples/cactus-example-discounted-asset-trade-client": + version: 0.0.0-use.local + resolution: "@hyperledger/cactus-example-discounted-asset-trade-client@workspace:examples/cactus-example-discounted-asset-trade-client" + dependencies: + "@aries-framework/anoncreds": 0.5.0-alpha.58 + "@aries-framework/anoncreds-rs": 0.5.0-alpha.58 + "@aries-framework/askar": 0.5.0-alpha.58 + "@aries-framework/core": 0.5.0-alpha.58 + "@aries-framework/indy-sdk": 0.5.0-alpha.58 + "@aries-framework/indy-vdr": 0.5.0-alpha.58 + "@aries-framework/node": 0.5.0-alpha.58 + "@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 + "@types/inquirer": 8.2.6 + axios: 1.5.1 + inquirer: 8.2.6 + loglevel: 1.8.1 + bin: + run-discounted-asset-trade-client: dist/lib/main/typescript/scripts/run-discounted-asset-trade-client.js + setup-credentials: dist/lib/main/typescript/scripts/setup-credentials.js + languageName: unknown + linkType: soft + "@hyperledger/cactus-example-discounted-asset-trade@workspace:examples/cactus-example-discounted-asset-trade": version: 0.0.0-use.local resolution: "@hyperledger/cactus-example-discounted-asset-trade@workspace:examples/cactus-example-discounted-asset-trade" @@ -7210,14 +7505,13 @@ __metadata: "@hyperledger/cactus-common": 2.0.0-alpha.2 "@hyperledger/cactus-core": 2.0.0-alpha.2 "@hyperledger/cactus-core-api": 2.0.0-alpha.2 + "@hyperledger/cactus-example-discounted-asset-trade-client": 2.0.0-alpha.2 "@hyperledger/cactus-plugin-keychain-memory": 2.0.0-alpha.2 "@hyperledger/cactus-plugin-ledger-connector-ethereum": 2.0.0-alpha.2 "@hyperledger/cactus-plugin-ledger-connector-fabric": 2.0.0-alpha.2 - "@hyperledger/cactus-verifier-client": 2.0.0-alpha.2 "@types/elliptic": 6.4.14 "@types/escape-html": 1.0.1 "@types/express": 4.17.19 - "@types/indy-sdk": 1.16.29 "@types/jsonwebtoken": 9.0.2 "@types/jsrsasign": 10.5.8 "@types/node": 14.18.54 @@ -7967,6 +8261,7 @@ __metadata: body-parser: 1.20.2 express: 4.18.2 fast-safe-stringify: 2.1.1 + grpc: 1.24.11 internal-ip: 6.2.0 iroha-helpers: 1.5.0 key-encoder: 2.0.3 @@ -8681,6 +8976,27 @@ __metadata: languageName: unknown linkType: soft +"@hyperledger/indy-vdr-nodejs@npm:0.2.0-dev.3": + version: 0.2.0-dev.3 + resolution: "@hyperledger/indy-vdr-nodejs@npm:0.2.0-dev.3" + dependencies: + "@2060.io/ffi-napi": 4.0.8 + "@2060.io/ref-napi": 3.0.6 + "@hyperledger/indy-vdr-shared": 0.2.0-dev.3 + "@mapbox/node-pre-gyp": ^1.0.10 + ref-array-di: ^1.2.2 + ref-struct-di: ^1.1.1 + checksum: c1a0495a9df9e30f85539b3e53c6b3a52f5a17b116ca41a291b4601f564e76cd0c5f214d81f5ee9965d38588287c6c6e026a640d20e9b683754de41c827e0ac6 + languageName: node + linkType: hard + +"@hyperledger/indy-vdr-shared@npm:0.2.0-dev.3": + version: 0.2.0-dev.3 + resolution: "@hyperledger/indy-vdr-shared@npm:0.2.0-dev.3" + checksum: f7e3775109021b14984916b9e36954314fce83683a3c0dd2594903c92937dd930526811fa2e7220118966e33658a643ee890d16a713416cbfd9bdffa3f2444a9 + languageName: node + linkType: hard + "@improbable-eng/grpc-web@npm:^0.12.0": version: 0.12.0 resolution: "@improbable-eng/grpc-web@npm:0.12.0" @@ -9980,6 +10296,25 @@ __metadata: languageName: node linkType: hard +"@mapbox/node-pre-gyp@npm:^1.0.10, @mapbox/node-pre-gyp@npm:^1.0.11, @mapbox/node-pre-gyp@npm:^1.0.4": + version: 1.0.11 + resolution: "@mapbox/node-pre-gyp@npm:1.0.11" + dependencies: + detect-libc: ^2.0.0 + https-proxy-agent: ^5.0.0 + make-dir: ^3.1.0 + node-fetch: ^2.6.7 + nopt: ^5.0.0 + npmlog: ^5.0.1 + rimraf: ^3.0.2 + semver: ^7.3.5 + tar: ^6.1.11 + bin: + node-pre-gyp: bin/node-pre-gyp + checksum: b848f6abc531a11961d780db813cc510ca5a5b6bf3184d72134089c6875a91c44d571ba6c1879470020803f7803609e7b2e6e429651c026fe202facd11d444b8 + languageName: node + linkType: hard + "@metamask/eth-sig-util@npm:^4.0.0": version: 4.0.1 resolution: "@metamask/eth-sig-util@npm:4.0.1" @@ -10182,6 +10517,13 @@ __metadata: languageName: node linkType: hard +"@multiformats/base-x@npm:^4.0.1": + version: 4.0.1 + resolution: "@multiformats/base-x@npm:4.0.1" + checksum: ecbf84bdd7613fd795e4a41f20f3e8cc7df8bbee84690b7feed383d45a638ed228a80ff6f5c930373cbf24539f64857b66023ee3c1e914f6bac9995c76414a87 + languageName: node + linkType: hard + "@multiformats/multiaddr-to-uri@npm:^9.0.1": version: 9.0.7 resolution: "@multiformats/multiaddr-to-uri@npm:9.0.7" @@ -11127,6 +11469,39 @@ __metadata: languageName: node linkType: hard +"@peculiar/asn1-schema@npm:^2.3.6": + version: 2.3.8 + resolution: "@peculiar/asn1-schema@npm:2.3.8" + dependencies: + asn1js: ^3.0.5 + pvtsutils: ^1.3.5 + tslib: ^2.6.2 + checksum: 1f4dd421f1411df8bc52bca12b1cef710434c13ff0a8b5746ede42b10d62b5ad06a3925c4a6db53102aaf1e589947539a6955fa8554a9b8ebb1ffa38b0155a24 + languageName: node + linkType: hard + +"@peculiar/json-schema@npm:^1.1.12": + version: 1.1.12 + resolution: "@peculiar/json-schema@npm:1.1.12" + dependencies: + tslib: ^2.0.0 + checksum: b26ececdc23c5ef25837f8be8d1eb5e1c8bb6e9ae7227ac59ffea57fff56bd05137734e7685e9100595d3d88d906dff638ef8d1df54264c388d3eac1b05aa060 + languageName: node + linkType: hard + +"@peculiar/webcrypto@npm:^1.0.22": + version: 1.4.3 + resolution: "@peculiar/webcrypto@npm:1.4.3" + dependencies: + "@peculiar/asn1-schema": ^2.3.6 + "@peculiar/json-schema": ^1.1.12 + pvtsutils: ^1.3.2 + tslib: ^2.5.0 + webcrypto-core: ^1.7.7 + checksum: 5604c02b7e9a8cef61bb4430e733e939c7737533ba65ba5fac4beb3a6d613add478ab45455cb57506789b6d00704d83e4965a0f712de3e8f40706e0961670e5c + languageName: node + linkType: hard + "@pkgjs/parseargs@npm:^0.11.0": version: 0.11.0 resolution: "@pkgjs/parseargs@npm:0.11.0" @@ -11817,6 +12192,86 @@ __metadata: languageName: node linkType: hard +"@sovpro/delimited-stream@npm:^1.1.0": + version: 1.1.0 + resolution: "@sovpro/delimited-stream@npm:1.1.0" + checksum: e78fc97a8509c07b55483df2253137de07b10f14db15d230526a6dd95c86e99d8f54c7af8697806bd16522eec2c50e44e5b4e0294bed80da833a2185f17f3ab6 + languageName: node + linkType: hard + +"@stablelib/binary@npm:^1.0.1": + version: 1.0.1 + resolution: "@stablelib/binary@npm:1.0.1" + dependencies: + "@stablelib/int": ^1.0.1 + checksum: dca9b98eb1f56a4002b5b9e7351fbc49f3d8616af87007c01e833bd763ac89214eb5f3b7e18673c91ce59d4a0e4856a2eb661ace33d39f17fb1ad267271fccd8 + languageName: node + linkType: hard + +"@stablelib/ed25519@npm:^1.0.2, @stablelib/ed25519@npm:^1.0.3": + version: 1.0.3 + resolution: "@stablelib/ed25519@npm:1.0.3" + dependencies: + "@stablelib/random": ^1.0.2 + "@stablelib/sha512": ^1.0.1 + "@stablelib/wipe": ^1.0.1 + checksum: e18279de078edac67396ba07dbb862dce0fe89efa8141c21a5b04108a29914bd51636019522323ca5097ec596a90b3028ed64e88ee009b0ac7de7c1ab6499ccb + languageName: node + linkType: hard + +"@stablelib/hash@npm:^1.0.1": + version: 1.0.1 + resolution: "@stablelib/hash@npm:1.0.1" + checksum: 3ff1f12d1a4082aaf4b6cdf40c2010aabe5c4209d3b40b97b5bbb0d9abc0ee94abdc545e57de0614afaea807ca0212ac870e247ec8f66cdce91ec39ce82948cf + languageName: node + linkType: hard + +"@stablelib/int@npm:^1.0.1": + version: 1.0.1 + resolution: "@stablelib/int@npm:1.0.1" + checksum: 65bfbf50a382eea70c68e05366bf379cfceff8fbc076f1c267ef2f2411d7aed64fd140c415cb6c29f19a3910d3b8b7805d4b32ad5721a5007a8e744a808c7ae3 + languageName: node + linkType: hard + +"@stablelib/random@npm:^1.0.1, @stablelib/random@npm:^1.0.2": + version: 1.0.2 + resolution: "@stablelib/random@npm:1.0.2" + dependencies: + "@stablelib/binary": ^1.0.1 + "@stablelib/wipe": ^1.0.1 + checksum: f5ace0a588dc4c21f01cb85837892d4c872e994ae77a58a8eb7dd61aa0b26fb1e9b46b0445e71af57d963ef7d9f5965c64258fc0d04df7b2947bc48f2d3560c5 + languageName: node + linkType: hard + +"@stablelib/sha256@npm:^1.0.1": + version: 1.0.1 + resolution: "@stablelib/sha256@npm:1.0.1" + dependencies: + "@stablelib/binary": ^1.0.1 + "@stablelib/hash": ^1.0.1 + "@stablelib/wipe": ^1.0.1 + checksum: 38669871e1bda72eb537629ebceac1c72da8890273a9fbe088f81f6d14c1ec04e78be8c5b455380a06c67f8e62b2508e11e9063fcc257dbaa1b5c27ac756ba77 + languageName: node + linkType: hard + +"@stablelib/sha512@npm:^1.0.1": + version: 1.0.1 + resolution: "@stablelib/sha512@npm:1.0.1" + dependencies: + "@stablelib/binary": ^1.0.1 + "@stablelib/hash": ^1.0.1 + "@stablelib/wipe": ^1.0.1 + checksum: b7c82f7608a35948a2147a534c0c9afc80deab3fd5f72a2e27b2454e7c0c6944d39381be3abcb1b7fac5b824ba030ae3e98209d517a579c143d8ed63930b042f + languageName: node + linkType: hard + +"@stablelib/wipe@npm:^1.0.1": + version: 1.0.1 + resolution: "@stablelib/wipe@npm:1.0.1" + checksum: 287802eb146810a46ba72af70b82022caf83a8aeebde23605f5ee0decf64fe2b97a60c856e43b6617b5801287c30cfa863cfb0469e7fcde6f02d143cf0c6cbf4 + languageName: node + linkType: hard + "@stencil/core@npm:^2.18.0": version: 2.22.3 resolution: "@stencil/core@npm:2.22.3" @@ -12625,6 +13080,16 @@ __metadata: languageName: node linkType: hard +"@types/bytebuffer@npm:^5.0.40": + version: 5.0.46 + resolution: "@types/bytebuffer@npm:5.0.46" + dependencies: + "@types/long": ^3.0.0 + "@types/node": "*" + checksum: 43dc8df469141b65e3ac1f864f079ca046041794917b69a4a962014502daf140732276ffa241d849678ca867e8751332037c7857d2a5b81fe919f20f139fc573 + languageName: node + linkType: hard + "@types/cacheable-request@npm:^6.0.2": version: 6.0.3 resolution: "@types/cacheable-request@npm:6.0.3" @@ -13005,7 +13470,7 @@ __metadata: languageName: node linkType: hard -"@types/express@npm:4.17.20": +"@types/express@npm:4.17.20, @types/express@npm:^4.17.15": version: 4.17.20 resolution: "@types/express@npm:4.17.20" dependencies: @@ -13120,12 +13585,22 @@ __metadata: languageName: node linkType: hard -"@types/indy-sdk@npm:1.16.29": - version: 1.16.29 - resolution: "@types/indy-sdk@npm:1.16.29" +"@types/indy-sdk@npm:1.16.27": + version: 1.16.27 + resolution: "@types/indy-sdk@npm:1.16.27" dependencies: buffer: ^6.0.0 - checksum: d934c7e8bf28e65212aeee98e2398f9bbdc2a537069e722f73dca73af439ce7f54a8dc5c532441cf2860b2e603fe54d83a7e157e9ca14bfca34a1bd64e6908f9 + checksum: 26bc7936aba7a8b272123880cfbbc00d9f9701bc0a8932e96d5e5282816b316429ad3b88d449e4c259f92569b64488a9bd3aee18c660e6f85006f941c91c683f + languageName: node + linkType: hard + +"@types/inquirer@npm:8.2.6": + version: 8.2.6 + resolution: "@types/inquirer@npm:8.2.6" + dependencies: + "@types/through": "*" + rxjs: ^7.2.0 + checksum: d09c3b6bbfb1aff8bdb8fc938d43536be55dfb51af0c91d0105e3f7c5e3950c12618ac00e2e91f10b5abeba38f4b903289be1df5aa31f213b58c3cc675a19f81 languageName: node linkType: hard @@ -13332,6 +13807,13 @@ __metadata: languageName: node linkType: hard +"@types/long@npm:^3.0.0": + version: 3.0.32 + resolution: "@types/long@npm:3.0.32" + checksum: 7c64c64b4a8bf38d9a6690f725ed5e92383905b22c1320493749729c4f476a74fa2507cc9364268ecdfdba1cf11573a46648157f3e34cb0c39f51b05d13c37eb + languageName: node + linkType: hard + "@types/long@npm:^4.0.0, @types/long@npm:^4.0.1": version: 4.0.1 resolution: "@types/long@npm:4.0.1" @@ -13399,6 +13881,16 @@ __metadata: languageName: node linkType: hard +"@types/node-fetch@npm:2.6.2": + version: 2.6.2 + resolution: "@types/node-fetch@npm:2.6.2" + dependencies: + "@types/node": "*" + form-data: ^3.0.0 + checksum: 6f73b1470000d303d25a6fb92875ea837a216656cb7474f66cdd67bb014aa81a5a11e7ac9c21fe19bee9ecb2ef87c1962bceeaec31386119d1ac86e4c30ad7a6 + languageName: node + linkType: hard + "@types/node-fetch@npm:2.6.4": version: 2.6.4 resolution: "@types/node-fetch@npm:2.6.4" @@ -14008,6 +14500,13 @@ __metadata: languageName: node linkType: hard +"@types/validator@npm:^13.7.10": + version: 13.11.5 + resolution: "@types/validator@npm:13.11.5" + checksum: 30b48b4171e0e812e1d5c47dba3a218e1adc30ad024e58e6911d8ed1e381e5db689154c09318c561b8c3b7ca047c1da2b0ac602bf802fd27c9b3773fa2f98099 + languageName: node + linkType: hard + "@types/ws@npm:8.5.3, @types/ws@npm:^8.2.2": version: 8.5.3 resolution: "@types/ws@npm:8.5.3" @@ -14017,6 +14516,15 @@ __metadata: languageName: node linkType: hard +"@types/ws@npm:^8.5.4": + version: 8.5.8 + resolution: "@types/ws@npm:8.5.8" + dependencies: + "@types/node": "*" + checksum: 4ad30de842834d4dd8e6e1476470752709d4165352a3a36780f23f4fdb686d4ac8ca5e16a0e0622940ddace910b856ff8a0baa2e24e41d204fb7a6a02ab2172b + languageName: node + linkType: hard + "@types/ws@npm:^8.5.5": version: 8.5.5 resolution: "@types/ws@npm:8.5.5" @@ -14542,6 +15050,25 @@ __metadata: languageName: node linkType: hard +"@unimodules/core@npm:*": + version: 7.2.0 + resolution: "@unimodules/core@npm:7.2.0" + dependencies: + expo-modules-core: ~0.4.0 + checksum: 789b30c8bdab258fbac8cae36b91c8c6d7a10379681499858eee41db9444c405ef0512dbe7674c8ba082e87e455438af3cf4c4ee48b7cd2b10cd1b0696a10b99 + languageName: node + linkType: hard + +"@unimodules/react-native-adapter@npm:*": + version: 6.5.0 + resolution: "@unimodules/react-native-adapter@npm:6.5.0" + dependencies: + expo-modules-autolinking: ^0.3.2 + expo-modules-core: ~0.4.0 + checksum: bc47cb9b644ee3283a925df59018be2a6b410b8edf22072e5482830762b3806643148732ddc51b38001a5e4aa5da4bf0f5e1e289e09606d2ac9e36249d6d47cd + languageName: node + linkType: hard + "@vitejs/plugin-basic-ssl@npm:1.0.1": version: 1.0.1 resolution: "@vitejs/plugin-basic-ssl@npm:1.0.1" @@ -15955,6 +16482,16 @@ __metadata: languageName: node linkType: hard +"array-index@npm:^1.0.0": + version: 1.0.0 + resolution: "array-index@npm:1.0.0" + dependencies: + debug: ^2.2.0 + es6-symbol: ^3.0.2 + checksum: ea43314f55f7026169acb78884f464bd650f525c1bf54c8a73dd021571b233677ce7028ea4b606269f3e6033a2e26a9560a5fd5582d4fb349592f0364aaf76de + languageName: node + linkType: hard + "array-timsort@npm:^1.0.3": version: 1.0.3 resolution: "array-timsort@npm:1.0.3" @@ -16132,6 +16669,13 @@ __metadata: languageName: node linkType: hard +"asmcrypto.js@npm:^0.22.0": + version: 0.22.0 + resolution: "asmcrypto.js@npm:0.22.0" + checksum: 1fa4fba514443d25a787ee75935ff9a523628956f698987e16fe81519a71d42d3c484a660bb7d3271904f6c211c097cb551408de7d13294a334e9b6c3f00b78a + languageName: node + linkType: hard + "asn1.js@npm:^5.0.1, asn1.js@npm:^5.2.0": version: 5.4.1 resolution: "asn1.js@npm:5.4.1" @@ -16153,6 +16697,17 @@ __metadata: languageName: node linkType: hard +"asn1js@npm:^3.0.1, asn1js@npm:^3.0.5": + version: 3.0.5 + resolution: "asn1js@npm:3.0.5" + dependencies: + pvtsutils: ^1.3.2 + pvutils: ^1.1.3 + tslib: ^2.4.0 + checksum: 3b6af1bbadd5762ef8ead5daf2f6bda1bc9e23bc825c4dcc996aa1f9521ad7390a64028565d95d98090d69c8431f004c71cccb866004759169d7c203cf9075eb + languageName: node + linkType: hard + "assert-plus@npm:1.0.0, assert-plus@npm:^1.0.0": version: 1.0.0 resolution: "assert-plus@npm:1.0.0" @@ -16468,6 +17023,24 @@ __metadata: languageName: node linkType: hard +"b64-lite@npm:^1.3.1, b64-lite@npm:^1.4.0": + version: 1.4.0 + resolution: "b64-lite@npm:1.4.0" + dependencies: + base-64: ^0.1.0 + checksum: 75ff8556c265b603223d083c57358a9734261d398637f0f6345bb2e4b63d7fcd815bcc5aa72d8d414ca790e5a4c95f96c04d5acb393f8bd245d3d451ef94e8db + languageName: node + linkType: hard + +"b64u-lite@npm:^1.0.1": + version: 1.1.0 + resolution: "b64u-lite@npm:1.1.0" + dependencies: + b64-lite: ^1.4.0 + checksum: e427b153c29794d97acdaeafc3d4ddd2df207c9f244c8c9c00bde6f2eb910c8286a3e5a1eae092615d78da2e7fdb6dc3c8ec2714e0a25f4992ee8ed6353325e8 + languageName: node + linkType: hard + "babel-code-frame@npm:^6.16.0, babel-code-frame@npm:^6.22.0": version: 6.26.0 resolution: "babel-code-frame@npm:6.26.0" @@ -17040,6 +17613,13 @@ __metadata: languageName: node linkType: hard +"base-64@npm:^0.1.0": + version: 0.1.0 + resolution: "base-64@npm:0.1.0" + checksum: 5a42938f82372ab5392cbacc85a5a78115cbbd9dbef9f7540fa47d78763a3a8bd7d598475f0d92341f66285afd377509851a9bb5c67bbecb89686e9255d5b3eb + languageName: node + linkType: hard + "base-x@npm:^3.0.2, base-x@npm:^3.0.8": version: 3.0.9 resolution: "base-x@npm:3.0.9" @@ -17049,6 +17629,13 @@ __metadata: languageName: node linkType: hard +"base64-js@npm:*, base64-js@npm:^1.0.2, base64-js@npm:^1.2.0, base64-js@npm:^1.3.0, base64-js@npm:^1.3.1": + version: 1.5.1 + resolution: "base64-js@npm:1.5.1" + checksum: 669632eb3745404c2f822a18fc3a0122d2f9a7a13f7fb8b5823ee19d1d2ff9ee5b52c53367176ea4ad093c332fd5ab4bd0ebae5a8e27917a4105a4cfc86b1005 + languageName: node + linkType: hard + "base64-js@npm:1.3.1": version: 1.3.1 resolution: "base64-js@npm:1.3.1" @@ -17056,13 +17643,6 @@ __metadata: languageName: node linkType: hard -"base64-js@npm:^1.0.2, base64-js@npm:^1.2.0, base64-js@npm:^1.3.0, base64-js@npm:^1.3.1": - version: 1.5.1 - resolution: "base64-js@npm:1.5.1" - checksum: 669632eb3745404c2f822a18fc3a0122d2f9a7a13f7fb8b5823ee19d1d2ff9ee5b52c53367176ea4ad093c332fd5ab4bd0ebae5a8e27917a4105a4cfc86b1005 - languageName: node - linkType: hard - "base64id@npm:2.0.0, base64id@npm:~2.0.0": version: 2.0.0 resolution: "base64id@npm:2.0.0" @@ -17157,7 +17737,7 @@ __metadata: languageName: node linkType: hard -"big-integer@npm:^1.6.44": +"big-integer@npm:^1.6.44, big-integer@npm:^1.6.51": version: 1.6.51 resolution: "big-integer@npm:1.6.51" checksum: 3d444173d1b2e20747e2c175568bedeebd8315b0637ea95d75fd27830d3b8e8ba36c6af40374f36bdaea7b5de376dcada1b07587cb2a79a928fccdb6e6e3c518 @@ -17459,6 +18039,26 @@ __metadata: languageName: node linkType: hard +"borc@npm:^3.0.0": + version: 3.0.0 + resolution: "borc@npm:3.0.0" + dependencies: + bignumber.js: ^9.0.0 + buffer: ^6.0.3 + commander: ^2.15.0 + ieee754: ^1.1.13 + iso-url: ^1.1.5 + json-text-sequence: ~0.3.0 + readable-stream: ^3.6.0 + bin: + cbor2comment: bin/cbor2comment.js + cbor2diag: bin/cbor2diag.js + cbor2json: bin/cbor2json.js + json2cbor: bin/json2cbor.js + checksum: 23e39557ed952a2e6e984cfc6277e714a3077c96202604a1a404149b656766ba1d3351d4a585b0f27126964fcd14aa95ff7acee83bfe947b863bd306b84876c2 + languageName: node + linkType: hard + "boxen@npm:^5.0.0": version: 5.1.2 resolution: "boxen@npm:5.1.2" @@ -18436,6 +19036,13 @@ __metadata: languageName: node linkType: hard +"canonicalize@npm:^1.0.1": + version: 1.0.8 + resolution: "canonicalize@npm:1.0.8" + checksum: c31ea64160171bbcd7ac0dc081058fbcff055410a1d532d7b3959e7b02a3001c5d5f4f8bad934ed5246eafc9a928d333cc0c29846c16fb6d0be97b8fb444de3c + languageName: node + linkType: hard + "cardinal@npm:^2.1.1": version: 2.1.1 resolution: "cardinal@npm:2.1.1" @@ -18826,6 +19433,13 @@ __metadata: languageName: node linkType: hard +"class-transformer@npm:0.5.1, class-transformer@npm:^0.5.1": + version: 0.5.1 + resolution: "class-transformer@npm:0.5.1" + checksum: f191c8b4cc4239990f5efdd790cabdd852c243ed66248e39f6616a349c910c6eed2d9fd1fbf7ee6ea89f69b4f1d0b493b27347fe0cd0ae26b47c3745a805b6d3 + languageName: node + linkType: hard + "class-utils@npm:^0.3.5": version: 0.3.6 resolution: "class-utils@npm:0.3.6" @@ -18838,6 +19452,17 @@ __metadata: languageName: node linkType: hard +"class-validator@npm:0.14.0": + version: 0.14.0 + resolution: "class-validator@npm:0.14.0" + dependencies: + "@types/validator": ^13.7.10 + libphonenumber-js: ^1.10.14 + validator: ^13.7.0 + checksum: f62e4a0ad24cee68f4b2bc70d32b96de90cb598f96bde362b4dbf4234151af8eb6ae225458312a38fc49fa3959844cf61c60e731a8205e9a570454cff8de2710 + languageName: node + linkType: hard + "classic-level@npm:^1.2.0": version: 1.3.0 resolution: "classic-level@npm:1.3.0" @@ -19087,6 +19712,13 @@ __metadata: languageName: node linkType: hard +"clone@npm:2.x": + version: 2.1.2 + resolution: "clone@npm:2.1.2" + checksum: aaf106e9bc025b21333e2f4c12da539b568db4925c0501a1bf4070836c9e848c892fa22c35548ce0d1132b08bbbfa17a00144fe58fccdab6fa900fec4250f67d + languageName: node + linkType: hard + "clone@npm:^1.0.2": version: 1.0.4 resolution: "clone@npm:1.0.4" @@ -19340,7 +19972,7 @@ __metadata: languageName: node linkType: hard -"commander@npm:^2.12.1, commander@npm:^2.13.0, commander@npm:^2.19.0, commander@npm:^2.20.0, commander@npm:^2.20.3, commander@npm:^2.8.1, commander@npm:^2.9.0": +"commander@npm:^2.12.1, commander@npm:^2.13.0, commander@npm:^2.15.0, commander@npm:^2.19.0, commander@npm:^2.20.0, commander@npm:^2.20.3, commander@npm:^2.8.1, commander@npm:^2.9.0": version: 2.20.3 resolution: "commander@npm:2.20.3" checksum: ab8c07884e42c3a8dbc5dd9592c606176c7eb5c1ca5ff274bcf907039b2c41de3626f684ea75ccf4d361ba004bbaff1f577d5384c155f3871e456bdf27becf9e @@ -19433,7 +20065,7 @@ __metadata: languageName: node linkType: hard -"compare-versions@npm:3.6.0": +"compare-versions@npm:3.6.0, compare-versions@npm:^3.4.0": version: 3.6.0 resolution: "compare-versions@npm:3.6.0" checksum: 7492a50cdaa2c27f5254eee7c4b38856e1c164991bab3d98d7fd067fe4b570d47123ecb92523b78338be86aa221668fd3868bfe8caa5587dc3ebbe1a03d52b5d @@ -20233,6 +20865,13 @@ __metadata: languageName: node linkType: hard +"credentials-context@npm:^2.0.0": + version: 2.0.0 + resolution: "credentials-context@npm:2.0.0" + checksum: c5ba6d257ef2fb1c21399238f5b1e0b2f7622b1f496f499edbac2d2e0faba40ebc06e0c5acee4bb2fbe712abfa3cbebdcc152f4bcf5a7481430f2731f2c514db + languageName: node + linkType: hard + "critters@npm:0.0.20": version: 0.0.20 resolution: "critters@npm:0.0.20" @@ -20898,6 +21537,13 @@ __metadata: languageName: node linkType: hard +"data-uri-to-buffer@npm:^3.0.1": + version: 3.0.1 + resolution: "data-uri-to-buffer@npm:3.0.1" + checksum: c59c3009686a78c071806b72f4810856ec28222f0f4e252aa495ec027ed9732298ceea99c50328cf59b151dd34cbc3ad6150bbb43e41fc56fa19f48c99e9fc30 + languageName: node + linkType: hard + "data-uri-to-buffer@npm:^4.0.0": version: 4.0.1 resolution: "data-uri-to-buffer@npm:4.0.1" @@ -21056,7 +21702,7 @@ __metadata: languageName: node linkType: hard -"decode-uri-component@npm:^0.2.0": +"decode-uri-component@npm:^0.2.0, decode-uri-component@npm:^0.2.2": version: 0.2.2 resolution: "decode-uri-component@npm:0.2.2" checksum: 95476a7d28f267292ce745eac3524a9079058bbb35767b76e3ee87d42e34cd0275d2eb19d9d08c3e167f97556e8a2872747f5e65cbebcac8b0c98d83e285f139 @@ -21694,6 +22340,13 @@ __metadata: languageName: node linkType: hard +"did-resolver@npm:^4.0.0, did-resolver@npm:^4.1.0": + version: 4.1.0 + resolution: "did-resolver@npm:4.1.0" + checksum: 0b0f6c3502f877c2a3cb264befc2718b12efa8e7d39ef255b00cd79f8fe12303257ac8e84a030a49599415bce87192fef29388d9f695776d331d0139848d3d4c + languageName: node + linkType: hard + "didyoumean@npm:^1.2.2": version: 1.2.2 resolution: "didyoumean@npm:1.2.2" @@ -22865,7 +23518,7 @@ __metadata: languageName: node linkType: hard -"es6-symbol@npm:^3.1.1, es6-symbol@npm:^3.1.3, es6-symbol@npm:~3.1.1, es6-symbol@npm:~3.1.3": +"es6-symbol@npm:^3.0.2, es6-symbol@npm:^3.1.1, es6-symbol@npm:^3.1.3, es6-symbol@npm:~3.1.1, es6-symbol@npm:~3.1.3": version: 3.1.3 resolution: "es6-symbol@npm:3.1.3" dependencies: @@ -24852,6 +25505,42 @@ __metadata: languageName: node linkType: hard +"expo-modules-autolinking@npm:^0.3.2": + version: 0.3.4 + resolution: "expo-modules-autolinking@npm:0.3.4" + dependencies: + chalk: ^4.1.0 + commander: ^7.2.0 + fast-glob: ^3.2.5 + find-up: ~5.0.0 + fs-extra: ^9.1.0 + bin: + expo-modules-autolinking: bin/expo-modules-autolinking.js + checksum: e408aac6808ce3c8725da7ecef6bbf33b2fc0a3e7e8ae0b33dd1cb00c36d2b8e7678184f1d0215acb189a8e400a64f79920c57958f426143b8fd190c5891c904 + languageName: node + linkType: hard + +"expo-modules-core@npm:~0.4.0": + version: 0.4.10 + resolution: "expo-modules-core@npm:0.4.10" + dependencies: + compare-versions: ^3.4.0 + invariant: ^2.2.4 + checksum: 92bd05c15a6f1c65dbb89e993f6672e40e3d8f34702faf238a71eea15ca816d4aeb6216ff2eafb5151e7d14e1e373a823b90e085f421304751566f5e776855d8 + languageName: node + linkType: hard + +"expo-random@npm:*": + version: 13.5.0 + resolution: "expo-random@npm:13.5.0" + dependencies: + base64-js: ^1.3.0 + peerDependencies: + expo: "*" + checksum: 656a24170e0325d76836a961b444151ffb8225ecc66327f52eaf3a5a65d12616a767368be9c5e56dc2d74ed8dbc8d8c27810cf085c679961884e657d2c812700 + languageName: node + linkType: hard + "exponential-backoff@npm:^3.1.1": version: 3.1.1 resolution: "exponential-backoff@npm:3.1.1" @@ -25298,7 +25987,7 @@ __metadata: languageName: node linkType: hard -"fast-glob@npm:3.3.1, fast-glob@npm:^3.2.12, fast-glob@npm:^3.3.0": +"fast-glob@npm:3.3.1, fast-glob@npm:^3.2.12, fast-glob@npm:^3.2.5, fast-glob@npm:^3.3.0": version: 3.3.1 resolution: "fast-glob@npm:3.3.1" dependencies: @@ -25366,6 +26055,13 @@ __metadata: languageName: node linkType: hard +"fast-text-encoding@npm:^1.0.3": + version: 1.0.6 + resolution: "fast-text-encoding@npm:1.0.6" + checksum: 9d58f694314b3283e785bf61954902536da228607ad246905e30256f9ab8331f780ac987e7222c9f5eafd04168d07e12b8054c85cedb76a2c05af0e82387a903 + languageName: node + linkType: hard + "fastest-levenshtein@npm:^1.0.12": version: 1.0.12 resolution: "fastest-levenshtein@npm:1.0.12" @@ -25416,6 +26112,16 @@ __metadata: languageName: node linkType: hard +"fetch-blob@npm:^2.1.1": + version: 2.1.2 + resolution: "fetch-blob@npm:2.1.2" + peerDependenciesMeta: + domexception: + optional: true + checksum: 22d4487ce78ea4e52b432b0057d8d42922d5d93c0374b0bc2692cebdcb11bf8fac4f6d141b31f1633db1e9212effd38385adbd765a2c7412a621307058499214 + languageName: node + linkType: hard + "fetch-blob@npm:^3.1.2, fetch-blob@npm:^3.1.4": version: 3.2.0 resolution: "fetch-blob@npm:3.2.0" @@ -25692,7 +26398,7 @@ __metadata: languageName: node linkType: hard -"find-up@npm:5.0.0, find-up@npm:^5.0.0": +"find-up@npm:5.0.0, find-up@npm:^5.0.0, find-up@npm:~5.0.0": version: 5.0.0 resolution: "find-up@npm:5.0.0" dependencies: @@ -26712,6 +27418,22 @@ __metadata: languageName: node linkType: hard +"get-symbol-from-current-process-h@npm:^1.0.1, get-symbol-from-current-process-h@npm:^1.0.2": + version: 1.0.2 + resolution: "get-symbol-from-current-process-h@npm:1.0.2" + checksum: d47cc1b9e0be27469e2af0555b21aaa5ebd114e8aa25bb0e2616c8abaebb7933e7b5bedcc31c6cad06e4df232e0fe280118001fec78da488f5f630b65cc1cae5 + languageName: node + linkType: hard + +"get-uv-event-loop-napi-h@npm:^1.0.5": + version: 1.0.6 + resolution: "get-uv-event-loop-napi-h@npm:1.0.6" + dependencies: + get-symbol-from-current-process-h: ^1.0.1 + checksum: 3a2a9f9fc18196113d94496c79d5208c7e750cee6f65625fa34df195cab6bf9f122981c923e10cadd81d7f8da1ff92fe4020a7414d3ec16c820dee18e45bb29c + languageName: node + linkType: hard + "get-value@npm:^2.0.3, get-value@npm:^2.0.6": version: 2.0.6 resolution: "get-value@npm:2.0.6" @@ -27461,6 +28183,20 @@ __metadata: languageName: node linkType: hard +"grpc@npm:1.24.11": + version: 1.24.11 + resolution: "grpc@npm:1.24.11" + dependencies: + "@mapbox/node-pre-gyp": ^1.0.4 + "@types/bytebuffer": ^5.0.40 + lodash.camelcase: ^4.3.0 + lodash.clone: ^4.5.0 + nan: ^2.13.2 + protobufjs: ^5.0.3 + checksum: a437525786329ff541d7bbb54e472f52001a4d9b1c2fd896468241e2f070bf558b380b3d19d2b87f401602bd5a319b171e119598f4035958a9519851e91110db + languageName: node + linkType: hard + "grpc_tools_node_protoc_ts@npm:5.3.3": version: 5.3.3 resolution: "grpc_tools_node_protoc_ts@npm:5.3.3" @@ -28973,7 +29709,7 @@ __metadata: languageName: node linkType: hard -"invariant@npm:^2.2.0": +"invariant@npm:^2.2.0, invariant@npm:^2.2.4": version: 2.2.4 resolution: "invariant@npm:2.2.4" dependencies: @@ -30220,6 +30956,34 @@ __metadata: languageName: node linkType: hard +"isomorphic-webcrypto@npm:^2.3.8": + version: 2.3.8 + resolution: "isomorphic-webcrypto@npm:2.3.8" + dependencies: + "@peculiar/webcrypto": ^1.0.22 + "@unimodules/core": "*" + "@unimodules/react-native-adapter": "*" + asmcrypto.js: ^0.22.0 + b64-lite: ^1.3.1 + b64u-lite: ^1.0.1 + expo-random: "*" + msrcrypto: ^1.5.6 + react-native-securerandom: ^0.1.1 + str2buf: ^1.3.0 + webcrypto-shim: ^0.1.4 + dependenciesMeta: + "@unimodules/core": + optional: true + "@unimodules/react-native-adapter": + optional: true + expo-random: + optional: true + react-native-securerandom: + optional: true + checksum: 0f1c4accaca753aae870194e36652b50080b0c0c6a465cbd90ec5a6a6a77919fd835d22a6de1bef737b3de48b04fdf5ddd04c8d5e6d6358492497d05751fdce8 + languageName: node + linkType: hard + "isomorphic-ws@npm:4.0.1, isomorphic-ws@npm:^4.0.1": version: 4.0.1 resolution: "isomorphic-ws@npm:4.0.1" @@ -31984,6 +32748,15 @@ __metadata: languageName: node linkType: hard +"json-text-sequence@npm:~0.3.0": + version: 0.3.0 + resolution: "json-text-sequence@npm:0.3.0" + dependencies: + "@sovpro/delimited-stream": ^1.1.0 + checksum: e5dc050aadd626938514363399cf14c409f878628914922c5d470530c3f3473d6b0e16a10338dd7d863aab0291bb0e5e15d71526d14733c22e30cba771b03297 + languageName: node + linkType: hard + "json5@npm:2.2.3, json5@npm:^2.2.0, json5@npm:^2.2.2, json5@npm:^2.2.3": version: 2.2.3 resolution: "json5@npm:2.2.3" @@ -32629,6 +33402,29 @@ __metadata: languageName: node linkType: hard +"ky-universal@npm:^0.8.2": + version: 0.8.2 + resolution: "ky-universal@npm:0.8.2" + dependencies: + abort-controller: ^3.0.0 + node-fetch: 3.0.0-beta.9 + peerDependencies: + ky: ">=0.17.0" + web-streams-polyfill: ">=2.0.0" + peerDependenciesMeta: + web-streams-polyfill: + optional: true + checksum: 87ed38c5c5a5b4448502fd5a64b68f30db69d366e148e5321cd9c0cb57d616519578ff0ae50146ff92ad037ef5cd77fbc40d893675459eead0d3f13101374570 + languageName: node + linkType: hard + +"ky@npm:^0.25.1": + version: 0.25.1 + resolution: "ky@npm:0.25.1" + checksum: ae1b7bebb48001d00d53e386e077939eeef7398a36b4fb45660f988ddb17d583d077290f2adb9706b4761f9d3b74918eb8d9f45ce799760143e104e1053b33ef + languageName: node + linkType: hard + "language-subtag-registry@npm:~0.3.2": version: 0.3.22 resolution: "language-subtag-registry@npm:0.3.22" @@ -33157,6 +33953,13 @@ __metadata: languageName: node linkType: hard +"libphonenumber-js@npm:^1.10.14": + version: 1.10.49 + resolution: "libphonenumber-js@npm:1.10.49" + checksum: 596b4ed05fbf8c99f384cda802e6afb111accdaf96f9baf2a3ac32c885602583f3e9cba4c4475c3922e9c4f79c63bcdf7e592666b7e14b258cad26f34f51c2e0 + languageName: node + linkType: hard + "libtap@npm:^1.4.0": version: 1.4.1 resolution: "libtap@npm:1.4.1" @@ -33413,6 +34216,13 @@ __metadata: languageName: node linkType: hard +"lodash.clone@npm:^4.5.0": + version: 4.5.0 + resolution: "lodash.clone@npm:4.5.0" + checksum: 5839f22acf3a43c026ac4325f7bcd378f34967415cd0b9fd7efa9bbbf38dc665900d36e040944c5afab94a51ff8a24f6cfc3781fe439705cbad5c722e9506b16 + languageName: node + linkType: hard + "lodash.clonedeep@npm:^4.5.0": version: 4.5.0 resolution: "lodash.clonedeep@npm:4.5.0" @@ -33786,7 +34596,7 @@ __metadata: languageName: node linkType: hard -"loglevel@npm:^1.4.1, loglevel@npm:^1.6.8": +"loglevel@npm:1.8.1, loglevel@npm:^1.4.1, loglevel@npm:^1.6.8": version: 1.8.1 resolution: "loglevel@npm:1.8.1" checksum: a1a62db40291aaeaef2f612334c49e531bff71cc1d01a2acab689ab80d59e092f852ab164a5aedc1a752fdc46b7b162cb097d8a9eb2cf0b299511106c29af61d @@ -33945,6 +34755,13 @@ __metadata: languageName: node linkType: hard +"lru_map@npm:^0.4.1": + version: 0.4.1 + resolution: "lru_map@npm:0.4.1" + checksum: a3eb277ca7e673c7d6e78578193cc7c67a7410978c260f9b49418aa2053c7cb025d98326d3e74817119cb4ef5f114e2e05da58b7badfbde4a7b4d566c5f294e5 + languageName: node + linkType: hard + "ltgt@npm:2.2.1, ltgt@npm:^2.1.2, ltgt@npm:~2.2.0": version: 2.2.1 resolution: "ltgt@npm:2.2.1" @@ -33959,6 +34776,13 @@ __metadata: languageName: node linkType: hard +"luxon@npm:^3.3.0": + version: 3.4.3 + resolution: "luxon@npm:3.4.3" + checksum: 3eade81506224d038ed24035a0cd0dd4887848d7eba9361dce9ad8ef81380596a68153240be3988721f9690c624fb449fcf8fd8c3fc0681a6a8496faf48e92a3 + languageName: node + linkType: hard + "magic-string@npm:0.30.1": version: 0.30.1 resolution: "magic-string@npm:0.30.1" @@ -34035,7 +34859,7 @@ __metadata: languageName: node linkType: hard -"make-error@npm:1.x, make-error@npm:^1.1.1": +"make-error@npm:1.x, make-error@npm:^1.1.1, make-error@npm:^1.3.6": version: 1.3.6 resolution: "make-error@npm:1.3.6" checksum: b86e5e0e25f7f777b77fabd8e2cbf15737972869d852a22b7e73c17623928fccb826d8e46b9951501d3f20e51ad74ba8c59ed584f610526a48f8ccf88aaec402 @@ -35189,6 +36013,13 @@ __metadata: languageName: node linkType: hard +"msrcrypto@npm:^1.5.6": + version: 1.5.8 + resolution: "msrcrypto@npm:1.5.8" + checksum: efb41bf91e18258bb25dd7b56dcad201fe8c7ad210644dc3da4c41889360a4ee7f75753f7d3606d0b7920064bcc476e643a9bb779e1b3052374c3b3289e15719 + languageName: node + linkType: hard + "multer@npm:1.4.5-lts.1, multer@npm:^1.4.5-lts.1": version: 1.4.5-lts.1 resolution: "multer@npm:1.4.5-lts.1" @@ -35370,7 +36201,7 @@ __metadata: languageName: node linkType: hard -"nan@npm:^2.11.1": +"nan@npm:^2.11.1, nan@npm:^2.13.2": version: 2.18.0 resolution: "nan@npm:2.18.0" dependencies: @@ -35743,6 +36574,15 @@ __metadata: languageName: node linkType: hard +"node-cache@npm:^5.1.2": + version: 5.1.2 + resolution: "node-cache@npm:5.1.2" + dependencies: + clone: 2.x + checksum: b0bdd81a6fee4754fb984a05246b510bb35dc54721116d465899bf4229ee3287fdafb47da526900ee9924fb402ed5c7d8050049d37d8bf2d26dbafc23a2c3205 + languageName: node + linkType: hard + "node-domexception@npm:^1.0.0": version: 1.0.0 resolution: "node-domexception@npm:1.0.0" @@ -35764,6 +36604,16 @@ __metadata: languageName: node linkType: hard +"node-fetch@npm:3.0.0-beta.9": + version: 3.0.0-beta.9 + resolution: "node-fetch@npm:3.0.0-beta.9" + dependencies: + data-uri-to-buffer: ^3.0.1 + fetch-blob: ^2.1.1 + checksum: 586af0910649cb62f1c044ddac41e71c0b0f48133fba406ad5e0fab51baff18f22cd187ea65ef690ceed7386a71910e904348105dc8eae55f907fa94df7e76ca + languageName: node + linkType: hard + "node-fetch@npm:3.3.2, node-fetch@npm:^3.3.2": version: 3.3.2 resolution: "node-fetch@npm:3.3.2" @@ -35843,6 +36693,17 @@ __metadata: languageName: node linkType: hard +"node-gyp-build@npm:^4.2.1": + version: 4.6.1 + resolution: "node-gyp-build@npm:4.6.1" + bin: + node-gyp-build: bin.js + node-gyp-build-optional: optional.js + node-gyp-build-test: build-test.js + checksum: c3676d337b36803bc7792e35bf7fdcda7cdcb7e289b8f9855a5535702a82498eb976842fefcf487258c58005ca32ce3d537fbed91280b04409161dcd7232a882 + languageName: node + linkType: hard + "node-gyp-build@npm:~4.1.0": version: 4.1.1 resolution: "node-gyp-build@npm:4.1.1" @@ -36654,6 +37515,13 @@ __metadata: languageName: node linkType: hard +"object-inspect@npm:^1.10.3": + version: 1.13.1 + resolution: "object-inspect@npm:1.13.1" + checksum: 7d9fa9221de3311dcb5c7c307ee5dc011cdd31dc43624b7c184b3840514e118e05ef0002be5388304c416c0eb592feb46e983db12577fc47e47d5752fbbfb61f + languageName: node + linkType: hard + "object-inspect@npm:^1.11.0": version: 1.12.0 resolution: "object-inspect@npm:1.12.0" @@ -40208,6 +41076,22 @@ __metadata: languageName: node linkType: hard +"pvtsutils@npm:^1.3.2, pvtsutils@npm:^1.3.5": + version: 1.3.5 + resolution: "pvtsutils@npm:1.3.5" + dependencies: + tslib: ^2.6.1 + checksum: e734516b3cb26086c18bd9c012fefe818928a5073178842ab7e62885a090f1dd7bda9c7bb8cd317167502cb8ec86c0b1b0ccd71dac7ab469382a4518157b0d12 + languageName: node + linkType: hard + +"pvutils@npm:^1.1.3": + version: 1.1.3 + resolution: "pvutils@npm:1.1.3" + checksum: 2ee26a9e5176c348977d6ec00d8ee80bff62f51743b1c5fe8abeeb4c5d29d9959cdfe0ce146707a9e6801bce88190fed3002d720b072dc87d031c692820b44c9 + languageName: node + linkType: hard + "q@npm:^1.1.2": version: 1.5.1 resolution: "q@npm:1.5.1" @@ -40279,6 +41163,18 @@ __metadata: languageName: node linkType: hard +"query-string@npm:^7.0.1": + version: 7.1.3 + resolution: "query-string@npm:7.1.3" + dependencies: + decode-uri-component: ^0.2.2 + filter-obj: ^1.1.0 + split-on-first: ^1.0.0 + strict-uri-encode: ^2.0.0 + checksum: 91af02dcd9cc9227a052841d5c2eecb80a0d6489d05625df506a097ef1c59037cfb5e907f39b84643cbfd535c955abec3e553d0130a7b510120c37d06e0f4346 + languageName: node + linkType: hard + "querystring-es3@npm:^0.2.1": version: 0.2.1 resolution: "querystring-es3@npm:0.2.1" @@ -40548,6 +41444,17 @@ __metadata: languageName: node linkType: hard +"react-native-securerandom@npm:^0.1.1": + version: 0.1.1 + resolution: "react-native-securerandom@npm:0.1.1" + dependencies: + base64-js: "*" + peerDependencies: + react-native: "*" + checksum: 9c043b2e20908f3a76b5906497873b54b57267bd92d8e5f62c52413c9eb948e90440153b4c5e516027cb2a700b18edd9cb9f8b02ac2b12ace37a0ba714ae3eea + languageName: node + linkType: hard + "react-reconciler@npm:^0.26.2": version: 0.26.2 resolution: "react-reconciler@npm:0.26.2" @@ -41048,7 +41955,28 @@ __metadata: languageName: node linkType: hard -"reflect-metadata@npm:0.1.13, reflect-metadata@npm:^0.1.2": +"ref-array-di@npm:1.2.2, ref-array-di@npm:^1.2.2": + version: 1.2.2 + resolution: "ref-array-di@npm:1.2.2" + dependencies: + array-index: ^1.0.0 + debug: ^3.1.0 + node-gyp: latest + checksum: 69e076831bb1affdec28af85e24eb82fde69408143909ecf07623f40ab61f2e9c20dd46334ebef49dd2c093fc1eb4973771b9e57ed5ebe3e043b1a8a104f9e95 + languageName: node + linkType: hard + +"ref-struct-di@npm:1.1.1, ref-struct-di@npm:^1.1.0, ref-struct-di@npm:^1.1.1": + version: 1.1.1 + resolution: "ref-struct-di@npm:1.1.1" + dependencies: + debug: ^3.1.0 + node-gyp: latest + checksum: 787dec1439628260b7928e5b53ff4cb83012e30e4a32b8b2d5198f138925b4bddf72de9da5c7ee6801c9f9c1427946bd911d58a249ce4f4babf2998cc69f0244 + languageName: node + linkType: hard + +"reflect-metadata@npm:0.1.13, reflect-metadata@npm:^0.1.13, reflect-metadata@npm:^0.1.2": version: 0.1.13 resolution: "reflect-metadata@npm:0.1.13" checksum: 798d379a7b6f6455501145419505c97dd11cbc23857a386add2b9ef15963ccf15a48d9d15507afe01d4cd74116df8a213247200bac00320bd7c11ddeaa5e8fb4 @@ -42204,7 +43132,7 @@ __metadata: languageName: node linkType: hard -"rxjs@npm:7.8.1, rxjs@npm:^7.5.1, rxjs@npm:^7.5.5, rxjs@npm:^7.8.1": +"rxjs@npm:7.8.1, rxjs@npm:^7.2.0, rxjs@npm:^7.5.1, rxjs@npm:^7.5.5, rxjs@npm:^7.8.1": version: 7.8.1 resolution: "rxjs@npm:7.8.1" dependencies: @@ -42803,6 +43731,15 @@ __metadata: languageName: node linkType: hard +"serialize-error@npm:^8.0.1": + version: 8.1.0 + resolution: "serialize-error@npm:8.1.0" + dependencies: + type-fest: ^0.20.2 + checksum: 2eef236d50edd2d7926e602c14fb500dc3a125ee52e9f08f67033181b8e0be5d1122498bdf7c23c80683cddcad083a27974e9e7111ce23165f4d3bcdd6d65102 + languageName: node + linkType: hard + "serialize-javascript@npm:6.0.0, serialize-javascript@npm:^6.0.0": version: 6.0.0 resolution: "serialize-javascript@npm:6.0.0" @@ -44331,6 +45268,13 @@ __metadata: languageName: node linkType: hard +"str2buf@npm:^1.3.0": + version: 1.3.0 + resolution: "str2buf@npm:1.3.0" + checksum: 2d32e6571d6a650cd59d1a0f3a6fb686659953f425f17dd936135c7ce8d28c0cf24bfca9ec297474635595c17cdccbb96afbece223c075a04e3af6a9f5b5d14e + languageName: node + linkType: hard + "stream-browserify@npm:3.0.0, stream-browserify@npm:^3.0.0": version: 3.0.0 resolution: "stream-browserify@npm:3.0.0" @@ -46456,7 +47400,7 @@ __metadata: languageName: node linkType: hard -"tslib@npm:2.6.2, tslib@npm:^2.5.0, tslib@npm:^2.6.0": +"tslib@npm:2.6.2, tslib@npm:^2.5.0, tslib@npm:^2.6.0, tslib@npm:^2.6.1, tslib@npm:^2.6.2": version: 2.6.2 resolution: "tslib@npm:2.6.2" checksum: 329ea56123005922f39642318e3d1f0f8265d1e7fcb92c633e0809521da75eeaca28d2cf96d7248229deb40e5c19adf408259f4b9640afd20d13aecc1430f3ad @@ -46577,6 +47521,15 @@ __metadata: languageName: node linkType: hard +"tsyringe@npm:^4.8.0": + version: 4.8.0 + resolution: "tsyringe@npm:4.8.0" + dependencies: + tslib: ^1.9.3 + checksum: 6bf13235cc1ae86829169e3a887c3ff6ee2d220678df01dd0fff202b5a533d4eb47a52334b76d2b1b1cf80c8c92ff22173a54ad72c9f1b8ea0ea4957304966f0 + languageName: node + linkType: hard + "tty-browserify@npm:^0.0.1": version: 0.0.1 resolution: "tty-browserify@npm:0.0.1" @@ -47764,6 +48717,13 @@ __metadata: languageName: node linkType: hard +"validator@npm:^13.7.0": + version: 13.11.0 + resolution: "validator@npm:13.11.0" + checksum: d1e0c27022681420756da25bc03eb08d5f0c66fb008f8ff02ebc95812b77c6be6e03d3bd05cf80ca702e23eeb73dadd66b4b3683173ea2a0bc7cc72820bee131 + languageName: node + linkType: hard + "value-or-promise@npm:1.0.11": version: 1.0.11 resolution: "value-or-promise@npm:1.0.11" @@ -48036,6 +48996,16 @@ __metadata: languageName: node linkType: hard +"web-did-resolver@npm:^2.0.21": + version: 2.0.27 + resolution: "web-did-resolver@npm:2.0.27" + dependencies: + cross-fetch: ^4.0.0 + did-resolver: ^4.0.0 + checksum: 9a048b833e821546511b08b5289ecf22a43969f5bb6c603a7c335f812756a5b461e42280c4b19ac1bfba8ea2f79330744e9e324e3cb5b1fa3560dd54ae916479 + languageName: node + linkType: hard + "web-streams-polyfill@npm:^3.0.3": version: 3.2.1 resolution: "web-streams-polyfill@npm:3.2.1" @@ -50794,6 +51764,26 @@ __metadata: languageName: node linkType: hard +"webcrypto-core@npm:^1.7.7": + version: 1.7.7 + resolution: "webcrypto-core@npm:1.7.7" + dependencies: + "@peculiar/asn1-schema": ^2.3.6 + "@peculiar/json-schema": ^1.1.12 + asn1js: ^3.0.1 + pvtsutils: ^1.3.2 + tslib: ^2.4.0 + checksum: 1dc5aedb250372dd95e175a671b990ae50e36974f99c4efc85d88e6528c1bc52dd964d44a41b68043c21fb26aabfe8aad4f05a1c39ca28d61de5ca7388413d52 + languageName: node + linkType: hard + +"webcrypto-shim@npm:^0.1.4": + version: 0.1.7 + resolution: "webcrypto-shim@npm:0.1.7" + checksum: c97c678ddab8122687958d060c3e8750dd26cc2347a077db09395a89af1cc113ae65cc3fd5379ca778fd953258cefebed42326d7b3aefc5a1083a273dcb6cb3d + languageName: node + linkType: hard + "webidl-conversions@npm:^3.0.0": version: 3.0.1 resolution: "webidl-conversions@npm:3.0.1"