From 0feda532628f47e0d381a5cc124f5aa052acf26d Mon Sep 17 00:00:00 2001 From: Timo Glastra Date: Wed, 31 Jan 2024 22:17:09 +0700 Subject: [PATCH] refactor(indy-sdk)!: remove indy-sdk package (#1629) Signed-off-by: Timo Glastra Co-authored-by: Ariel Gentile --- .devcontainer/Dockerfile | 18 - .devcontainer/devcontainer.json | 4 +- .github/actions/setup-cheqd/action.yml | 14 - .github/actions/setup-indy-pool/action.yml | 36 - .github/actions/setup-libindy/action.yml | 18 - .../setup-postgres-wallet-plugin/action.yml | 21 - .github/actions/setup-postgres/action.yml | 12 - .github/workflows/continuous-deployment.yml | 8 - .github/workflows/continuous-integration.yml | 34 +- DEVREADME.md | 107 +-- Dockerfile | 66 +- README.md | 18 +- TROUBLESHOOTING.md | 85 --- demo/package.json | 2 - demo/src/Alice.ts | 2 +- demo/src/BaseAgent.ts | 64 +- demo/src/Faber.ts | 2 +- docker-compose.arm.yml | 32 + docker-compose.yml | 31 + docker/docker-compose-mediators-ngrok.yml | 19 - docker/docker-compose-mediators.yml | 16 - package.json | 7 +- .../action-menu/tests/action-menu.e2e.test.ts | 10 +- .../anoncreds-rs/src/AnonCredsRsModule.ts | 2 +- packages/anoncreds-rs/src/index.ts | 1 + .../src/services/AnonCredsRsHolderService.ts | 12 +- .../__tests__/AnonCredsRsServices.test.ts | 7 +- .../src/services/__tests__/helpers.ts | 2 + .../anoncreds-rs/tests/anoncreds-flow.test.ts | 4 +- packages/anoncreds-rs/tests/anoncredsSetup.ts | 22 +- packages/anoncreds-rs/tests/indy-flow.test.ts | 2 +- .../v2-credential-revocation.e2e.test.ts | 4 +- .../tests/v2-credentials.e2e.test.ts | 1 + .../anoncreds-rs/tests/v2-proofs.e2e.test.ts | 2 +- packages/anoncreds/package.json | 1 - packages/anoncreds/src/AnonCredsApi.ts | 2 + .../AnonCredsCredentialFormatService.ts | 4 +- .../LegacyIndyCredentialFormatService.ts | 4 +- .../legacy-indy-format-services.test.ts | 120 +++- packages/anoncreds/src/models/exchange.ts | 1 + packages/anoncreds/src/models/internal.ts | 4 +- .../v1-connectionless-proofs.e2e.test.ts | 17 +- .../src/updates/__tests__/0.3.test.ts | 47 +- .../__tests__/__snapshots__/0.3.test.ts.snap | 8 +- .../tests/InMemoryAnonCredsRegistry.ts | 27 +- packages/anoncreds/tests/anoncreds.test.ts | 54 +- .../anoncreds/tests/legacyAnonCredsSetup.ts | 84 +-- packages/askar/src/AskarModule.ts | 2 +- .../askar/src/storage/AskarStorageService.ts | 2 +- packages/askar/src/utils/askarKeyTypes.ts | 43 +- packages/askar/src/utils/askarWalletConfig.ts | 44 +- packages/askar/src/wallet/AskarBaseWallet.ts | 315 +++------ packages/askar/src/wallet/AskarWallet.ts | 11 +- .../AskarWalletPostgresStorageConfig.ts | 22 - .../src/wallet/AskarWalletStorageConfig.ts | 47 ++ packages/askar/src/wallet/didcommV1.ts | 177 +++++ packages/askar/src/wallet/index.ts | 2 +- .../askar/tests/askar-inmemory.e2e.test.ts | 6 +- .../askar/tests/askar-postgres.e2e.test.ts | 18 +- packages/askar/tests/askar-sqlite.e2e.test.ts | 6 +- packages/askar/tests/helpers.ts | 17 +- packages/bbs-signatures/src/BbsModule.ts | 2 +- .../tests/bbs-signatures.e2e.test.ts | 25 +- .../tests/bbs-signing-provider.e2e.test.ts | 34 +- ...proof.credentials.propose-offerBbs.test.ts | 5 +- packages/cheqd/package.json | 2 - packages/cheqd/src/CheqdModule.ts | 2 +- .../tests/cheqd-did-registrar.e2e.test.ts | 4 +- .../tests/cheqd-did-resolver.e2e.test.ts | 4 +- .../cheqd-sdk-anoncreds-registry.e2e.test.ts | 20 +- packages/cheqd/tests/setupCheqdModule.ts | 8 - packages/core/src/agent/Agent.ts | 4 +- packages/core/src/agent/Dispatcher.ts | 6 +- packages/core/src/agent/MessageSender.ts | 6 +- .../core/src/agent/__tests__/Agent.test.ts | 10 +- .../src/agent/__tests__/MessageSender.test.ts | 9 +- .../src/crypto/__tests__/JwsService.test.ts | 11 +- .../signature/SignatureDecoratorUtils.test.ts | 6 +- .../__tests__/basic-messages.e2e.test.ts | 25 +- .../__tests__/ConnectionService.test.ts | 6 +- .../__tests__/connection-manual.e2e.test.ts | 12 +- .../__tests__/did-rotate.e2e.test.ts | 9 +- .../__tests__/didexchange-numalgo.e2e.test.ts | 9 +- .../v2-connectionless-credentials.e2e.test.ts | 12 +- .../v2-credentials-auto-accept.e2e.test.ts | 14 +- ...f.credentials.propose-offerED25519.test.ts | 44 +- .../modules/dids/__tests__/DidsApi.test.ts | 18 +- .../dids/__tests__/dids-registrar.e2e.test.ts | 14 +- .../dids/__tests__/dids-resolver.e2e.test.ts | 16 +- .../modules/dids/__tests__/peer-did.test.ts | 6 +- .../DifPresentationExchangeModule.ts | 2 +- .../v1-discover-features.e2e.test.ts | 25 +- .../v2-discover-features.e2e.test.ts | 25 +- .../message-pickup/__tests__/pickup.test.ts | 19 +- .../oob/__tests__/connect-to-self.e2e.test.ts | 13 +- .../oob/__tests__/implicit.e2e.test.ts | 46 +- ...entationExchangeProofFormatService.test.ts | 26 +- .../v2-indy-connectionless-proofs.e2e.test.ts | 16 +- .../v2/__tests__/v2-indy-proofs.e2e.test.ts | 5 + ...entation-exchange-presentation.e2e.test.ts | 2 +- .../routing/__tests__/mediation.test.ts | 34 +- .../vc/__tests__/W3cCredentialService.test.ts | 10 +- .../vc/__tests__/W3cCredentialsApi.test.ts | 22 +- .../W3cJsonLdCredentialService.test.ts | 7 +- .../modules/vc/data-integrity/deriveProof.ts | 1 + .../proof-purposes/ProofPurpose.ts | 1 + .../vc/jwt-vc/W3cJwtCredentialService.ts | 2 +- .../__tests__/W3cJwtCredentialService.test.ts | 12 +- .../storage/migration/__tests__/0.1.test.ts | 70 +- .../storage/migration/__tests__/0.2.test.ts | 61 +- .../storage/migration/__tests__/0.3.test.ts | 20 +- .../__tests__/UpdateAssistant.test.ts | 28 +- .../__tests__/__snapshots__/0.2.test.ts.snap | 22 +- .../migration/__tests__/backup-askar.test.ts | 11 +- .../migration/__tests__/backup.test.ts | 16 +- packages/core/tests/agents.test.ts | 23 +- packages/core/tests/connections.test.ts | 36 +- packages/core/tests/generic-records.test.ts | 13 +- packages/core/tests/helpers.ts | 98 ++- packages/core/tests/index.ts | 1 - packages/core/tests/indySdk.ts | 3 - packages/core/tests/jsonld.ts | 23 +- packages/core/tests/migration.test.ts | 4 +- .../core/tests/multi-protocol-version.test.ts | 23 +- .../tests/oob-mediation-provision.test.ts | 22 +- packages/core/tests/oob-mediation.test.ts | 22 +- packages/core/tests/oob.test.ts | 17 +- packages/core/tests/setup.ts | 3 - packages/core/tests/wallet.test.ts | 186 ----- .../indy-sdk-to-askar-migration/package.json | 2 - .../src/IndySdkToAskarMigrationUpdater.ts | 2 +- .../tests/indy-sdk-040-wallet.db | Bin 0 -> 57344 bytes .../tests/migrate.test.ts | 99 +-- packages/indy-sdk/CHANGELOG.md | 59 -- packages/indy-sdk/README.md | 31 - packages/indy-sdk/jest.config.ts | 13 - packages/indy-sdk/package.json | 41 -- packages/indy-sdk/src/IndySdkModule.ts | 60 -- packages/indy-sdk/src/IndySdkModuleConfig.ts | 81 --- packages/indy-sdk/src/anoncreds/index.ts | 4 - .../services/IndySdkAnonCredsRegistry.ts | 634 ----------------- .../services/IndySdkHolderService.ts | 464 ------------- .../services/IndySdkIssuerService.ts | 173 ----- .../services/IndySdkIssuerServiceMetadata.ts | 3 - .../services/IndySdkRevocationService.ts | 155 ----- .../services/IndySdkVerifierService.ts | 96 --- .../utils/__tests__/assertUnqualified.test.ts | 152 ----- .../utils/__tests__/identifiers.test.ts | 79 --- .../utils/__tests__/transform.test.ts | 114 ---- .../src/anoncreds/utils/assertUnqualified.ts | 129 ---- .../src/anoncreds/utils/identifiers.ts | 63 -- .../indy-sdk/src/anoncreds/utils/tails.ts | 45 -- .../indy-sdk/src/anoncreds/utils/transform.ts | 161 ----- .../src/dids/IndySdkIndyDidRegistrar.ts | 328 --------- .../src/dids/IndySdkIndyDidResolver.ts | 126 ---- .../src/dids/IndySdkSovDidResolver.ts | 101 --- .../__tests__/IndySdkIndyDidRegistrar.test.ts | 501 -------------- .../__tests__/IndySdkIndyDidResolver.test.ts | 127 ---- .../__tests__/IndySdkSovDidResolver.test.ts | 132 ---- .../didIndyPool1R1xKJw17sUoXhejEpugMYJ.json | 50 -- .../didIndyPool1WJz9mHyW9BZksioQnRsrAo.json | 48 -- .../didSovR1xKJw17sUoXhejEpugMYJ.json | 51 -- .../didSovWJz9mHyW9BZksioQnRsrAo.json | 49 -- packages/indy-sdk/src/dids/didIndyUtil.ts | 55 -- packages/indy-sdk/src/dids/didSovUtil.ts | 138 ---- packages/indy-sdk/src/dids/index.ts | 3 - packages/indy-sdk/src/error/IndySdkError.ts | 11 - packages/indy-sdk/src/error/index.ts | 2 - packages/indy-sdk/src/error/indyError.ts | 100 --- packages/indy-sdk/src/index.ts | 23 - packages/indy-sdk/src/ledger/IndySdkPool.ts | 218 ------ .../indy-sdk/src/ledger/IndySdkPoolService.ts | 357 ---------- .../__tests__/IndySdkPoolService.test.ts | 422 ------------ .../src/ledger/__tests__/didResponses.ts | 58 -- .../serializeRequestForSignature.test.ts | 87 --- .../src/ledger/__tests__/util.test.ts | 45 -- .../src/ledger/error/IndySdkPoolError.ts | 7 - .../error/IndySdkPoolNotConfiguredError.ts | 7 - .../ledger/error/IndySdkPoolNotFoundError.ts | 7 - packages/indy-sdk/src/ledger/error/index.ts | 3 - packages/indy-sdk/src/ledger/index.ts | 2 - .../ledger/serializeRequestForSignature.ts | 61 -- packages/indy-sdk/src/ledger/util.ts | 9 - .../src/storage/IndySdkStorageService.ts | 321 --------- .../__tests__/IndySdkStorageService.test.ts | 314 --------- packages/indy-sdk/src/storage/index.ts | 1 - packages/indy-sdk/src/types.ts | 6 - .../indy-sdk/src/utils/__tests__/did.test.ts | 77 --- .../indy-sdk/src/utils/assertIndySdkWallet.ts | 13 - packages/indy-sdk/src/utils/did.ts | 89 --- packages/indy-sdk/src/utils/promises.ts | 44 -- packages/indy-sdk/src/wallet/IndySdkWallet.ts | 645 ------------------ .../wallet/__tests__/IndySdkWallet.test.ts | 114 ---- packages/indy-sdk/src/wallet/index.ts | 1 - .../indy-sdk/tests/__fixtures__/anoncreds.ts | 30 - .../tests/indy-did-registrar.e2e.test.ts | 125 ---- .../tests/indy-did-resolver.e2e.test.ts | 99 --- .../indy-sdk-anoncreds-registry.e2e.test.ts | 345 ---------- packages/indy-sdk/tests/postgres.e2e.test.ts | 112 --- packages/indy-sdk/tests/setup.ts | 1 - packages/indy-sdk/tests/setupIndySdkModule.ts | 35 - .../tests/sov-did-resolver.e2e.test.ts | 102 --- packages/indy-sdk/tsconfig.build.json | 7 - packages/indy-sdk/tsconfig.json | 6 - packages/indy-vdr/src/IndyVdrModule.ts | 2 +- .../src/anoncreds/IndyVdrAnonCredsRegistry.ts | 4 +- .../src/anoncreds/utils/identifiers.ts | 5 - .../__tests__/IndyVdrIndyDidRegistrar.test.ts | 8 +- .../indy-vdr-anoncreds-registry.e2e.test.ts | 76 +-- .../tests/indy-vdr-did-registrar.e2e.test.ts | 217 +++--- .../indy-vdr-indy-did-resolver.e2e.test.ts | 9 +- .../indy-vdr/tests/indy-vdr-pool.e2e.test.ts | 7 +- .../indy-vdr-sov-did-resolver.e2e.test.ts | 9 +- packages/node/src/PostgresPlugin.ts | 108 --- packages/node/src/index.ts | 10 +- .../src/OpenId4VcClientModule.ts | 2 +- .../tests/openid4vc-client.e2e.test.ts | 13 +- .../__tests__/QuestionAnswerService.test.ts | 7 +- .../tests/question-answer.e2e.test.ts | 10 +- packages/react-native/jest.config.ts | 4 - packages/sd-jwt-vc/package.json | 1 - packages/sd-jwt-vc/src/SdJwtVcModule.ts | 2 +- .../src/__tests__/SdJwtVcService.test.ts | 28 +- packages/sd-jwt-vc/tests/sdJwtVc.e2e.test.ts | 42 +- packages/tenants/src/TenantsModule.ts | 2 +- .../tenants/src/__tests__/TenantAgent.test.ts | 18 +- .../tenants/src/__tests__/TenantsApi.test.ts | 5 +- .../TenantSessionCoordinator.test.ts | 20 +- .../tenants/tests/tenant-sessions.e2e.test.ts | 16 +- .../tests/tenants-askar-profiles.e2e.test.ts | 12 +- packages/tenants/tests/tenants.e2e.test.ts | 17 +- samples/extension-module/package.json | 16 +- .../extension-module/tests/dummy.e2e.test.ts | 8 +- tests/InMemoryStorageService.ts | 68 +- tests/InMemoryWallet.ts | 343 ++++++++++ tests/InMemoryWalletModule.ts | 22 + ...> e2e-askar-indy-vdr-anoncreds-rs.test.ts} | 23 +- tests/e2e-http.test.ts | 16 +- tests/e2e-subject.test.ts | 16 +- tests/e2e-ws-pickup-v2.test.ts | 20 +- tests/e2e-ws.test.ts | 20 +- yarn.lock | 221 +----- 242 files changed, 2058 insertions(+), 10727 deletions(-) delete mode 100644 .devcontainer/Dockerfile delete mode 100644 .github/actions/setup-cheqd/action.yml delete mode 100644 .github/actions/setup-indy-pool/action.yml delete mode 100644 .github/actions/setup-libindy/action.yml delete mode 100644 .github/actions/setup-postgres-wallet-plugin/action.yml delete mode 100644 .github/actions/setup-postgres/action.yml delete mode 100644 TROUBLESHOOTING.md create mode 100644 docker-compose.arm.yml create mode 100644 docker-compose.yml delete mode 100644 docker/docker-compose-mediators-ngrok.yml delete mode 100644 docker/docker-compose-mediators.yml delete mode 100644 packages/askar/src/wallet/AskarWalletPostgresStorageConfig.ts create mode 100644 packages/askar/src/wallet/AskarWalletStorageConfig.ts create mode 100644 packages/askar/src/wallet/didcommV1.ts delete mode 100644 packages/core/tests/indySdk.ts delete mode 100644 packages/core/tests/wallet.test.ts create mode 100644 packages/indy-sdk-to-askar-migration/tests/indy-sdk-040-wallet.db delete mode 100644 packages/indy-sdk/CHANGELOG.md delete mode 100644 packages/indy-sdk/README.md delete mode 100644 packages/indy-sdk/jest.config.ts delete mode 100644 packages/indy-sdk/package.json delete mode 100644 packages/indy-sdk/src/IndySdkModule.ts delete mode 100644 packages/indy-sdk/src/IndySdkModuleConfig.ts delete mode 100644 packages/indy-sdk/src/anoncreds/index.ts delete mode 100644 packages/indy-sdk/src/anoncreds/services/IndySdkAnonCredsRegistry.ts delete mode 100644 packages/indy-sdk/src/anoncreds/services/IndySdkHolderService.ts delete mode 100644 packages/indy-sdk/src/anoncreds/services/IndySdkIssuerService.ts delete mode 100644 packages/indy-sdk/src/anoncreds/services/IndySdkIssuerServiceMetadata.ts delete mode 100644 packages/indy-sdk/src/anoncreds/services/IndySdkRevocationService.ts delete mode 100644 packages/indy-sdk/src/anoncreds/services/IndySdkVerifierService.ts delete mode 100644 packages/indy-sdk/src/anoncreds/utils/__tests__/assertUnqualified.test.ts delete mode 100644 packages/indy-sdk/src/anoncreds/utils/__tests__/identifiers.test.ts delete mode 100644 packages/indy-sdk/src/anoncreds/utils/__tests__/transform.test.ts delete mode 100644 packages/indy-sdk/src/anoncreds/utils/assertUnqualified.ts delete mode 100644 packages/indy-sdk/src/anoncreds/utils/identifiers.ts delete mode 100644 packages/indy-sdk/src/anoncreds/utils/tails.ts delete mode 100644 packages/indy-sdk/src/anoncreds/utils/transform.ts delete mode 100644 packages/indy-sdk/src/dids/IndySdkIndyDidRegistrar.ts delete mode 100644 packages/indy-sdk/src/dids/IndySdkIndyDidResolver.ts delete mode 100644 packages/indy-sdk/src/dids/IndySdkSovDidResolver.ts delete mode 100644 packages/indy-sdk/src/dids/__tests__/IndySdkIndyDidRegistrar.test.ts delete mode 100644 packages/indy-sdk/src/dids/__tests__/IndySdkIndyDidResolver.test.ts delete mode 100644 packages/indy-sdk/src/dids/__tests__/IndySdkSovDidResolver.test.ts delete mode 100644 packages/indy-sdk/src/dids/__tests__/__fixtures__/didIndyPool1R1xKJw17sUoXhejEpugMYJ.json delete mode 100644 packages/indy-sdk/src/dids/__tests__/__fixtures__/didIndyPool1WJz9mHyW9BZksioQnRsrAo.json delete mode 100644 packages/indy-sdk/src/dids/__tests__/__fixtures__/didSovR1xKJw17sUoXhejEpugMYJ.json delete mode 100644 packages/indy-sdk/src/dids/__tests__/__fixtures__/didSovWJz9mHyW9BZksioQnRsrAo.json delete mode 100644 packages/indy-sdk/src/dids/didIndyUtil.ts delete mode 100644 packages/indy-sdk/src/dids/didSovUtil.ts delete mode 100644 packages/indy-sdk/src/dids/index.ts delete mode 100644 packages/indy-sdk/src/error/IndySdkError.ts delete mode 100644 packages/indy-sdk/src/error/index.ts delete mode 100644 packages/indy-sdk/src/error/indyError.ts delete mode 100644 packages/indy-sdk/src/index.ts delete mode 100644 packages/indy-sdk/src/ledger/IndySdkPool.ts delete mode 100644 packages/indy-sdk/src/ledger/IndySdkPoolService.ts delete mode 100644 packages/indy-sdk/src/ledger/__tests__/IndySdkPoolService.test.ts delete mode 100644 packages/indy-sdk/src/ledger/__tests__/didResponses.ts delete mode 100644 packages/indy-sdk/src/ledger/__tests__/serializeRequestForSignature.test.ts delete mode 100644 packages/indy-sdk/src/ledger/__tests__/util.test.ts delete mode 100644 packages/indy-sdk/src/ledger/error/IndySdkPoolError.ts delete mode 100644 packages/indy-sdk/src/ledger/error/IndySdkPoolNotConfiguredError.ts delete mode 100644 packages/indy-sdk/src/ledger/error/IndySdkPoolNotFoundError.ts delete mode 100644 packages/indy-sdk/src/ledger/error/index.ts delete mode 100644 packages/indy-sdk/src/ledger/index.ts delete mode 100644 packages/indy-sdk/src/ledger/serializeRequestForSignature.ts delete mode 100644 packages/indy-sdk/src/ledger/util.ts delete mode 100644 packages/indy-sdk/src/storage/IndySdkStorageService.ts delete mode 100644 packages/indy-sdk/src/storage/__tests__/IndySdkStorageService.test.ts delete mode 100644 packages/indy-sdk/src/storage/index.ts delete mode 100644 packages/indy-sdk/src/types.ts delete mode 100644 packages/indy-sdk/src/utils/__tests__/did.test.ts delete mode 100644 packages/indy-sdk/src/utils/assertIndySdkWallet.ts delete mode 100644 packages/indy-sdk/src/utils/did.ts delete mode 100644 packages/indy-sdk/src/utils/promises.ts delete mode 100644 packages/indy-sdk/src/wallet/IndySdkWallet.ts delete mode 100644 packages/indy-sdk/src/wallet/__tests__/IndySdkWallet.test.ts delete mode 100644 packages/indy-sdk/src/wallet/index.ts delete mode 100644 packages/indy-sdk/tests/__fixtures__/anoncreds.ts delete mode 100644 packages/indy-sdk/tests/indy-did-registrar.e2e.test.ts delete mode 100644 packages/indy-sdk/tests/indy-did-resolver.e2e.test.ts delete mode 100644 packages/indy-sdk/tests/indy-sdk-anoncreds-registry.e2e.test.ts delete mode 100644 packages/indy-sdk/tests/postgres.e2e.test.ts delete mode 100644 packages/indy-sdk/tests/setup.ts delete mode 100644 packages/indy-sdk/tests/setupIndySdkModule.ts delete mode 100644 packages/indy-sdk/tests/sov-did-resolver.e2e.test.ts delete mode 100644 packages/indy-sdk/tsconfig.build.json delete mode 100644 packages/indy-sdk/tsconfig.json delete mode 100644 packages/node/src/PostgresPlugin.ts create mode 100644 tests/InMemoryWallet.ts create mode 100644 tests/InMemoryWalletModule.ts rename tests/{e2e-askar-indy-sdk-wallet-subject.test.ts => e2e-askar-indy-vdr-anoncreds-rs.test.ts} (83%) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile deleted file mode 100644 index 3d51f0a5a0..0000000000 --- a/.devcontainer/Dockerfile +++ /dev/null @@ -1,18 +0,0 @@ -# arm + amd compatible Dockerfile -FROM ghcr.io/findy-network/findy-base:indy-1.16.ubuntu-18.04 AS indy-base - -FROM ubuntu:18.04 - -# install indy deps and files from base -RUN apt-get update && apt-get install -y libsodium23 libssl1.1 libzmq5 git zsh - -COPY --from=indy-base /usr/include/indy /usr/include/indy -COPY --from=indy-base /usr/lib/libindy.a /usr/lib/libindy.a -COPY --from=indy-base /usr/lib/libindy.so /usr/lib/libindy.so - -RUN apt-get install -y curl python3 build-essential ca-certificates && \ - curl https://raw.githubusercontent.com/creationix/nvm/master/install.sh | bash && \ - export NVM_DIR="$HOME/.nvm" && \ - [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" && \ - nvm install v16 && \ - npm install yarn -g diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 1728c1a7cc..61745b0bc6 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,7 +1,5 @@ { - "build": { - "dockerfile": "Dockerfile" - }, + "image": "node:18", "runArgs": ["--env-file", ".devcontainer/devcontainer.env"], "workspaceMount": "source=${localWorkspaceFolder},target=/work,type=bind", "workspaceFolder": "/work" diff --git a/.github/actions/setup-cheqd/action.yml b/.github/actions/setup-cheqd/action.yml deleted file mode 100644 index e8a64207e7..0000000000 --- a/.github/actions/setup-cheqd/action.yml +++ /dev/null @@ -1,14 +0,0 @@ -name: Setup cheqd -description: Setup a cheqd network to perform tests -author: 'daev@cheqd.io' - -runs: - using: composite - steps: - - name: Start cheqd localnet - run: docker run --rm -d -p 26657:26657 ghcr.io/cheqd/cheqd-testnet:latest - shell: bash - -branding: - icon: scissors - color: purple diff --git a/.github/actions/setup-indy-pool/action.yml b/.github/actions/setup-indy-pool/action.yml deleted file mode 100644 index 23e1ebd8cf..0000000000 --- a/.github/actions/setup-indy-pool/action.yml +++ /dev/null @@ -1,36 +0,0 @@ -name: Setup Indy Pool -description: Setup an Indy ledger pool and register test did on the ledger -author: 'timo@animo.id' - -inputs: - seed: - description: Seed to register on the ledger - required: true - endorserSeed: - description: Endorser seed to register on the ledger - required: true - -runs: - using: composite - steps: - - name: Start indy pool - run: | - docker build -f network/indy-pool.dockerfile -t indy-pool . - docker run -d --name indy-pool -p 9701-9708:9701-9708 indy-pool - shell: bash - - - name: Setup Indy CLI - run: docker exec indy-pool indy-cli-setup - shell: bash - - - name: Register Trustee DID on ledger - run: docker exec indy-pool add-did-from-seed ${{ inputs.seed }} TRUSTEE - shell: bash - - - name: Register Endorser DID on ledger - run: docker exec indy-pool add-did-from-seed ${{ inputs.endorserSeed }} ENDORSER - shell: bash - -branding: - icon: scissors - color: purple diff --git a/.github/actions/setup-libindy/action.yml b/.github/actions/setup-libindy/action.yml deleted file mode 100644 index 086635ee6c..0000000000 --- a/.github/actions/setup-libindy/action.yml +++ /dev/null @@ -1,18 +0,0 @@ -name: Setup Libindy -description: Download and install the libindy binary from the sovrin repository -author: 'timo@animo.id' - -runs: - using: composite - steps: - - name: Setup Indy - run: | - 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 -y - sudo apt-get install -y --allow-unauthenticated libindy - shell: bash - -branding: - icon: scissors - color: purple diff --git a/.github/actions/setup-postgres-wallet-plugin/action.yml b/.github/actions/setup-postgres-wallet-plugin/action.yml deleted file mode 100644 index a03b2f3fde..0000000000 --- a/.github/actions/setup-postgres-wallet-plugin/action.yml +++ /dev/null @@ -1,21 +0,0 @@ -name: Setup Postgres wallet plugin -description: Setup Postgres wallet plugin -author: 'sairanjit.tummalapalli@ayanworks.com' - -runs: - using: composite - steps: - # cargo build failing on latest release of rust due to - # socket2 dependency in the plugin https://users.rust-lang.org/t/build-broken-with-parse-quote-spanned-is-ambiguous/80280/2 - # so pointing rust version to 1.63.0 - - name: Setup Postgres wallet plugin - run: | - sudo apt-get install -y libzmq3-dev libsodium-dev pkg-config libssl-dev - curl https://sh.rustup.rs -sSf | bash -s -- -y - export PATH="/root/.cargo/bin:${PATH}" - rustup default 1.63.0 - cd ../ - git clone https://github.com/hyperledger/indy-sdk.git - cd indy-sdk/experimental/plugins/postgres_storage/ - cargo build --release - shell: bash diff --git a/.github/actions/setup-postgres/action.yml b/.github/actions/setup-postgres/action.yml deleted file mode 100644 index 6e69e6574f..0000000000 --- a/.github/actions/setup-postgres/action.yml +++ /dev/null @@ -1,12 +0,0 @@ -name: Setup Postgres -description: Setup Postgres -author: 'sairanjit.tummalapalli@ayanworks.com' - -runs: - using: composite - steps: - - name: Setup Postgres - run: | - docker pull postgres - docker run --name postgres -e POSTGRES_USER=postgres -e POSTGRES_PASSWORD=postgres -p 5432:5432 -d postgres - shell: bash diff --git a/.github/workflows/continuous-deployment.yml b/.github/workflows/continuous-deployment.yml index 2916ed1ec8..b9e47524ab 100644 --- a/.github/workflows/continuous-deployment.yml +++ b/.github/workflows/continuous-deployment.yml @@ -20,10 +20,6 @@ jobs: # pulls all commits (needed for lerna to correctly version) fetch-depth: 0 - # setup dependencies - - name: Setup Libindy - uses: ./.github/actions/setup-libindy - - name: Setup NodeJS uses: actions/setup-node@v4 with: @@ -69,10 +65,6 @@ jobs: - name: Checkout credo uses: actions/checkout@v4 - # setup dependencies - - name: Setup Libindy - uses: ./.github/actions/setup-libindy - - name: Setup NodeJS uses: actions/setup-node@v4 with: diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index 3aa49df90e..77b45515c3 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -9,10 +9,6 @@ on: workflow_dispatch: env: - TEST_AGENT_PUBLIC_DID_SEED: 000000000000000000000000Trustee9 - ENDORSER_AGENT_PUBLIC_DID_SEED: 00000000000000000000000Endorser9 - GENESIS_TXN_PATH: network/genesis/local-genesis.txn - LIB_INDY_STRG_POSTGRES: /home/runner/work/credo-ts/indy-sdk/experimental/plugins/postgres_storage/target/release # for Linux NODE_OPTIONS: --max_old_space_size=6144 # Make sure we're not running multiple release steps at the same time as this can give issues with determining the next npm version to release. @@ -53,10 +49,6 @@ jobs: - name: Checkout credo-ts uses: actions/checkout@v4 - # setup dependencies - - name: Setup Libindy - uses: ./.github/actions/setup-libindy - - name: Setup NodeJS uses: actions/setup-node@v4 with: @@ -91,24 +83,8 @@ jobs: uses: actions/checkout@v4 # setup dependencies - - - name: Setup Libindy - uses: ./.github/actions/setup-libindy - - - name: Setup Indy Pool - uses: ./.github/actions/setup-indy-pool - with: - seed: ${TEST_AGENT_PUBLIC_DID_SEED} - endorserSeed: ${ENDORSER_AGENT_PUBLIC_DID_SEED} - - - name: Setup Cheqd - uses: ./.github/actions/setup-cheqd - - - name: Setup Postgres - uses: ./.github/actions/setup-postgres - - - name: Setup Postgres wallet plugin - uses: ./.github/actions/setup-postgres-wallet-plugin + - name: Setup services + run: docker compose up -d - name: Setup NodeJS uses: actions/setup-node@v4 @@ -120,7 +96,7 @@ jobs: run: yarn install --frozen-lockfile - name: Run tests - run: TEST_AGENT_PUBLIC_DID_SEED=${TEST_AGENT_PUBLIC_DID_SEED} ENDORSER_AGENT_PUBLIC_DID_SEED=${ENDORSER_AGENT_PUBLIC_DID_SEED} GENESIS_TXN_PATH=${GENESIS_TXN_PATH} yarn test --coverage --forceExit --bail + run: yarn test --coverage --forceExit --bail - uses: codecov/codecov-action@v3 if: always() @@ -138,10 +114,6 @@ jobs: fetch-depth: 0 persist-credentials: false - # setup dependencies - - name: Setup Libindy - uses: ./.github/actions/setup-libindy - - name: Setup NodeJS uses: actions/setup-node@v4 with: diff --git a/DEVREADME.md b/DEVREADME.md index 7fa9a7a06a..bfd3e87e9e 100644 --- a/DEVREADME.md +++ b/DEVREADME.md @@ -18,74 +18,22 @@ GENESIS_TXN_PATH=/work/network/genesis/local-genesis.txn ## Running tests -Test are executed using jest. Some test require either the **mediator agents** or the **ledger** to be running. When running tests that require a connection to the ledger pool, you need to set the `TEST_AGENT_PUBLIC_DID_SEED`, `ENDORSER_AGENT_PUBLIC_DID_SEED` and `GENESIS_TXN_PATH` environment variables. +Test are executed using jest. Some test require the **indy ledger**, **cheqd ledger** or **postgres database** to be running. -### Setting environment variables - -If you're using the setup as described in this document, you don't need to provide any environment variables as the default will be sufficient. - -- `GENESIS_TXN_PATH`: The path to the genesis transaction that allows us to connect to the indy pool. - - `GENESIS_TXN_PATH=network/genesis/local-genesis.txn` - default. Works with the [ledger setup](#setup-indy-ledger) from the previous step. - - `GENESIS_TXN_PATH=network/genesis/builder-net-genesis.txn` - Sovrin BuilderNet genesis. - - `GENESIS_TXN_PATH=/path/to/any/ledger/you/like` -- `TEST_AGENT_PUBLIC_DID_SEED`: The seed to use for the public DID. This will be used to do public write operations to the ledger. You should use a seed for a DID that is already registered on the ledger. - - If using the local or default genesis, use the same seed you used for the `add-did-from-seed` command from the [ledger setup](#setup-indy-ledger) in the previous step. (default is `000000000000000000000000Trustee9`) - - If using the BuilderNet genesis, make sure your seed is registered on the BuilderNet using [selfserve.sovrin.org](https://selfserve.sovrin.org/) and you have read and accepted the associated [Transaction Author Agreement](https://github.com/sovrin-foundation/sovrin/blob/master/TAA/TAA.md). We are not responsible for any unwanted consequences of using the BuilderNet. -- `ENDORSER_AGENT_PUBLIC_DID_SEED`: The seed to use for the public Endorser DID. This will be used to endorse transactions. You should use a seed for a DID that is already registered on the ledger. - - If using the local or default genesis, use the same seed you used for the `add-did-from-seed` command from the [ledger setup](#setup-indy-ledger) in the previous step. (default is `00000000000000000000000Endorser9`) - - If using the BuilderNet genesis, make sure your seed is registered on the BuilderNet using [selfserve.sovrin.org](https://selfserve.sovrin.org/) and you have read and accepted the associated [Transaction Author Agreement](https://github.com/sovrin-foundation/sovrin/blob/master/TAA/TAA.md). We are not responsible for any unwanted consequences of using the BuilderNet. - -### Setup Postgres +When running tests that require a connection to the indy ledger pool, you can set the `TEST_AGENT_PUBLIC_DID_SEED`, `ENDORSER_AGENT_PUBLIC_DID_SEED` and `GENESIS_TXN_PATH` environment variables. -> Note: Setup the postgres plugin first by following the [docs](https://https://credo.js.org/) +### Quick Setup -```sh -# Get postgres docker image -docker pull postgres - -# Run postgres in docker -docker run --name postgres -e POSTGRES_USER=postgres -e POSTGRES_PASSWORD=postgres -p 5432:5432 -d postgres -``` - -### Setup Indy Ledger - -For testing we've added a setup to this repo that allows you to quickly setup an indy ledger. +To quickly set up all services needed to run tests (Postgres, Hyperledger Indy Ledger, and Cheqd Ledger), run the following command: ```sh -# Build indy pool -docker build -f network/indy-pool.dockerfile -t indy-pool . --platform linux/amd64 - -# NOTE: If you are on an ARM (M1) mac use the `network/indy-pool-arm.dockerfile` instead -# docker build -f network/indy-pool-arm.dockerfile -t indy-pool . --platform linux/arm64/v8 - -# Start indy pool -docker run -d --rm --name indy-pool -p 9701-9708:9701-9708 indy-pool - -# Setup CLI. This creates a wallet, connects to the ledger and sets the Transaction Author Agreement -docker exec indy-pool indy-cli-setup - -# DID and Verkey from seed. Set 'ENDORSER' role in order to be able to register public DIDs -docker exec indy-pool add-did-from-seed 00000000000000000000000Endorser9 ENDORSER - -# DID and Verkey from seed. Set 'Trustee' -docker exec indy-pool add-did-from-seed 000000000000000000000000Trustee9 TRUSTEE - -# If you want to register using the DID/Verkey you can use -# docker exec indy-pool add-did "NkGXDEPgpFGjQKMYmz6SyF" "CrSA1WbYYWLJoHm16Xw1VEeWxFvXtWjtsfEzMsjB5vDT" +docker compose up -d ``` -### Setup Cheqd Ledger - -In addition, there's also a docker command to run a cheqd test network. +If you're running on an ARM based machine (such as Apple Silicon), you can use the `docker-compose.arm.yml` file instead: ```sh -docker run --rm -d -p 26657:26657 ghcr.io/cheqd/cheqd-testnet:latest -``` - -If you want to run tests without the cheqd ledger, you can use the following ignore pattern: - -```sh -yarn test --testPathIgnorePatterns packages/cheqd +docker compose -f docker-compose.arm.yml up -d ``` ### Run all tests @@ -96,34 +44,17 @@ You can run the tests using the following command. yarn test ``` -If you're not using the ledger setup from above, make sure you pass the correct environment variables from [Setting environment variables](#setting-environment-variables) for connecting to the indy **ledger** pool. - -```sh -GENESIS_TXN_PATH=network/genesis/local-genesis.txn TEST_AGENT_PUBLIC_DID_SEED=000000000000000000000000Trustee9 ENDORSER_AGENT_PUBLIC_DID_SEED=00000000000000000000000Endorser9 yarn test -``` - -Locally, you might want to run the tests without postgres tests. You can do that by ignoring the tests: - -```sh -yarn test --testPathIgnorePatterns postgres.e2e.test.ts -``` - -In case you run into trouble running the tests, e.g. complaining about snapshots not being up-to-date, you can try and remove the data stored for the indy-client or Credo. Note this removes all wallets and data, so make sure you're okay with all data being removed. On a Unix system with default setup you achieve this by running: - -```sh -rm -rf ~/.indy-client ~/.afj -``` - -## Usage with Docker - -If you don't want to install the libindy dependencies yourself, or want a clean environment when running the framework or tests you can use docker. - -Make sure you followed the [local ledger setup](#setup-indy-ledger) to setup a local indy pool inside docker. +### Setting environment variables -```sh -# Builds the framework docker image with all dependencies installed -docker build -t credo . +If you're using the setup as described in this document, you don't need to provide any environment variables as the default will be sufficient. -# Run test with ledger pool -docker run -it --rm --network host credo yarn test -``` +- `GENESIS_TXN_PATH`: The path to the genesis transaction that allows us to connect to the indy pool. + - `GENESIS_TXN_PATH=network/genesis/local-genesis.txn` - default. Works with the [ledger setup](#setup-indy-ledger) from the previous step. + - `GENESIS_TXN_PATH=network/genesis/builder-net-genesis.txn` - Sovrin BuilderNet genesis. + - `GENESIS_TXN_PATH=/path/to/any/ledger/you/like` +- `TEST_AGENT_PUBLIC_DID_SEED`: The seed to use for the public DID. This will be used to do public write operations to the ledger. You should use a seed for a DID that is already registered on the ledger. + - If using the local or default genesis, use the same seed you used for the `add-did-from-seed` command from the [ledger setup](#setup-indy-ledger) in the previous step. (default is `000000000000000000000000Trustee9`) + - If using the BuilderNet genesis, make sure your seed is registered on the BuilderNet using [selfserve.sovrin.org](https://selfserve.sovrin.org/) and you have read and accepted the associated [Transaction Author Agreement](https://github.com/sovrin-foundation/sovrin/blob/master/TAA/TAA.md). We are not responsible for any unwanted consequences of using the BuilderNet. +- `ENDORSER_AGENT_PUBLIC_DID_SEED`: The seed to use for the public Endorser DID. This will be used to endorse transactions. You should use a seed for a DID that is already registered on the ledger. + - If using the local or default genesis, use the same seed you used for the `add-did-from-seed` command from the [ledger setup](#setup-indy-ledger) in the previous step. (default is `00000000000000000000000Endorser9`) + - If using the BuilderNet genesis, make sure your seed is registered on the BuilderNet using [selfserve.sovrin.org](https://selfserve.sovrin.org/) and you have read and accepted the associated [Transaction Author Agreement](https://github.com/sovrin-foundation/sovrin/blob/master/TAA/TAA.md). We are not responsible for any unwanted consequences of using the BuilderNet. diff --git a/Dockerfile b/Dockerfile index 5babd3d3da..83236c6e63 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,66 +1,4 @@ -## Stage 1: Build indy-sdk and postgres plugin - -FROM ubuntu:22.04 as base - -# Set this value only during build -ARG DEBIAN_FRONTEND noninteractive - -# Define packages to install -ENV PACKAGES software-properties-common ca-certificates \ - curl build-essential git \ - libzmq3-dev libsodium-dev pkg-config gnupg - -# Combined update and install to ensure Docker caching works correctly -RUN apt-get update -y \ - && apt-get install -y $PACKAGES - -RUN curl http://security.ubuntu.com/ubuntu/pool/main/o/openssl/libssl1.1_1.1.1-1ubuntu2.1~18.04.23_amd64.deb -o libssl1.1.deb \ - # libssl1.1 (required by libindy) - && dpkg -i libssl1.1.deb \ - && curl http://security.ubuntu.com/ubuntu/pool/main/o/openssl/libssl-dev_1.1.1-1ubuntu2.1~18.04.23_amd64.deb -o libssl-dev1.1.deb \ - # libssl-dev1.1 (required to compile libindy with posgres plugin) - && dpkg -i libssl-dev1.1.deb - -# Add APT sources -RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys CE7709D068DB5E88 \ - && add-apt-repository "deb https://repo.sovrin.org/sdk/deb bionic stable" \ - && mkdir -p /etc/apt/keyrings \ - && curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg \ - && echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_18.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list \ - && curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - \ - && echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list - -# Install libindy, NodeJS and yarn -RUN apt-get update -y \ - # Install libindy - && apt-get install -y --allow-unauthenticated libindy \ - && apt-get install -y nodejs \ - && apt-get install -y --no-install-recommends yarn \ - && rm -rf /var/lib/apt/lists/* \ - && apt-get clean -y - -# postgres plugin setup -# install rust and set up rustup -RUN curl https://sh.rustup.rs -sSf | bash -s -- -y -ENV PATH="/root/.cargo/bin:${PATH}" - -# cargo build failing on latest release of rust due to socket2 dependency in the plugin https://users.rust-lang.org/t/build-broken-with-parse-quote-spanned-is-ambiguous/80280/2 so pointing rust version to 1.63.0 -RUN rustup default 1.63.0 - -# clone indy-sdk and build postgres plugin -RUN git clone https://github.com/hyperledger/indy-sdk.git -WORKDIR /indy-sdk/experimental/plugins/postgres_storage/ -RUN cargo build --release - -# set up library path for postgres plugin -ENV LIB_INDY_STRG_POSTGRES="/indy-sdk/experimental/plugins/postgres_storage/target/release" - -## Stage 2: Build Credo - -FROM base as final - -# Set environment variables -ENV RUN_MODE="docker" +FROM node:18 # Set working directory WORKDIR /www @@ -71,3 +9,5 @@ COPY . . # Run yarn install and build RUN yarn install --frozen-lockfile \ && yarn build + +entrypoint ["yarn", "run-mediator"] \ No newline at end of file diff --git a/README.md b/README.md index 9a8c903932..0630435a30 100644 --- a/README.md +++ b/README.md @@ -90,15 +90,7 @@ Credo is a framework written in TypeScript for building **SSI Agents and DIDComm - @credo-ts/indy-sdk - - - @credo-ts/indy-sdk version - - - - - @credo-ts/indy-vdr + @aries-framework/indy-vdr @credo-ts/indy-vdr version @@ -168,6 +160,14 @@ Credo is a framework written in TypeScript for building **SSI Agents and DIDComm + + ~~@aries-framework/indy-sdk~~ (deprecated, unmaintained after 0.4.x) + + + @aries-framework/indy-sdk version + + + ## Getting Started diff --git a/TROUBLESHOOTING.md b/TROUBLESHOOTING.md deleted file mode 100644 index b34c8a40f9..0000000000 --- a/TROUBLESHOOTING.md +++ /dev/null @@ -1,85 +0,0 @@ -# Troubleshooting - -This document contains the most common errors that arise when first installing libindy and Credo. If you encounter a problem that is not listed here and manage to fix it, please open a PR describing the steps taken to resolve the issue. - -- [macOS](#macos) - - [Unable to find `libindy.dylib`](#unable-to-find-libindydylib) - - [Unable to find `libssl.1.0.0.dylib`](#unable-to-find-libssl100dylib) - - [Library not loaded: `libsodium.18.dylib`](#library-not-loaded-libsodium18dylib) - -## macOS - -### Unable to find `libindy.dylib` - -Installing Libindy on macOS can be tricky. If the the troubleshooting section of the NodeJS Wrapper documentation doesn't provide an answer and you're getting the following error: - -``` -dlopen(//credo/node_modules/indy-sdk/build/Release/indynodejs.node, 1): Library not loaded: /Users/jenkins/workspace/indy-sdk_indy-sdk-cd_master/libindy/target/release/deps/libindy.dylib - Referenced from: //credo/node_modules/indy-sdk/build/Release/indynodejs.node - Reason: image not found -``` - -See this StackOverflow answer: https://stackoverflow.com/questions/19776571/error-dlopen-library-not-loaded-reason-image-not-found - -The NodeJS Wrapper tries to find the library at the hardcoded CI built path `/Users/jenkins/workspace/indy-sdk_indy-sdk-cd_master/libindy/target/release/deps/libindy.dylib`. However the library will probably be located at `/usr/local/lib/libindy.dylib` (depending on how you installed libindy). - -To check where the NodeJS wrapper points to the static CI build path you can run: - -```bash -$ otool -L node_modules/indy-sdk/build/Release/indynodejs.node -node_modules/indy-sdk/build/Release/indynodejs.node: - /Users/jenkins/workspace/indy-sdk_indy-sdk-cd_master/libindy/target/release/deps/libindy.dylib (compatibility version 0.0.0, current version 0.0.0) - /usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 902.1.0) - /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1281.100.1) -``` - -You can manually change the path using the `install_name_tool`. Be sure change the path if you're not using the default. - -```bash -install_name_tool -change /Users/jenkins/workspace/indy-sdk_indy-sdk-cd_master/libindy/target/release/deps/libindy.dylib /usr/local/lib/libindy.dylib node_modules/indy-sdk/build/Release/indynodejs.node -``` - -### Unable to find `libssl.1.0.0.dylib` - -Libindy makes use of OpenSSL 1.0, however macOS by default has OpenSSL version 1.1. The standard brew repo also doesn't contain version 1.0 anymore. So if you're getting something that looks like the following error: - -``` -dlopen(//credo/node_modules/indy-sdk/build/Release/indynodejs.node, 1): Library not loaded: /usr/local/opt/openssl/lib/libssl.1.0.0.dylib - Referenced from: //libindy_1.15.0/lib/libindy.dylib - Reason: image not found -``` - -You can manually install OpenSSL 1.0 with the following Brew command: - -```sh -brew install https://raw.githubusercontent.com/Homebrew/homebrew-core/64555220bfbf4a25598523c2e4d3a232560eaad7/Formula/openssl.rb -f -``` - -In newer versions of HomeBrew installing packages is disabled, which will give an error that looks something like this: - -``` -Error: Calling Installation of openssl from a GitHub commit URL is disabled! Use 'brew extract openssl' to stable tap on GitHub instead. -``` - -They advise to use `brew extract` which also gives errors. The easiest way is to download the file and then extract it: - -```sh -curl https://raw.githubusercontent.com/Homebrew/homebrew-core/64555220bfbf4a25598523c2e4d3a232560eaad7/Formula/openssl.rb -o openssl.rb -brew install openssl.rb -``` - -### Library not loaded: `libsodium.18.dylib` - -When you install `libsodium` it automatically installs version 23. However libindy needs version 18. So if you're getting something that looks like the following error: - -``` -dyld: Library not loaded: /usr/local/opt/libsodium/lib/libsodium.18.dylib -``` - -You can manually link the path for version 18 to the path of version 23 with the following command: - -```sh -ln -s /usr/local/opt/libsodium/lib/libsodium.23.dylib /usr/local/opt/libsodium/lib/libsodium.18.dylib -``` - -Inspired by [this answer](https://github.com/Homebrew/homebrew-php/issues/4589) to the same error using php71-libsodium. diff --git a/demo/package.json b/demo/package.json index 0b3188e5b8..36028b4eef 100644 --- a/demo/package.json +++ b/demo/package.json @@ -24,12 +24,10 @@ "@credo-ts/anoncreds-rs": "*", "@credo-ts/askar": "*", "@credo-ts/core": "*", - "@credo-ts/indy-sdk": "*", "@credo-ts/indy-vdr": "*", "@credo-ts/cheqd": "*", "@credo-ts/node": "*", "@types/figlet": "^1.5.4", - "@types/indy-sdk": "^1.16.26", "@types/inquirer": "^8.2.6", "clear": "^0.1.0", "figlet": "^1.5.2", diff --git a/demo/src/Alice.ts b/demo/src/Alice.ts index f5fa2e48ce..ca50a0f50a 100644 --- a/demo/src/Alice.ts +++ b/demo/src/Alice.ts @@ -8,7 +8,7 @@ export class Alice extends BaseAgent { public connectionRecordFaberId?: string public constructor(port: number, name: string) { - super({ port, name, useLegacyIndySdk: true }) + super({ port, name }) this.connected = false } diff --git a/demo/src/BaseAgent.ts b/demo/src/BaseAgent.ts index 3be75da659..abd249fb6c 100644 --- a/demo/src/BaseAgent.ts +++ b/demo/src/BaseAgent.ts @@ -1,5 +1,4 @@ import type { InitConfig } from '@credo-ts/core' -import type { IndySdkPoolConfig } from '@credo-ts/indy-sdk' import type { IndyVdrPoolConfig } from '@credo-ts/indy-vdr' import { @@ -32,14 +31,11 @@ import { Agent, HttpOutboundTransport, } from '@credo-ts/core' -import { IndySdkAnonCredsRegistry, IndySdkModule, IndySdkSovDidResolver } from '@credo-ts/indy-sdk' import { IndyVdrIndyDidResolver, IndyVdrAnonCredsRegistry, IndyVdrModule } from '@credo-ts/indy-vdr' import { agentDependencies, HttpInboundTransport } from '@credo-ts/node' import { anoncreds } from '@hyperledger/anoncreds-nodejs' import { ariesAskar } from '@hyperledger/aries-askar-nodejs' import { indyVdr } from '@hyperledger/indy-vdr-nodejs' -import { randomUUID } from 'crypto' -import indySdk from 'indy-sdk' import { greenText } from './OutputClass' @@ -49,13 +45,11 @@ const bcovrin = `{"reqSignature":{},"txn":{"data":{"data":{"alias":"Node1","blsk {"reqSignature":{},"txn":{"data":{"data":{"alias":"Node4","blskey":"2zN3bHM1m4rLz54MJHYSwvqzPchYp8jkHswveCLAEJVcX6Mm1wHQD1SkPYMzUDTZvWvhuE6VNAkK3KxVeEmsanSmvjVkReDeBEMxeDaayjcZjFGPydyey1qxBHmTvAnBKoPydvuTAqx5f7YNNRAdeLmUi99gERUU7TD8KfAa6MpQ9bw","blskey_pop":"RPLagxaR5xdimFzwmzYnz4ZhWtYQEj8iR5ZU53T2gitPCyCHQneUn2Huc4oeLd2B2HzkGnjAff4hWTJT6C7qHYB1Mv2wU5iHHGFWkhnTX9WsEAbunJCV2qcaXScKj4tTfvdDKfLiVuU2av6hbsMztirRze7LvYBkRHV3tGwyCptsrP","client_ip":"138.197.138.255","client_port":9708,"node_ip":"138.197.138.255","node_port":9707,"services":["VALIDATOR"]},"dest":"4PS3EDQ3dW1tci1Bp6543CfuuebjFrg36kLAUcskGfaA"},"metadata":{"from":"TWwCRQRZ2ZHMJFn9TzLp7W"},"type":"0"},"txnMetadata":{"seqNo":4,"txnId":"aa5e817d7cc626170eca175822029339a444eb0ee8f0bd20d3b0b76e566fb008"},"ver":"1"}` export const indyNetworkConfig = { - // Need unique network id as we will have multiple agent processes in the agent - id: randomUUID(), genesisTransactions: bcovrin, indyNamespace: 'bcovrin:test', isProduction: false, connectOnStartup: true, -} satisfies IndySdkPoolConfig | IndyVdrPoolConfig +} satisfies IndyVdrPoolConfig type DemoAgent = Agent> @@ -64,17 +58,8 @@ export class BaseAgent { public name: string public config: InitConfig public agent: DemoAgent - public useLegacyIndySdk: boolean - public constructor({ - port, - name, - useLegacyIndySdk = false, - }: { - port: number - name: string - useLegacyIndySdk?: boolean - }) { + public constructor({ port, name }: { port: number; name: string }) { this.name = name this.port = port @@ -89,8 +74,6 @@ export class BaseAgent { this.config = config - this.useLegacyIndySdk = useLegacyIndySdk - this.agent = new Agent({ config, dependencies: agentDependencies, @@ -167,46 +150,3 @@ function getAskarAnonCredsIndyModules() { }), } as const } - -function getLegacyIndySdkModules() { - const legacyIndyCredentialFormatService = new LegacyIndyCredentialFormatService() - const legacyIndyProofFormatService = new LegacyIndyProofFormatService() - - return { - connections: new ConnectionsModule({ - autoAcceptConnections: true, - }), - credentials: new CredentialsModule({ - autoAcceptCredentials: AutoAcceptCredential.ContentApproved, - credentialProtocols: [ - new V1CredentialProtocol({ - indyCredentialFormat: legacyIndyCredentialFormatService, - }), - new V2CredentialProtocol({ - credentialFormats: [legacyIndyCredentialFormatService], - }), - ], - }), - proofs: new ProofsModule({ - autoAcceptProofs: AutoAcceptProof.ContentApproved, - proofProtocols: [ - new V1ProofProtocol({ - indyProofFormat: legacyIndyProofFormatService, - }), - new V2ProofProtocol({ - proofFormats: [legacyIndyProofFormatService], - }), - ], - }), - anoncreds: new AnonCredsModule({ - registries: [new IndySdkAnonCredsRegistry()], - }), - indySdk: new IndySdkModule({ - indySdk, - networks: [indyNetworkConfig], - }), - dids: new DidsModule({ - resolvers: [new IndySdkSovDidResolver()], - }), - } as const -} diff --git a/demo/src/Faber.ts b/demo/src/Faber.ts index d9ee218209..5f3542b803 100644 --- a/demo/src/Faber.ts +++ b/demo/src/Faber.ts @@ -21,7 +21,7 @@ export class Faber extends BaseAgent { public ui: BottomBar public constructor(port: number, name: string) { - super({ port, name, useLegacyIndySdk: true }) + super({ port, name }) this.ui = new ui.BottomBar() } diff --git a/docker-compose.arm.yml b/docker-compose.arm.yml new file mode 100644 index 0000000000..263f77baf2 --- /dev/null +++ b/docker-compose.arm.yml @@ -0,0 +1,32 @@ +version: '3' +services: + postgres: + image: postgres:15-alpine + environment: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + ports: + - '5432:5432' + + indy-pool: + build: + context: . + dockerfile: network/indy-pool-arm.dockerfile + platform: linux/arm64/v8 + ports: + - '9701-9708:9701-9708' + # Start supervisord in bg, run commands, bring supervisor to fg + command: > + /bin/bash -c " + /usr/bin/supervisord & + indy-cli-setup && + add-did-from-seed 00000000000000000000000Endorser9 ENDORSER && + add-did-from-seed 000000000000000000000000Trustee9 TRUSTEE && + /usr/bin/supervisord -n + " + + cheqd-ledger: + image: ghcr.io/cheqd/cheqd-testnet:latest + platform: linux/amd64 + ports: + - '26657:26657' diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000000..f7dea20d37 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,31 @@ +version: '3' +services: + postgres: + image: postgres:15-alpine + environment: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + ports: + - '5432:5432' + + indy-pool: + build: + context: . + dockerfile: network/indy-pool.dockerfile + ports: + - '9701-9708:9701-9708' + # Start supervisord in bg, run commands, bring supervisor to fg + command: > + /bin/bash -c " + /usr/bin/supervisord & + indy-cli-setup && + add-did-from-seed 00000000000000000000000Endorser9 ENDORSER && + add-did-from-seed 000000000000000000000000Trustee9 TRUSTEE && + /usr/bin/supervisord -n + " + + cheqd-ledger: + image: ghcr.io/cheqd/cheqd-testnet:latest + platform: linux/amd64 + ports: + - '26657:26657' diff --git a/docker/docker-compose-mediators-ngrok.yml b/docker/docker-compose-mediators-ngrok.yml deleted file mode 100644 index 36c5899b36..0000000000 --- a/docker/docker-compose-mediators-ngrok.yml +++ /dev/null @@ -1,19 +0,0 @@ -version: '3' - -# This file extends docker-compose-mediators.yml - -services: - mediator: - environment: - NGROK_NAME: mediator-ngrok - entrypoint: ./scripts/ngrok-wait.sh - depends_on: [mediator-ngrok] - - mediator-ngrok: - image: wernight/ngrok - command: ngrok http -bind-tls=true --log stdout mediator:3001 - networks: - - hyperledger - -networks: - hyperledger: diff --git a/docker/docker-compose-mediators.yml b/docker/docker-compose-mediators.yml deleted file mode 100644 index 372d682563..0000000000 --- a/docker/docker-compose-mediators.yml +++ /dev/null @@ -1,16 +0,0 @@ -version: '3' - -services: - mediator: - build: .. - image: credo - container_name: credo-mediator - command: yarn run-mediator - platform: linux/amd64 - networks: - - hyperledger - ports: - - 3001:3001 - -networks: - hyperledger: diff --git a/package.json b/package.json index 1568d37c90..30e910f3ba 100644 --- a/package.json +++ b/package.json @@ -28,16 +28,18 @@ }, "devDependencies": { "@hyperledger/aries-askar-nodejs": "^0.2.0-dev.5", + "@types/bn.js": "^5.1.5", "@types/cors": "^2.8.10", "@types/eslint": "^8.21.2", "@types/express": "^4.17.13", - "@types/jest": "^29.5.5", + "@types/jest": "^29.5.11", "@types/node": "^18.18.8", "@types/uuid": "^9.0.1", "@types/varint": "^6.0.0", "@types/ws": "^8.5.4", "@typescript-eslint/eslint-plugin": "^5.48.1", "@typescript-eslint/parser": "^5.48.1", + "bn.js": "^5.2.1", "conventional-changelog-conventionalcommits": "^5.0.0", "conventional-recommended-bump": "^6.1.0", "cors": "^2.8.5", @@ -48,12 +50,11 @@ "eslint-plugin-prettier": "^4.2.1", "eslint-plugin-workspaces": "^0.8.0", "express": "^4.17.1", - "indy-sdk": "^1.16.0-dev-1655", "jest": "^29.7.0", "lerna": "^6.5.1", "prettier": "^2.3.1", "rxjs": "^7.8.0", - "ts-jest": "^29.0.5", + "ts-jest": "^29.1.2", "ts-node": "^10.0.0", "tsconfig-paths": "^4.1.2", "tsyringe": "^4.8.0", diff --git a/packages/action-menu/tests/action-menu.e2e.test.ts b/packages/action-menu/tests/action-menu.e2e.test.ts index 425a3f15ee..134887830c 100644 --- a/packages/action-menu/tests/action-menu.e2e.test.ts +++ b/packages/action-menu/tests/action-menu.e2e.test.ts @@ -2,8 +2,7 @@ import type { ConnectionRecord } from '@credo-ts/core' import { Agent } from '@credo-ts/core' -import { getAgentOptions, makeConnection, testLogger, setupSubjectTransports, indySdk } from '../../core/tests' -import { IndySdkModule } from '../../indy-sdk/src' +import { makeConnection, testLogger, setupSubjectTransports, getInMemoryAgentOptions } from '../../core/tests' import { waitForActionMenuRecord } from './helpers' @@ -11,12 +10,9 @@ import { ActionMenu, ActionMenuModule, ActionMenuRecord, ActionMenuRole, ActionM const modules = { actionMenu: new ActionMenuModule(), - indySdk: new IndySdkModule({ - indySdk, - }), } -const faberAgentOptions = getAgentOptions( +const faberAgentOptions = getInMemoryAgentOptions( 'Faber Action Menu', { endpoints: ['rxjs:faber'], @@ -24,7 +20,7 @@ const faberAgentOptions = getAgentOptions( modules ) -const aliceAgentOptions = getAgentOptions( +const aliceAgentOptions = getInMemoryAgentOptions( 'Alice Action Menu', { endpoints: ['rxjs:alice'], diff --git a/packages/anoncreds-rs/src/AnonCredsRsModule.ts b/packages/anoncreds-rs/src/AnonCredsRsModule.ts index d2abdbcb73..5e78a2238f 100644 --- a/packages/anoncreds-rs/src/AnonCredsRsModule.ts +++ b/packages/anoncreds-rs/src/AnonCredsRsModule.ts @@ -23,7 +23,7 @@ export class AnonCredsRsModule implements Module { dependencyManager .resolve(AgentConfig) .logger.warn( - "The '@credo-ts/anoncreds-rs' module is experimental and could have unexpected breaking changes. When using this module, make sure to use strict versions for all @aries-framework packages." + "The '@credo-ts/anoncreds-rs' module is experimental and could have unexpected breaking changes. When using this module, make sure to use strict versions for all @credo-ts packages." ) dependencyManager.registerInstance(AnonCredsRsModuleConfig, this.config) diff --git a/packages/anoncreds-rs/src/index.ts b/packages/anoncreds-rs/src/index.ts index 5fdd9486c7..952884c8c5 100644 --- a/packages/anoncreds-rs/src/index.ts +++ b/packages/anoncreds-rs/src/index.ts @@ -3,3 +3,4 @@ export * from './services' // Module export { AnonCredsRsModule } from './AnonCredsRsModule' +export { AnonCredsRsModuleConfig } from './AnonCredsRsModuleConfig' diff --git a/packages/anoncreds-rs/src/services/AnonCredsRsHolderService.ts b/packages/anoncreds-rs/src/services/AnonCredsRsHolderService.ts index 1408aa9ae8..bd5643f7c3 100644 --- a/packages/anoncreds-rs/src/services/AnonCredsRsHolderService.ts +++ b/packages/anoncreds-rs/src/services/AnonCredsRsHolderService.ts @@ -317,8 +317,8 @@ export class AnonCredsRsHolderService implements AnonCredsHolderService { credentialDefinitionId: credentialRecord.credential.cred_def_id, credentialId: credentialRecord.credentialId, schemaId: credentialRecord.credential.schema_id, - credentialRevocationId: credentialRecord.credentialRevocationId, - revocationRegistryId: credentialRecord.credential.rev_reg_id, + credentialRevocationId: credentialRecord.credentialRevocationId ?? null, + revocationRegistryId: credentialRecord.credential.rev_reg_id ?? null, methodName: credentialRecord.methodName, } } @@ -346,8 +346,8 @@ export class AnonCredsRsHolderService implements AnonCredsHolderService { credentialDefinitionId: credentialRecord.credential.cred_def_id, credentialId: credentialRecord.credentialId, schemaId: credentialRecord.credential.schema_id, - credentialRevocationId: credentialRecord.credentialRevocationId, - revocationRegistryId: credentialRecord.credential.rev_reg_id, + credentialRevocationId: credentialRecord.credentialRevocationId ?? null, + revocationRegistryId: credentialRecord.credential.rev_reg_id ?? null, methodName: credentialRecord.methodName, })) } @@ -412,8 +412,8 @@ export class AnonCredsRsHolderService implements AnonCredsHolderService { credentialDefinitionId: credentialRecord.credential.cred_def_id, credentialId: credentialRecord.credentialId, schemaId: credentialRecord.credential.schema_id, - credentialRevocationId: credentialRecord.credentialRevocationId, - revocationRegistryId: credentialRecord.credential.rev_reg_id, + credentialRevocationId: credentialRecord.credentialRevocationId ?? null, + revocationRegistryId: credentialRecord.credential.rev_reg_id ?? null, methodName: credentialRecord.methodName, }, interval: proofRequest.non_revoked, diff --git a/packages/anoncreds-rs/src/services/__tests__/AnonCredsRsServices.test.ts b/packages/anoncreds-rs/src/services/__tests__/AnonCredsRsServices.test.ts index 5f86d08b46..f23ff1f230 100644 --- a/packages/anoncreds-rs/src/services/__tests__/AnonCredsRsServices.test.ts +++ b/packages/anoncreds-rs/src/services/__tests__/AnonCredsRsServices.test.ts @@ -25,6 +25,7 @@ import { anoncreds } from '@hyperledger/anoncreds-nodejs' import { Subject } from 'rxjs' import { InMemoryStorageService } from '../../../../../tests/InMemoryStorageService' +import { InMemoryWallet } from '../../../../../tests/InMemoryWallet' import { encodeCredentialValue } from '../../../../anoncreds/src/utils/credential' import { InMemoryAnonCredsRegistry } from '../../../../anoncreds/tests/InMemoryAnonCredsRegistry' import { agentDependencies, getAgentConfig, getAgentContext } from '../../../../core/tests/helpers' @@ -37,9 +38,11 @@ const anonCredsVerifierService = new AnonCredsRsVerifierService() const anonCredsHolderService = new AnonCredsRsHolderService() const anonCredsIssuerService = new AnonCredsRsIssuerService() const storageService = new InMemoryStorageService() +const wallet = new InMemoryWallet() const registry = new InMemoryAnonCredsRegistry() const agentContext = getAgentContext({ + wallet, registerInstances: [ [InjectionSymbols.Stop$, new Subject()], [InjectionSymbols.AgentDependencies, agentDependencies], @@ -190,7 +193,7 @@ describe('AnonCredsRsServices', () => { schemaId: schemaState.schemaId, credentialDefinitionId: credentialDefinitionState.credentialDefinitionId, revocationRegistryId: null, - credentialRevocationId: undefined, // Should it be null in this case? + credentialRevocationId: null, methodName: 'inMemory', }) @@ -398,7 +401,7 @@ describe('AnonCredsRsServices', () => { schemaId: unqualifiedSchemaId, credentialDefinitionId: unqualifiedCredentialDefinitionId, revocationRegistryId: null, - credentialRevocationId: undefined, // Should it be null in this case? + credentialRevocationId: null, methodName: 'inMemory', }) diff --git a/packages/anoncreds-rs/src/services/__tests__/helpers.ts b/packages/anoncreds-rs/src/services/__tests__/helpers.ts index 16b8fb1a79..e1eaffb115 100644 --- a/packages/anoncreds-rs/src/services/__tests__/helpers.ts +++ b/packages/anoncreds-rs/src/services/__tests__/helpers.ts @@ -160,6 +160,8 @@ export function createCredentialForHolder(options: { credentialId, schemaId, methodName: 'inMemory', + credentialRevocationId: null, + revocationRegistryId: null, } const returnObj = { credential: credentialObj.toJson() as unknown as AnonCredsCredential, diff --git a/packages/anoncreds-rs/tests/anoncreds-flow.test.ts b/packages/anoncreds-rs/tests/anoncreds-flow.test.ts index 288c610110..4f4dece3c0 100644 --- a/packages/anoncreds-rs/tests/anoncreds-flow.test.ts +++ b/packages/anoncreds-rs/tests/anoncreds-flow.test.ts @@ -83,7 +83,7 @@ const indyDid = 'did:indy:local:LjgpST2rjsoxYegQDRm7EL' describe('AnonCreds format services using anoncreds-rs', () => { afterEach(() => { - inMemoryStorageService.records = {} + inMemoryStorageService.contextCorrelationIdToRecords = {} }) test('issuance and verification flow starting from proposal without negotiation and without revocation', async () => { @@ -355,7 +355,7 @@ async function anonCredsFlowTest(options: { issuerId: string; revocable: boolean schemaId: schemaState.schemaId, credentialDefinitionId: credentialDefinitionState.credentialDefinitionId, revocationRegistryId: revocable ? revocationRegistryDefinitionId : null, - credentialRevocationId: revocable ? '1' : undefined, + credentialRevocationId: revocable ? '1' : null, methodName: 'inMemory', }) diff --git a/packages/anoncreds-rs/tests/anoncredsSetup.ts b/packages/anoncreds-rs/tests/anoncredsSetup.ts index e82b043351..aff1d1ccca 100644 --- a/packages/anoncreds-rs/tests/anoncredsSetup.ts +++ b/packages/anoncreds-rs/tests/anoncredsSetup.ts @@ -37,12 +37,10 @@ import { randomUUID } from 'crypto' import { AnonCredsCredentialFormatService, AnonCredsProofFormatService, AnonCredsModule } from '../../anoncreds/src' import { InMemoryAnonCredsRegistry } from '../../anoncreds/tests/InMemoryAnonCredsRegistry' -import { AskarModule } from '../../askar/src' -import { askarModuleConfig } from '../../askar/tests/helpers' import { sleep } from '../../core/src/utils/sleep' import { setupSubjectTransports, setupEventReplaySubjects } from '../../core/tests' import { - getAgentOptions, + getInMemoryAgentOptions, makeConnection, waitForCredentialRecordSubject, waitForProofExchangeRecordSubject, @@ -55,6 +53,7 @@ import { LocalDidResolver } from './LocalDidResolver' // Helper type to get the type of the agents (with the custom modules) for the credential tests export type AnonCredsTestsAgent = Agent< + // eslint-disable-next-line @typescript-eslint/no-explicit-any ReturnType & { mediationRecipient?: any; mediator?: any } > @@ -97,7 +96,6 @@ export const getAnonCredsModules = ({ dids: new DidsModule({ resolvers: [new LocalDidResolver()], }), - askar: new AskarModule(askarModuleConfig), cache: new CacheModule({ cache: new InMemoryLruCache({ limit: 100 }), }), @@ -201,7 +199,7 @@ export async function issueAnonCredsCredential({ holderReplay: EventReplaySubject issuerHolderConnectionId: string - revocationRegistryDefinitionId?: string + revocationRegistryDefinitionId: string | null offer: AnonCredsOfferCredentialFormat }) { let issuerCredentialExchangeRecord = await issuerAgent.credentials.offerCredential({ @@ -209,7 +207,11 @@ export async function issueAnonCredsCredential({ connectionId: issuerHolderConnectionId, protocolVersion: 'v2', credentialFormats: { - anoncreds: { ...offer, revocationRegistryDefinitionId, revocationRegistryIndex: 1 }, + anoncreds: { + ...offer, + revocationRegistryDefinitionId: revocationRegistryDefinitionId ?? undefined, + revocationRegistryIndex: 1, + }, }, autoAcceptCredential: AutoAcceptCredential.ContentApproved, }) @@ -267,7 +269,7 @@ interface SetupAnonCredsTestsReturn> { const issuerAgent = new Agent( - getAgentOptions( + getInMemoryAgentOptions( issuerName, { endpoints: ['rxjs:issuer'], @@ -312,7 +314,7 @@ export async function setupAnonCredsTests< ) const holderAgent = new Agent( - getAgentOptions( + getInMemoryAgentOptions( holderName, { endpoints: ['rxjs:holder'], @@ -327,7 +329,7 @@ export async function setupAnonCredsTests< const verifierAgent = verifierName ? new Agent( - getAgentOptions( + getInMemoryAgentOptions( verifierName, { endpoints: ['rxjs:verifier'], diff --git a/packages/anoncreds-rs/tests/indy-flow.test.ts b/packages/anoncreds-rs/tests/indy-flow.test.ts index a8f0c65966..d080620255 100644 --- a/packages/anoncreds-rs/tests/indy-flow.test.ts +++ b/packages/anoncreds-rs/tests/indy-flow.test.ts @@ -285,7 +285,7 @@ describe('Legacy indy format services using anoncreds-rs', () => { schemaId: unqualifiedSchemaId, credentialDefinitionId: unqualifiedCredentialDefinitionId, revocationRegistryId: null, - credentialRevocationId: undefined, // FIXME: should be null? + credentialRevocationId: null, methodName: 'inMemory', }) diff --git a/packages/anoncreds-rs/tests/v2-credential-revocation.e2e.test.ts b/packages/anoncreds-rs/tests/v2-credential-revocation.e2e.test.ts index ff9381c0b1..ee335955ea 100644 --- a/packages/anoncreds-rs/tests/v2-credential-revocation.e2e.test.ts +++ b/packages/anoncreds-rs/tests/v2-credential-revocation.e2e.test.ts @@ -28,7 +28,7 @@ describe('IC v2 credential revocation', () => { let faberAgent: AnonCredsTestsAgent let aliceAgent: AnonCredsTestsAgent let credentialDefinitionId: string - let revocationRegistryDefinitionId: string | undefined + let revocationRegistryDefinitionId: string | null let aliceConnectionId: string let faberReplay: EventReplaySubject @@ -105,7 +105,7 @@ describe('IC v2 credential revocation', () => { anoncreds: { credentialDefinitionId: credentialDefinitionId, attributes: credentialPreview.attributes, - revocationRegistryDefinitionId, + revocationRegistryDefinitionId: revocationRegistryDefinitionId ?? undefined, revocationRegistryIndex: 1, }, }, diff --git a/packages/anoncreds-rs/tests/v2-credentials.e2e.test.ts b/packages/anoncreds-rs/tests/v2-credentials.e2e.test.ts index 6739004d50..ba0e70a692 100644 --- a/packages/anoncreds-rs/tests/v2-credentials.e2e.test.ts +++ b/packages/anoncreds-rs/tests/v2-credentials.e2e.test.ts @@ -239,6 +239,7 @@ describe('IC V2 AnonCreds credentials', () => { credentialDefinitionId: credentialDefinitionId, attributes: credentialPreview.attributes, }, + revocationRegistryDefinitionId: null, }) // test that delete credential removes from both repository and wallet diff --git a/packages/anoncreds-rs/tests/v2-proofs.e2e.test.ts b/packages/anoncreds-rs/tests/v2-proofs.e2e.test.ts index 97e5338765..aff906251b 100644 --- a/packages/anoncreds-rs/tests/v2-proofs.e2e.test.ts +++ b/packages/anoncreds-rs/tests/v2-proofs.e2e.test.ts @@ -28,7 +28,7 @@ describe('PP V2 AnonCreds Proofs', () => { let aliceAgent: AnonCredsTestsAgent let aliceReplay: EventReplaySubject let credentialDefinitionId: string - let revocationRegistryDefinitionId: string | undefined + let revocationRegistryDefinitionId: string | null let aliceConnectionId: string let faberConnectionId: string let faberProofExchangeRecord: ProofExchangeRecord diff --git a/packages/anoncreds/package.json b/packages/anoncreds/package.json index be387c9823..3112fa7f1a 100644 --- a/packages/anoncreds/package.json +++ b/packages/anoncreds/package.json @@ -32,7 +32,6 @@ }, "devDependencies": { "@credo-ts/node": "0.4.2", - "indy-sdk": "^1.16.0-dev-1636", "rimraf": "^4.4.0", "rxjs": "^7.8.0", "typescript": "~4.9.5" diff --git a/packages/anoncreds/src/AnonCredsApi.ts b/packages/anoncreds/src/AnonCredsApi.ts index d0b0cc1d6b..6f729de76f 100644 --- a/packages/anoncreds/src/AnonCredsApi.ts +++ b/packages/anoncreds/src/AnonCredsApi.ts @@ -278,6 +278,8 @@ export class AnonCredsApi { supportRevocation: options.options.supportRevocation, schema: schemaResult.schema, }, + // NOTE: indy-sdk support has been removed from main repo, but keeping + // this in place to allow the indy-sdk to still be used as a custom package for some time // FIXME: Indy SDK requires the schema seq no to be passed in here. This is not ideal. { indyLedgerSchemaSeqNo: schemaResult.schemaMetadata.indyLedgerSeqNo, diff --git a/packages/anoncreds/src/formats/AnonCredsCredentialFormatService.ts b/packages/anoncreds/src/formats/AnonCredsCredentialFormatService.ts index 534c1956cb..a63a6bd0a2 100644 --- a/packages/anoncreds/src/formats/AnonCredsCredentialFormatService.ts +++ b/packages/anoncreds/src/formats/AnonCredsCredentialFormatService.ts @@ -468,8 +468,8 @@ export class AnonCredsCredentialFormatService implements CredentialFormatService const credential = await anonCredsHolderService.getCredential(agentContext, { credentialId }) credentialRecord.metadata.add(AnonCredsCredentialMetadataKey, { - credentialRevocationId: credential.credentialRevocationId, - revocationRegistryId: credential.revocationRegistryId, + credentialRevocationId: credential.credentialRevocationId ?? undefined, + revocationRegistryId: credential.revocationRegistryId ?? undefined, }) credentialRecord.setTags({ anonCredsRevocationRegistryId: credential.revocationRegistryId, diff --git a/packages/anoncreds/src/formats/LegacyIndyCredentialFormatService.ts b/packages/anoncreds/src/formats/LegacyIndyCredentialFormatService.ts index 5ed540cfb8..dd53ce16c3 100644 --- a/packages/anoncreds/src/formats/LegacyIndyCredentialFormatService.ts +++ b/packages/anoncreds/src/formats/LegacyIndyCredentialFormatService.ts @@ -434,8 +434,8 @@ export class LegacyIndyCredentialFormatService implements CredentialFormatServic const credential = await anonCredsHolderService.getCredential(agentContext, { credentialId }) credentialRecord.metadata.add(AnonCredsCredentialMetadataKey, { - credentialRevocationId: credential.credentialRevocationId, - revocationRegistryId: credential.revocationRegistryId, + credentialRevocationId: credential.credentialRevocationId ?? undefined, + revocationRegistryId: credential.revocationRegistryId ?? undefined, }) credentialRecord.setTags({ anonCredsRevocationRegistryId: credential.revocationRegistryId, diff --git a/packages/anoncreds/src/formats/__tests__/legacy-indy-format-services.test.ts b/packages/anoncreds/src/formats/__tests__/legacy-indy-format-services.test.ts index d3047c7403..ecda92dcb8 100644 --- a/packages/anoncreds/src/formats/__tests__/legacy-indy-format-services.test.ts +++ b/packages/anoncreds/src/formats/__tests__/legacy-indy-format-services.test.ts @@ -3,30 +3,39 @@ import type { AnonCredsCredentialRequest } from '../../models' import { CredentialState, CredentialExchangeRecord, - SigningProviderRegistry, KeyType, CredentialPreviewAttribute, ProofExchangeRecord, ProofState, EventEmitter, + InjectionSymbols, } from '@credo-ts/core' -import * as indySdk from 'indy-sdk' import { Subject } from 'rxjs' -import { agentDependencies, getAgentConfig, getAgentContext } from '../../../../core/tests/helpers' +import { InMemoryStorageService } from '../../../../../tests/InMemoryStorageService' +import { InMemoryWallet } from '../../../../../tests/InMemoryWallet' import { - IndySdkHolderService, - IndySdkIssuerService, - IndySdkModuleConfig, - IndySdkStorageService, - IndySdkVerifierService, - IndySdkWallet, -} from '../../../../indy-sdk/src' -import { IndySdkRevocationService } from '../../../../indy-sdk/src/anoncreds/services/IndySdkRevocationService' -import { legacyIndyDidFromPublicKeyBase58 } from '../../../../indy-sdk/src/utils/did' + AnonCredsRsHolderService, + AnonCredsRsIssuerService, + AnonCredsRsModuleConfig, + AnonCredsRsVerifierService, +} from '../../../../anoncreds-rs/src' +import { anoncreds } from '../../../../anoncreds-rs/tests/helpers' +import { indyDidFromPublicKeyBase58 } from '../../../../core/src/utils/did' +import { agentDependencies, getAgentConfig, getAgentContext } from '../../../../core/tests/helpers' import { InMemoryAnonCredsRegistry } from '../../../tests/InMemoryAnonCredsRegistry' import { AnonCredsModuleConfig } from '../../AnonCredsModuleConfig' -import { AnonCredsLinkSecretRecord, AnonCredsLinkSecretRepository } from '../../repository' +import { + AnonCredsCredentialDefinitionPrivateRecord, + AnonCredsCredentialDefinitionPrivateRepository, + AnonCredsCredentialDefinitionRecord, + AnonCredsCredentialDefinitionRepository, + AnonCredsCredentialRepository, + AnonCredsKeyCorrectnessProofRecord, + AnonCredsKeyCorrectnessProofRepository, + AnonCredsLinkSecretRecord, + AnonCredsLinkSecretRepository, +} from '../../repository' import { AnonCredsHolderServiceSymbol, AnonCredsIssuerServiceSymbol, @@ -48,14 +57,24 @@ const anonCredsModuleConfig = new AnonCredsModuleConfig({ }) const agentConfig = getAgentConfig('LegacyIndyFormatServicesTest') -const anonCredsRevocationService = new IndySdkRevocationService(indySdk) -const anonCredsVerifierService = new IndySdkVerifierService(indySdk) -const anonCredsHolderService = new IndySdkHolderService(anonCredsRevocationService, indySdk) -const anonCredsIssuerService = new IndySdkIssuerService(indySdk) -const wallet = new IndySdkWallet(indySdk, agentConfig.logger, new SigningProviderRegistry([])) -const storageService = new IndySdkStorageService(indySdk) +const anonCredsVerifierService = new AnonCredsRsVerifierService() +const anonCredsHolderService = new AnonCredsRsHolderService() +const anonCredsIssuerService = new AnonCredsRsIssuerService() +const wallet = new InMemoryWallet() +// eslint-disable-next-line @typescript-eslint/no-explicit-any +const storageService = new InMemoryStorageService() const eventEmitter = new EventEmitter(agentDependencies, new Subject()) const anonCredsLinkSecretRepository = new AnonCredsLinkSecretRepository(storageService, eventEmitter) +const anonCredsCredentialDefinitionRepository = new AnonCredsCredentialDefinitionRepository( + storageService, + eventEmitter +) +const anonCredsCredentialDefinitionPrivateRepository = new AnonCredsCredentialDefinitionPrivateRepository( + storageService, + eventEmitter +) +const anonCredsCredentialRepository = new AnonCredsCredentialRepository(storageService, eventEmitter) +const anonCredsKeyCorrectnessProofRepository = new AnonCredsKeyCorrectnessProofRepository(storageService, eventEmitter) const agentContext = getAgentContext({ registerInstances: [ [AnonCredsIssuerServiceSymbol, anonCredsIssuerService], @@ -64,7 +83,18 @@ const agentContext = getAgentContext({ [AnonCredsRegistryService, new AnonCredsRegistryService()], [AnonCredsModuleConfig, anonCredsModuleConfig], [AnonCredsLinkSecretRepository, anonCredsLinkSecretRepository], - [IndySdkModuleConfig, new IndySdkModuleConfig({ indySdk, autoCreateLinkSecret: false })], + [AnonCredsCredentialDefinitionRepository, anonCredsCredentialDefinitionRepository], + [AnonCredsCredentialDefinitionPrivateRepository, anonCredsCredentialDefinitionPrivateRepository], + [AnonCredsCredentialRepository, anonCredsCredentialRepository], + [AnonCredsKeyCorrectnessProofRepository, anonCredsKeyCorrectnessProofRepository], + [InjectionSymbols.StorageService, storageService], + [ + AnonCredsRsModuleConfig, + new AnonCredsRsModuleConfig({ + anoncreds, + autoCreateLinkSecret: false, + }), + ], ], agentConfig, wallet, @@ -87,15 +117,16 @@ describe('Legacy indy format services', () => { test('issuance and verification flow starting from proposal without negotiation and without revocation', async () => { // This is just so we don't have to register an actual indy did (as we don't have the indy did registrar configured) const key = await wallet.createKey({ keyType: KeyType.Ed25519 }) - const unqualifiedIndyDid = legacyIndyDidFromPublicKeyBase58(key.publicKeyBase58) + const unqualifiedIndyDid = indyDidFromPublicKeyBase58(key.publicKeyBase58) const indyDid = `did:indy:pool1:${unqualifiedIndyDid}` // Create link secret - await anonCredsHolderService.createLinkSecret(agentContext, { + const { linkSecretValue } = await anonCredsHolderService.createLinkSecret(agentContext, { linkSecretId: 'link-secret-id', }) const anonCredsLinkSecret = new AnonCredsLinkSecretRecord({ linkSecretId: 'link-secret-id', + value: linkSecretValue, }) anonCredsLinkSecret.setTag('isDefault', true) await anonCredsLinkSecretRepository.save(agentContext, anonCredsLinkSecret) @@ -107,25 +138,19 @@ describe('Legacy indy format services', () => { version: '1.0.0', }) - const { schemaState, schemaMetadata } = await registry.registerSchema(agentContext, { + const { schemaState } = await registry.registerSchema(agentContext, { schema, options: {}, }) - const { credentialDefinition } = await anonCredsIssuerService.createCredentialDefinition( - agentContext, - { + const { credentialDefinition, credentialDefinitionPrivate, keyCorrectnessProof } = + await anonCredsIssuerService.createCredentialDefinition(agentContext, { issuerId: indyDid, schemaId: schemaState.schemaId as string, schema, tag: 'Employee Credential', supportRevocation: false, - }, - { - // Need to pass this as the indy-sdk MUST have the seqNo - indyLedgerSchemaSeqNo: schemaMetadata.indyLedgerSeqNo as number, - } - ) + }) const { credentialDefinitionState } = await registry.registerCredentialDefinition(agentContext, { credentialDefinition, @@ -141,6 +166,35 @@ describe('Legacy indy format services', () => { throw new Error('Failed to create schema or credential definition') } + await anonCredsCredentialDefinitionRepository.save( + agentContext, + new AnonCredsCredentialDefinitionRecord({ + credentialDefinition, + credentialDefinitionId: credentialDefinitionState.credentialDefinitionId, + methodName: 'indy', + }) + ) + + if (!keyCorrectnessProof || !credentialDefinitionPrivate) { + throw new Error('Failed to create credential definition private or key correctness proof') + } + + await anonCredsKeyCorrectnessProofRepository.save( + agentContext, + new AnonCredsKeyCorrectnessProofRecord({ + credentialDefinitionId: credentialDefinitionState.credentialDefinitionId, + value: keyCorrectnessProof, + }) + ) + + await anonCredsCredentialDefinitionPrivateRepository.save( + agentContext, + new AnonCredsCredentialDefinitionPrivateRecord({ + credentialDefinitionId: credentialDefinitionState.credentialDefinitionId, + value: credentialDefinitionPrivate, + }) + ) + const holderCredentialRecord = new CredentialExchangeRecord({ protocolVersion: 'v1', state: CredentialState.ProposalSent, @@ -248,7 +302,7 @@ describe('Legacy indy format services', () => { credentialDefinitionId: legacyCredentialDefinitionId, revocationRegistryId: null, credentialRevocationId: null, - methodName: 'indy', + methodName: 'inMemory', }) expect(holderCredentialRecord.metadata.data).toEqual({ diff --git a/packages/anoncreds/src/models/exchange.ts b/packages/anoncreds/src/models/exchange.ts index 5213153ff9..7d483a602f 100644 --- a/packages/anoncreds/src/models/exchange.ts +++ b/packages/anoncreds/src/models/exchange.ts @@ -90,6 +90,7 @@ export interface AnonCredsProof { predicates: Record } // TODO: extend types for proof property + // eslint-disable-next-line @typescript-eslint/no-explicit-any proof: any identifiers: Array<{ schema_id: string diff --git a/packages/anoncreds/src/models/internal.ts b/packages/anoncreds/src/models/internal.ts index 8aacc72a52..112a0fb128 100644 --- a/packages/anoncreds/src/models/internal.ts +++ b/packages/anoncreds/src/models/internal.ts @@ -5,8 +5,8 @@ export interface AnonCredsCredentialInfo { } schemaId: string credentialDefinitionId: string - revocationRegistryId?: string | undefined - credentialRevocationId?: string | undefined + revocationRegistryId: string | null + credentialRevocationId: string | null methodName: string } diff --git a/packages/anoncreds/src/protocols/proofs/v1/__tests__/v1-connectionless-proofs.e2e.test.ts b/packages/anoncreds/src/protocols/proofs/v1/__tests__/v1-connectionless-proofs.e2e.test.ts index 57127b9269..9b7c86c770 100644 --- a/packages/anoncreds/src/protocols/proofs/v1/__tests__/v1-connectionless-proofs.e2e.test.ts +++ b/packages/anoncreds/src/protocols/proofs/v1/__tests__/v1-connectionless-proofs.e2e.test.ts @@ -23,13 +23,12 @@ import { uuid } from '../../../../../../core/src/utils/uuid' import { testLogger, waitForProofExchangeRecordSubject, - getAgentOptions, makeConnection, setupEventReplaySubjects, + getInMemoryAgentOptions, } from '../../../../../../core/tests' -import { getIndySdkModules } from '../../../../../../indy-sdk/tests/setupIndySdkModule' import { - getLegacyAnonCredsModules, + getAnonCredsIndyModules, issueLegacyAnonCredsCredential, prepareForAnonCredsIssuance, setupAnonCredsTests, @@ -62,6 +61,7 @@ describe('V1 Proofs - Connectionless - Indy', () => { attributeNames: ['name', 'age'], }) + // FIXME: We should reuse anoncreds crypto object as it will speed up tests significantly await issueLegacyAnonCredsCredential({ issuerAgent: faberAgent, holderAgent: aliceAgent, @@ -359,13 +359,12 @@ describe('V1 Proofs - Connectionless - Indy', () => { const unique = uuid().substring(0, 4) - const mediatorAgentOptions = getAgentOptions( + const mediatorAgentOptions = getInMemoryAgentOptions( `Connectionless proofs with mediator Mediator-${unique}`, { endpoints: ['rxjs:mediator'], }, { - ...getIndySdkModules(), mediator: new MediatorModule({ autoAcceptMediationRequests: true, }), @@ -391,11 +390,11 @@ describe('V1 Proofs - Connectionless - Indy', () => { handshakeProtocols: [HandshakeProtocol.Connections], }) - const faberAgentOptions = getAgentOptions( + const faberAgentOptions = getInMemoryAgentOptions( `Connectionless proofs with mediator Faber-${unique}`, {}, { - ...getLegacyAnonCredsModules({ + ...getAnonCredsIndyModules({ autoAcceptProofs: AutoAcceptProof.Always, }), mediationRecipient: new MediationRecipientModule({ @@ -407,11 +406,11 @@ describe('V1 Proofs - Connectionless - Indy', () => { } ) - const aliceAgentOptions = getAgentOptions( + const aliceAgentOptions = getInMemoryAgentOptions( `Connectionless proofs with mediator Alice-${unique}`, {}, { - ...getLegacyAnonCredsModules({ + ...getAnonCredsIndyModules({ autoAcceptProofs: AutoAcceptProof.Always, }), mediationRecipient: new MediationRecipientModule({ diff --git a/packages/anoncreds/src/updates/__tests__/0.3.test.ts b/packages/anoncreds/src/updates/__tests__/0.3.test.ts index 449724e874..69972503c6 100644 --- a/packages/anoncreds/src/updates/__tests__/0.3.test.ts +++ b/packages/anoncreds/src/updates/__tests__/0.3.test.ts @@ -3,9 +3,8 @@ import { readFileSync } from 'fs' import path from 'path' import { InMemoryStorageService } from '../../../../../tests/InMemoryStorageService' -import { indySdk, agentDependencies } from '../../../../core/tests' -import { IndySdkWallet } from '../../../../indy-sdk/src' -import { IndySdkSymbol } from '../../../../indy-sdk/src/types' +import { RegisteredAskarTestWallet } from '../../../../askar/tests/helpers' +import { agentDependencies, getAskarWalletConfig } from '../../../../core/tests' import { InMemoryAnonCredsRegistry } from '../../../tests/InMemoryAnonCredsRegistry' import { AnonCredsModule } from '../../AnonCredsModule' import { @@ -32,9 +31,8 @@ describe('UpdateAssistant | AnonCreds | v0.3.1 - v0.4', () => { const dependencyManager = new DependencyManager() const storageService = new InMemoryStorageService() dependencyManager.registerInstance(InjectionSymbols.StorageService, storageService) - // If we register the IndySdkModule it will register the storage service, but we use in memory storage here - dependencyManager.registerContextScoped(InjectionSymbols.Wallet, IndySdkWallet) - dependencyManager.registerInstance(IndySdkSymbol, indySdk) + // If we register the AskarModule it will register the storage service, but we use in memory storage here + dependencyManager.registerContextScoped(InjectionSymbols.Wallet, RegisteredAskarTestWallet) dependencyManager.registerInstance(AnonCredsIssuerServiceSymbol, {}) dependencyManager.registerInstance(AnonCredsHolderServiceSymbol, {}) dependencyManager.registerInstance(AnonCredsVerifierServiceSymbol, {}) @@ -43,10 +41,7 @@ describe('UpdateAssistant | AnonCreds | v0.3.1 - v0.4', () => { { config: { label: 'Test Agent', - walletConfig: { - id: `Wallet: 0.3 Update AnonCreds - Holder`, - key: `Key: 0.3 Update AnonCreds - Holder`, - }, + walletConfig: getAskarWalletConfig('0.3 Update AnonCreds - Holder', { inMemory: false, random: 'static' }), }, dependencies: agentDependencies, modules: { @@ -69,7 +64,12 @@ describe('UpdateAssistant | AnonCreds | v0.3.1 - v0.4', () => { // Set storage after initialization. This mimics as if this wallet // is opened as an existing wallet instead of a new wallet - storageService.records = JSON.parse(holderRecordsString) + storageService.contextCorrelationIdToRecords = { + default: { + records: JSON.parse(holderRecordsString), + creationDate: new Date(), + }, + } expect(await updateAssistant.isUpToDate()).toBe(false) expect(await updateAssistant.getNeededUpdates('0.4')).toEqual([ @@ -85,9 +85,7 @@ describe('UpdateAssistant | AnonCreds | v0.3.1 - v0.4', () => { expect(await updateAssistant.isUpToDate()).toBe(true) expect(await updateAssistant.getNeededUpdates()).toEqual([]) - // MEDIATOR_ROUTING_RECORD recipientKeys will be different every time, and is not what we're testing here - delete storageService.records.MEDIATOR_ROUTING_RECORD - expect(storageService.records).toMatchSnapshot() + expect(storageService.contextCorrelationIdToRecords[agent.context.contextCorrelationId].records).toMatchSnapshot() await agent.shutdown() await agent.wallet.delete() @@ -108,9 +106,8 @@ describe('UpdateAssistant | AnonCreds | v0.3.1 - v0.4', () => { const dependencyManager = new DependencyManager() const storageService = new InMemoryStorageService() dependencyManager.registerInstance(InjectionSymbols.StorageService, storageService) - // If we register the IndySdkModule it will register the storage service, but we use in memory storage here - dependencyManager.registerContextScoped(InjectionSymbols.Wallet, IndySdkWallet) - dependencyManager.registerInstance(IndySdkSymbol, indySdk) + // If we register the AskarModule it will register the storage service, but we use in memory storage here + dependencyManager.registerContextScoped(InjectionSymbols.Wallet, RegisteredAskarTestWallet) dependencyManager.registerInstance(AnonCredsIssuerServiceSymbol, {}) dependencyManager.registerInstance(AnonCredsHolderServiceSymbol, {}) dependencyManager.registerInstance(AnonCredsVerifierServiceSymbol, {}) @@ -119,10 +116,7 @@ describe('UpdateAssistant | AnonCreds | v0.3.1 - v0.4', () => { { config: { label: 'Test Agent', - walletConfig: { - id: `Wallet: 0.3 Update AnonCreds - Issuer`, - key: `Key: 0.3 Update AnonCreds - Issuer`, - }, + walletConfig: getAskarWalletConfig('0.3 Update AnonCreds - Issuer', { inMemory: false, random: 'static' }), }, dependencies: agentDependencies, modules: { @@ -211,7 +205,12 @@ describe('UpdateAssistant | AnonCreds | v0.3.1 - v0.4', () => { // Set storage after initialization. This mimics as if this wallet // is opened as an existing wallet instead of a new wallet - storageService.records = JSON.parse(issuerRecordsString) + storageService.contextCorrelationIdToRecords = { + default: { + records: JSON.parse(issuerRecordsString), + creationDate: new Date(), + }, + } expect(await updateAssistant.isUpToDate()).toBe(false) expect(await updateAssistant.getNeededUpdates()).toEqual([ @@ -227,9 +226,7 @@ describe('UpdateAssistant | AnonCreds | v0.3.1 - v0.4', () => { expect(await updateAssistant.isUpToDate()).toBe(true) expect(await updateAssistant.getNeededUpdates()).toEqual([]) - // MEDIATOR_ROUTING_RECORD recipientKeys will be different every time, and is not what we're testing here - delete storageService.records.MEDIATOR_ROUTING_RECORD - expect(storageService.records).toMatchSnapshot() + expect(storageService.contextCorrelationIdToRecords[agent.context.contextCorrelationId].records).toMatchSnapshot() await agent.shutdown() await agent.wallet.delete() diff --git a/packages/anoncreds/src/updates/__tests__/__snapshots__/0.3.test.ts.snap b/packages/anoncreds/src/updates/__tests__/__snapshots__/0.3.test.ts.snap index d6061e5889..5deeb55c0d 100644 --- a/packages/anoncreds/src/updates/__tests__/__snapshots__/0.3.test.ts.snap +++ b/packages/anoncreds/src/updates/__tests__/__snapshots__/0.3.test.ts.snap @@ -6,7 +6,7 @@ exports[`UpdateAssistant | AnonCreds | v0.3.1 - v0.4 should correctly update the "id": "1-4e4f-41d9-94c4-f49351b811f1", "tags": { "isDefault": true, - "linkSecretId": "Wallet: 0.3 Update AnonCreds - Holder", + "linkSecretId": "Wallet: 0.3 Update AnonCreds - Holder - static", }, "type": "AnonCredsLinkSecretRecord", "value": { @@ -14,7 +14,7 @@ exports[`UpdateAssistant | AnonCreds | v0.3.1 - v0.4 should correctly update the "isDefault": true, }, "id": "1-4e4f-41d9-94c4-f49351b811f1", - "linkSecretId": "Wallet: 0.3 Update AnonCreds - Holder", + "linkSecretId": "Wallet: 0.3 Update AnonCreds - Holder - static", "metadata": {}, "updatedAt": "2023-03-19T22:50:20.522Z", "value": undefined, @@ -345,7 +345,7 @@ exports[`UpdateAssistant | AnonCreds | v0.3.1 - v0.4 should correctly update the "id": "1-4e4f-41d9-94c4-f49351b811f1", "tags": { "isDefault": true, - "linkSecretId": "Wallet: 0.3 Update AnonCreds - Issuer", + "linkSecretId": "Wallet: 0.3 Update AnonCreds - Issuer - static", }, "type": "AnonCredsLinkSecretRecord", "value": { @@ -353,7 +353,7 @@ exports[`UpdateAssistant | AnonCreds | v0.3.1 - v0.4 should correctly update the "isDefault": true, }, "id": "1-4e4f-41d9-94c4-f49351b811f1", - "linkSecretId": "Wallet: 0.3 Update AnonCreds - Issuer", + "linkSecretId": "Wallet: 0.3 Update AnonCreds - Issuer - static", "metadata": {}, "updatedAt": "2023-03-19T22:50:20.522Z", "value": undefined, diff --git a/packages/anoncreds/tests/InMemoryAnonCredsRegistry.ts b/packages/anoncreds/tests/InMemoryAnonCredsRegistry.ts index f1194047f5..382b1f68b0 100644 --- a/packages/anoncreds/tests/InMemoryAnonCredsRegistry.ts +++ b/packages/anoncreds/tests/InMemoryAnonCredsRegistry.ts @@ -1,21 +1,21 @@ import type { + AnonCredsCredentialDefinition, AnonCredsRegistry, - GetSchemaReturn, - RegisterSchemaOptions, - RegisterSchemaReturn, + AnonCredsRevocationRegistryDefinition, + AnonCredsRevocationStatusList, + AnonCredsSchema, GetCredentialDefinitionReturn, - RegisterCredentialDefinitionOptions, - RegisterCredentialDefinitionReturn, GetRevocationRegistryDefinitionReturn, GetRevocationStatusListReturn, - AnonCredsRevocationStatusList, - AnonCredsRevocationRegistryDefinition, - AnonCredsSchema, - AnonCredsCredentialDefinition, + GetSchemaReturn, + RegisterCredentialDefinitionOptions, + RegisterCredentialDefinitionReturn, RegisterRevocationRegistryDefinitionOptions, RegisterRevocationRegistryDefinitionReturn, - RegisterRevocationStatusListReturn, RegisterRevocationStatusListOptions, + RegisterRevocationStatusListReturn, + RegisterSchemaOptions, + RegisterSchemaReturn, } from '../src' import type { AgentContext } from '@credo-ts/core' @@ -26,12 +26,12 @@ import { getDidIndyCredentialDefinitionId, getDidIndyRevocationRegistryDefinitionId, getDidIndySchemaId, -} from '../../indy-sdk/src/anoncreds/utils/identifiers' +} from '../../indy-vdr/src/anoncreds/utils/identifiers' import { - parseIndyCredentialDefinitionId, getUnqualifiedRevocationRegistryDefinitionId, getUnqualifiedCredentialDefinitionId, getUnqualifiedSchemaId, + parseIndyCredentialDefinitionId, parseIndyDid, parseIndySchemaId, } from '../src' @@ -43,9 +43,6 @@ import { dateToTimestamp } from '../src/utils/timestamp' export class InMemoryAnonCredsRegistry implements AnonCredsRegistry { public readonly methodName = 'inMemory' - // Roughly match that the identifier starts with an unqualified indy did. Once the - // anoncreds tests are not based on the indy-sdk anymore, we can use any identifier - // we want, but the indy-sdk is picky about the identifier format. public readonly supportedIdentifier = /.+/ private schemas: Record diff --git a/packages/anoncreds/tests/anoncreds.test.ts b/packages/anoncreds/tests/anoncreds.test.ts index 56427e47fa..dc0ce53967 100644 --- a/packages/anoncreds/tests/anoncreds.test.ts +++ b/packages/anoncreds/tests/anoncreds.test.ts @@ -1,8 +1,8 @@ -import { Agent, KeyDerivationMethod, KeyType, TypedArrayEncoder } from '@credo-ts/core' -import { agentDependencies } from '@credo-ts/node' -import * as indySdk from 'indy-sdk' +import { Agent, KeyType, TypedArrayEncoder } from '@credo-ts/core' -import { IndySdkModule } from '../../indy-sdk/src/IndySdkModule' +import { AnonCredsRsModule } from '../../anoncreds-rs/src' +import { anoncreds } from '../../anoncreds-rs/tests/helpers' +import { getInMemoryAgentOptions } from '../../core/tests' import { AnonCredsModule } from '../src' import { InMemoryAnonCredsRegistry } from './InMemoryAnonCredsRegistry' @@ -71,33 +71,25 @@ const existingRevocationStatusLists = { }, } -const agent = new Agent({ - config: { - label: '@credo-ts/anoncreds', - walletConfig: { - id: '@credo-ts/anoncreds', - key: 'CwNJroKHTSSj3XvE7ZAnuKiTn2C4QkFvxEqfm5rzhNrb', - keyDerivationMethod: KeyDerivationMethod.Raw, - }, - }, - modules: { - indySdk: new IndySdkModule({ - indySdk, - autoCreateLinkSecret: false, - }), - anoncreds: new AnonCredsModule({ - registries: [ - new InMemoryAnonCredsRegistry({ - existingSchemas, - existingCredentialDefinitions, - existingRevocationRegistryDefinitions, - existingRevocationStatusLists, - }), - ], - }), - }, - dependencies: agentDependencies, -}) +const agent = new Agent( + getInMemoryAgentOptions( + 'credo-anoncreds-package', + {}, + { + anoncredsRs: new AnonCredsRsModule({ anoncreds, autoCreateLinkSecret: false }), + anoncreds: new AnonCredsModule({ + registries: [ + new InMemoryAnonCredsRegistry({ + existingSchemas, + existingCredentialDefinitions, + existingRevocationRegistryDefinitions, + existingRevocationStatusLists, + }), + ], + }), + } + ) +) describe('AnonCreds API', () => { beforeEach(async () => { diff --git a/packages/anoncreds/tests/legacyAnonCredsSetup.ts b/packages/anoncreds/tests/legacyAnonCredsSetup.ts index 0d8b3f9148..f9752c4a7c 100644 --- a/packages/anoncreds/tests/legacyAnonCredsSetup.ts +++ b/packages/anoncreds/tests/legacyAnonCredsSetup.ts @@ -11,6 +11,7 @@ import type { import type { AutoAcceptProof, ConnectionRecord } from '@credo-ts/core' import { + AgentEventTypes, TypedArrayEncoder, CacheModule, InMemoryLruCache, @@ -31,12 +32,10 @@ import { randomUUID } from 'crypto' import { AnonCredsRsModule } from '../../anoncreds-rs/src' import { anoncreds } from '../../anoncreds-rs/tests/helpers' -import { AskarModule } from '../../askar/src' -import { askarModuleConfig } from '../../askar/tests/helpers' import { sleep } from '../../core/src/utils/sleep' import { setupSubjectTransports, setupEventReplaySubjects } from '../../core/tests' import { - getAgentOptions, + getInMemoryAgentOptions, importExistingIndyDidFromPrivateKey, makeConnection, publicDidSeed, @@ -44,14 +43,6 @@ import { waitForProofExchangeRecordSubject, } from '../../core/tests/helpers' import testLogger from '../../core/tests/logger' -import { - IndySdkAnonCredsRegistry, - IndySdkIndyDidRegistrar, - IndySdkIndyDidResolver, - IndySdkModule, - IndySdkSovDidResolver, -} from '../../indy-sdk/src' -import { getIndySdkModuleConfig } from '../../indy-sdk/tests/setupIndySdkModule' import { IndyVdrAnonCredsRegistry, IndyVdrSovDidResolver, @@ -73,54 +64,12 @@ import { } from '../src' // Helper type to get the type of the agents (with the custom modules) for the credential tests -export type AnonCredsTestsAgent = - | Agent & { mediationRecipient?: any; mediator?: any }> - | Agent & { mediationRecipient?: any; mediator?: any }> - -export const getLegacyAnonCredsModules = ({ - autoAcceptCredentials, - autoAcceptProofs, -}: { autoAcceptCredentials?: AutoAcceptCredential; autoAcceptProofs?: AutoAcceptProof } = {}) => { - const indyCredentialFormat = new LegacyIndyCredentialFormatService() - const indyProofFormat = new LegacyIndyProofFormatService() - - // Register the credential and proof protocols - const modules = { - credentials: new CredentialsModule({ - autoAcceptCredentials, - credentialProtocols: [ - new V1CredentialProtocol({ indyCredentialFormat }), - new V2CredentialProtocol({ - credentialFormats: [indyCredentialFormat], - }), - ], - }), - proofs: new ProofsModule({ - autoAcceptProofs, - proofProtocols: [ - new V1ProofProtocol({ indyProofFormat }), - new V2ProofProtocol({ - proofFormats: [indyProofFormat], - }), - ], - }), - anoncreds: new AnonCredsModule({ - registries: [new IndySdkAnonCredsRegistry()], - }), - dids: new DidsModule({ - resolvers: [new IndySdkSovDidResolver(), new IndySdkIndyDidResolver()], - registrars: [new IndySdkIndyDidRegistrar()], - }), - indySdk: new IndySdkModule(getIndySdkModuleConfig()), - cache: new CacheModule({ - cache: new InMemoryLruCache({ limit: 100 }), - }), - } as const - - return modules -} +export type AnonCredsTestsAgent = Agent< + // eslint-disable-next-line @typescript-eslint/no-explicit-any + ReturnType & { mediationRecipient?: any; mediator?: any } +> -export const getAskarAnonCredsIndyModules = ({ +export const getAnonCredsIndyModules = ({ autoAcceptCredentials, autoAcceptProofs, }: { autoAcceptCredentials?: AutoAcceptCredential; autoAcceptProofs?: AutoAcceptProof } = {}) => { @@ -161,7 +110,6 @@ export const getAskarAnonCredsIndyModules = ({ resolvers: [new IndyVdrSovDidResolver(), new IndyVdrIndyDidResolver()], registrars: [new IndyVdrIndyDidRegistrar()], }), - askar: new AskarModule(askarModuleConfig), cache: new CacheModule({ cache: new InMemoryLruCache({ limit: 100 }), }), @@ -352,12 +300,12 @@ export async function setupAnonCredsTests< createConnections?: CreateConnections }): Promise> { const issuerAgent = new Agent( - getAgentOptions( + getInMemoryAgentOptions( issuerName, { endpoints: ['rxjs:issuer'], }, - getLegacyAnonCredsModules({ + getAnonCredsIndyModules({ autoAcceptCredentials, autoAcceptProofs, }) @@ -365,12 +313,12 @@ export async function setupAnonCredsTests< ) const holderAgent = new Agent( - getAgentOptions( + getInMemoryAgentOptions( holderName, { endpoints: ['rxjs:holder'], }, - getLegacyAnonCredsModules({ + getAnonCredsIndyModules({ autoAcceptCredentials, autoAcceptProofs, }) @@ -379,12 +327,12 @@ export async function setupAnonCredsTests< const verifierAgent = verifierName ? new Agent( - getAgentOptions( + getInMemoryAgentOptions( verifierName, { endpoints: ['rxjs:verifier'], }, - getLegacyAnonCredsModules({ + getAnonCredsIndyModules({ autoAcceptCredentials, autoAcceptProofs, }) @@ -395,7 +343,11 @@ export async function setupAnonCredsTests< setupSubjectTransports(verifierAgent ? [issuerAgent, holderAgent, verifierAgent] : [issuerAgent, holderAgent]) const [issuerReplay, holderReplay, verifierReplay] = setupEventReplaySubjects( verifierAgent ? [issuerAgent, holderAgent, verifierAgent] : [issuerAgent, holderAgent], - [CredentialEventTypes.CredentialStateChanged, ProofEventTypes.ProofStateChanged] + [ + CredentialEventTypes.CredentialStateChanged, + ProofEventTypes.ProofStateChanged, + AgentEventTypes.AgentMessageProcessed, + ] ) await issuerAgent.initialize() diff --git a/packages/askar/src/AskarModule.ts b/packages/askar/src/AskarModule.ts index fe86f89755..561e0c2f85 100644 --- a/packages/askar/src/AskarModule.ts +++ b/packages/askar/src/AskarModule.ts @@ -21,7 +21,7 @@ export class AskarModule implements Module { dependencyManager .resolve(AgentConfig) .logger.warn( - "The '@credo-ts/askar' module is experimental and could have unexpected breaking changes. When using this module, make sure to use strict versions for all @aries-framework packages." + "The '@credo-ts/askar' module is experimental and could have unexpected breaking changes. When using this module, make sure to use strict versions for all @credo-ts packages." ) dependencyManager.registerInstance(AskarModuleConfig, this.config) diff --git a/packages/askar/src/storage/AskarStorageService.ts b/packages/askar/src/storage/AskarStorageService.ts index b34531871e..8edfb5c2f1 100644 --- a/packages/askar/src/storage/AskarStorageService.ts +++ b/packages/askar/src/storage/AskarStorageService.ts @@ -110,7 +110,7 @@ export class AskarStorageService implements StorageService return recordToInstance(record, recordClass) } catch (error) { if (error instanceof RecordNotFoundError) throw error - throw new WalletError(`Error getting record`, { cause: error }) + throw new WalletError(`Error getting record ${recordClass.name}`, { cause: error }) } } diff --git a/packages/askar/src/utils/askarKeyTypes.ts b/packages/askar/src/utils/askarKeyTypes.ts index 9731618b21..cbbf3713d2 100644 --- a/packages/askar/src/utils/askarKeyTypes.ts +++ b/packages/askar/src/utils/askarKeyTypes.ts @@ -1,15 +1,40 @@ import { KeyType } from '@credo-ts/core' import { KeyAlgs } from '@hyperledger/aries-askar-shared' +export enum AskarKeyTypePurpose { + KeyManagement = 'KeyManagement', + Signing = 'Signing', +} + const keyTypeToAskarAlg = { - [KeyType.Ed25519]: KeyAlgs.Ed25519, - [KeyType.X25519]: KeyAlgs.X25519, - [KeyType.Bls12381g1]: KeyAlgs.Bls12381G1, - [KeyType.Bls12381g2]: KeyAlgs.Bls12381G2, - [KeyType.Bls12381g1g2]: KeyAlgs.Bls12381G1G2, - [KeyType.P256]: KeyAlgs.EcSecp256r1, -} as const - -export const isKeyTypeSupportedByAskar = (keyType: KeyType) => keyType in keyTypeToAskarAlg + [KeyType.Ed25519]: { + keyAlg: KeyAlgs.Ed25519, + purposes: [AskarKeyTypePurpose.KeyManagement, AskarKeyTypePurpose.Signing], + }, + [KeyType.X25519]: { + keyAlg: KeyAlgs.X25519, + purposes: [AskarKeyTypePurpose.KeyManagement, AskarKeyTypePurpose.Signing], + }, + [KeyType.Bls12381g1]: { + keyAlg: KeyAlgs.Bls12381G1, + purposes: [AskarKeyTypePurpose.KeyManagement], + }, + [KeyType.Bls12381g2]: { + keyAlg: KeyAlgs.Bls12381G2, + purposes: [AskarKeyTypePurpose.KeyManagement], + }, + [KeyType.Bls12381g1g2]: { + keyAlg: KeyAlgs.Bls12381G1, + purposes: [AskarKeyTypePurpose.KeyManagement], + }, + [KeyType.P256]: { + keyAlg: KeyAlgs.EcSecp256r1, + purposes: [AskarKeyTypePurpose.KeyManagement], + }, +} + +export const isKeyTypeSupportedByAskarForPurpose = (keyType: KeyType, purpose: AskarKeyTypePurpose) => + keyType in keyTypeToAskarAlg && + keyTypeToAskarAlg[keyType as keyof typeof keyTypeToAskarAlg].purposes.includes(purpose) export const keyTypesSupportedByAskar = Object.keys(keyTypeToAskarAlg) as KeyType[] diff --git a/packages/askar/src/utils/askarWalletConfig.ts b/packages/askar/src/utils/askarWalletConfig.ts index 2ddfbb00a0..1819222e2a 100644 --- a/packages/askar/src/utils/askarWalletConfig.ts +++ b/packages/askar/src/utils/askarWalletConfig.ts @@ -1,9 +1,13 @@ -import type { AskarWalletPostgresStorageConfig } from '../wallet/AskarWalletPostgresStorageConfig' import type { WalletConfig } from '@credo-ts/core' import { KeyDerivationMethod, WalletError } from '@credo-ts/core' import { KdfMethod, StoreKeyMethod } from '@hyperledger/aries-askar-shared' +import { + isAskarWalletPostgresStorageConfig, + isAskarWalletSqliteStorageConfig, +} from '../wallet/AskarWalletStorageConfig' + export const keyDerivationMethodToStoreKeyMethod = (keyDerivationMethod: KeyDerivationMethod) => { const correspondenceTable = { [KeyDerivationMethod.Raw]: KdfMethod.Raw, @@ -32,33 +36,27 @@ export const uriFromWalletConfig = ( walletConfig.storage = { type: 'sqlite' } } - if (walletConfig.storage.type === 'sqlite') { - if (walletConfig.storage.inMemory) { + const urlParams = [] + + const storageConfig = walletConfig.storage + if (isAskarWalletSqliteStorageConfig(storageConfig)) { + if (storageConfig.config?.inMemory) { uri = 'sqlite://:memory:' } else { - path = (walletConfig.storage.path as string) ?? `${credoDataPath}/wallet/${walletConfig.id}/sqlite.db` + path = storageConfig.config?.path ?? `${credoDataPath}/wallet/${walletConfig.id}/sqlite.db` uri = `sqlite://${path}` } - } else if (walletConfig.storage.type === 'postgres') { - const storageConfig = walletConfig.storage as unknown as AskarWalletPostgresStorageConfig - + } else if (isAskarWalletPostgresStorageConfig(storageConfig)) { if (!storageConfig.config || !storageConfig.credentials) { throw new WalletError('Invalid storage configuration for postgres wallet') } - const urlParams = [] if (storageConfig.config.connectTimeout !== undefined) { urlParams.push(`connect_timeout=${encodeURIComponent(storageConfig.config.connectTimeout)}`) } if (storageConfig.config.idleTimeout !== undefined) { urlParams.push(`idle_timeout=${encodeURIComponent(storageConfig.config.idleTimeout)}`) } - if (storageConfig.config.maxConnections !== undefined) { - urlParams.push(`max_connections=${encodeURIComponent(storageConfig.config.maxConnections)}`) - } - if (storageConfig.config.minConnections !== undefined) { - urlParams.push(`min_connections=${encodeURIComponent(storageConfig.config.minConnections)}`) - } if (storageConfig.credentials.adminAccount !== undefined) { urlParams.push(`admin_account=${encodeURIComponent(storageConfig.credentials.adminAccount)}`) } @@ -69,12 +67,20 @@ export const uriFromWalletConfig = ( uri = `postgres://${encodeURIComponent(storageConfig.credentials.account)}:${encodeURIComponent( storageConfig.credentials.password )}@${storageConfig.config.host}/${encodeURIComponent(walletConfig.id)}` - - if (urlParams.length > 0) { - uri = `${uri}?${urlParams.join('&')}` - } } else { - throw new WalletError(`Storage type not supported: ${walletConfig.storage.type}`) + throw new WalletError(`Storage type not supported: ${storageConfig.type}`) + } + + // Common config options + if (storageConfig.config?.maxConnections !== undefined) { + urlParams.push(`max_connections=${encodeURIComponent(storageConfig.config.maxConnections)}`) + } + if (storageConfig.config?.minConnections !== undefined) { + urlParams.push(`min_connections=${encodeURIComponent(storageConfig.config.minConnections)}`) + } + + if (urlParams.length > 0) { + uri = `${uri}?${urlParams.join('&')}` } return { uri, path } diff --git a/packages/askar/src/wallet/AskarBaseWallet.ts b/packages/askar/src/wallet/AskarBaseWallet.ts index 90aae49f79..70796751e6 100644 --- a/packages/askar/src/wallet/AskarBaseWallet.ts +++ b/packages/askar/src/wallet/AskarBaseWallet.ts @@ -12,30 +12,33 @@ import type { Logger, SigningProviderRegistry, } from '@credo-ts/core' -import type { KeyEntryObject, Session } from '@hyperledger/aries-askar-shared' +import type { Session } from '@hyperledger/aries-askar-shared' import { WalletKeyExistsError, isValidSeed, isValidPrivateKey, - JsonTransformer, JsonEncoder, - KeyType, Buffer, AriesFrameworkError, WalletError, Key, TypedArrayEncoder, } from '@credo-ts/core' -import { KeyAlgs, CryptoBox, Store, Key as AskarKey, keyAlgFromString } from '@hyperledger/aries-askar-shared' -// eslint-disable-next-line import/order +import { CryptoBox, Store, Key as AskarKey, keyAlgFromString } from '@hyperledger/aries-askar-shared' import BigNumber from 'bn.js' -const isError = (error: unknown): error is Error => error instanceof Error +import { + AskarErrorCode, + AskarKeyTypePurpose, + isAskarError, + isKeyTypeSupportedByAskarForPurpose, + keyTypesSupportedByAskar, +} from '../utils' -import { AskarErrorCode, isAskarError, isKeyTypeSupportedByAskar, keyTypesSupportedByAskar } from '../utils' +import { didcommV1Pack, didcommV1Unpack } from './didcommV1' -import { JweEnvelope, JweRecipient } from './JweEnvelope' +const isError = (error: unknown): error is Error => error instanceof Error export abstract class AskarBaseWallet implements Wallet { protected _session?: Session @@ -96,13 +99,13 @@ export abstract class AskarBaseWallet implements Wallet { throw new WalletError('Invalid private key provided') } - if (isKeyTypeSupportedByAskar(keyType)) { + if (isKeyTypeSupportedByAskarForPurpose(keyType, AskarKeyTypePurpose.KeyManagement)) { const algorithm = keyAlgFromString(keyType) // Create key let key: AskarKey | undefined try { - const key = privateKey + key = privateKey ? AskarKey.fromSecretBytes({ secretKey: privateKey, algorithm }) : seed ? AskarKey.fromSeed({ seed, algorithm }) @@ -154,32 +157,81 @@ export abstract class AskarBaseWallet implements Wallet { * @returns A signature for the data */ public async sign({ data, key }: WalletSignOptions): Promise { - let keyEntry: KeyEntryObject | null | undefined + let askarKey: AskarKey | null | undefined + let keyPair: KeyPair | null | undefined + try { - if (isKeyTypeSupportedByAskar(key.keyType)) { + if (isKeyTypeSupportedByAskarForPurpose(key.keyType, AskarKeyTypePurpose.KeyManagement)) { + askarKey = (await this.session.fetchKey({ name: key.publicKeyBase58 }))?.key + } + + // FIXME: remove the custom KeyPair record now that we deprecate Indy SDK. + // We can do this in a migration script + + // Fallback to fetching key from the non-askar storage, this is to handle the case + // where a key wasn't supported at first by the wallet, but now is + if (!askarKey) { + keyPair = await this.retrieveKeyPair(key.publicKeyBase58) + + // If we have the key stored in a custom record, but it is now supported by Askar, + // we 'import' the key into askar storage and remove the custom key record + if (keyPair && isKeyTypeSupportedByAskarForPurpose(keyPair.keyType, AskarKeyTypePurpose.KeyManagement)) { + askarKey = AskarKey.fromSecretBytes({ + secretKey: TypedArrayEncoder.fromBase58(keyPair.privateKeyBase58), + algorithm: keyAlgFromString(keyPair.keyType), + }) + await this.session.insertKey({ + name: key.publicKeyBase58, + key: askarKey, + }) + // Now we can remove it from the custom record as we have imported it into Askar + await this.deleteKeyPair(key.publicKeyBase58) + keyPair = undefined + } + } + + if (!askarKey && !keyPair) { + throw new WalletError('Key entry not found') + } + + // Not all keys are supported for signing + if (isKeyTypeSupportedByAskarForPurpose(key.keyType, AskarKeyTypePurpose.Signing)) { if (!TypedArrayEncoder.isTypedArray(data)) { throw new WalletError(`Currently not supporting signing of multiple messages`) } - keyEntry = await this.session.fetchKey({ name: key.publicKeyBase58 }) - if (!keyEntry) { + askarKey = + askarKey ?? + (keyPair + ? AskarKey.fromSecretBytes({ + secretKey: TypedArrayEncoder.fromBase58(keyPair.privateKeyBase58), + algorithm: keyAlgFromString(keyPair.keyType), + }) + : undefined) + + if (!askarKey) { throw new WalletError('Key entry not found') } - const signed = keyEntry.key.signMessage({ message: data as Buffer }) - - keyEntry.key.handle.free() - + const signed = askarKey.signMessage({ message: data as Buffer }) return Buffer.from(signed) } else { // Check if there is a signing key provider for the specified key type. if (this.signingKeyProviderRegistry.hasProviderForKeyType(key.keyType)) { const signingKeyProvider = this.signingKeyProviderRegistry.getProviderForKeyType(key.keyType) - const keyPair = await this.retrieveKeyPair(key.publicKeyBase58) + // It could be that askar supports storing the key, but can't sign with it + // (in case of bls) + const privateKeyBase58 = + keyPair?.privateKeyBase58 ?? + (askarKey?.secretBytes ? TypedArrayEncoder.toBase58(askarKey.secretBytes) : undefined) + + if (!privateKeyBase58) { + throw new WalletError('Key entry not found') + } const signed = await signingKeyProvider.sign({ data, - privateKeyBase58: keyPair.privateKeyBase58, + privateKeyBase58: privateKeyBase58, publicKeyBase58: key.publicKeyBase58, }) @@ -188,11 +240,12 @@ export abstract class AskarBaseWallet implements Wallet { throw new WalletError(`Unsupported keyType: ${key.keyType}`) } } catch (error) { - keyEntry?.key.handle.free() if (!isError(error)) { throw new AriesFrameworkError('Attempted to throw error, but it was not of type Error', { cause: error }) } throw new WalletError(`Error signing data with verkey ${key.publicKeyBase58}. ${error.message}`, { cause: error }) + } finally { + askarKey?.handle.free() } } @@ -211,31 +264,29 @@ export abstract class AskarBaseWallet implements Wallet { public async verify({ data, key, signature }: WalletVerifyOptions): Promise { let askarKey: AskarKey | undefined try { - if (isKeyTypeSupportedByAskar(key.keyType)) { + if (isKeyTypeSupportedByAskarForPurpose(key.keyType, AskarKeyTypePurpose.Signing)) { if (!TypedArrayEncoder.isTypedArray(data)) { throw new WalletError(`Currently not supporting verification of multiple messages`) } - const askarKey = AskarKey.fromPublicBytes({ + askarKey = AskarKey.fromPublicBytes({ algorithm: keyAlgFromString(key.keyType), publicKey: key.publicKey, }) const verified = askarKey.verifySignature({ message: data as Buffer, signature }) askarKey.handle.free() return verified - } else { + } else if (this.signingKeyProviderRegistry.hasProviderForKeyType(key.keyType)) { // Check if there is a signing key provider for the specified key type. - if (this.signingKeyProviderRegistry.hasProviderForKeyType(key.keyType)) { - const signingKeyProvider = this.signingKeyProviderRegistry.getProviderForKeyType(key.keyType) - - const signed = await signingKeyProvider.verify({ - data, - signature, - publicKeyBase58: key.publicKeyBase58, - }) + const signingKeyProvider = this.signingKeyProviderRegistry.getProviderForKeyType(key.keyType) + const signed = await signingKeyProvider.verify({ + data, + signature, + publicKeyBase58: key.publicKeyBase58, + }) - return signed - } + return signed + } else { throw new WalletError(`Unsupported keyType: ${key.keyType}`) } } catch (error) { @@ -262,96 +313,18 @@ export abstract class AskarBaseWallet implements Wallet { recipientKeys: string[], senderVerkey?: string // in base58 ): Promise { - let cek: AskarKey | undefined - let senderKey: KeyEntryObject | null | undefined - let senderExchangeKey: AskarKey | undefined + const senderKey = senderVerkey ? await this.session.fetchKey({ name: senderVerkey }) : undefined try { - cek = AskarKey.generate(KeyAlgs.Chacha20C20P) - - senderKey = senderVerkey ? await this.session.fetchKey({ name: senderVerkey }) : undefined if (senderVerkey && !senderKey) { - throw new WalletError(`Unable to pack message. Sender key ${senderVerkey} not found in wallet.`) + throw new WalletError(`Sender key not found`) } - senderExchangeKey = senderKey ? senderKey.key.convertkey({ algorithm: KeyAlgs.X25519 }) : undefined - - const recipients: JweRecipient[] = [] + const envelope = didcommV1Pack(payload, recipientKeys, senderKey?.key) - for (const recipientKey of recipientKeys) { - let targetExchangeKey: AskarKey | undefined - try { - targetExchangeKey = AskarKey.fromPublicBytes({ - publicKey: Key.fromPublicKeyBase58(recipientKey, KeyType.Ed25519).publicKey, - algorithm: KeyAlgs.Ed25519, - }).convertkey({ algorithm: KeyAlgs.X25519 }) - - if (senderVerkey && senderExchangeKey) { - const encryptedSender = CryptoBox.seal({ - recipientKey: targetExchangeKey, - message: Buffer.from(senderVerkey), - }) - const nonce = CryptoBox.randomNonce() - const encryptedCek = CryptoBox.cryptoBox({ - recipientKey: targetExchangeKey, - senderKey: senderExchangeKey, - message: cek.secretBytes, - nonce, - }) - - recipients.push( - new JweRecipient({ - encryptedKey: encryptedCek, - header: { - kid: recipientKey, - sender: TypedArrayEncoder.toBase64URL(encryptedSender), - iv: TypedArrayEncoder.toBase64URL(nonce), - }, - }) - ) - } else { - const encryptedCek = CryptoBox.seal({ - recipientKey: targetExchangeKey, - message: cek.secretBytes, - }) - recipients.push( - new JweRecipient({ - encryptedKey: encryptedCek, - header: { - kid: recipientKey, - }, - }) - ) - } - } finally { - targetExchangeKey?.handle.free() - } - } - - const protectedJson = { - enc: 'xchacha20poly1305_ietf', - typ: 'JWM/1.0', - alg: senderVerkey ? 'Authcrypt' : 'Anoncrypt', - recipients: recipients.map((item) => JsonTransformer.toJSON(item)), - } - - const { ciphertext, tag, nonce } = cek.aeadEncrypt({ - message: Buffer.from(JSON.stringify(payload)), - aad: Buffer.from(JsonEncoder.toBase64URL(protectedJson)), - }).parts - - const envelope = new JweEnvelope({ - ciphertext: TypedArrayEncoder.toBase64URL(ciphertext), - iv: TypedArrayEncoder.toBase64URL(nonce), - protected: JsonEncoder.toBase64URL(protectedJson), - tag: TypedArrayEncoder.toBase64URL(tag), - }).toJson() - - return envelope as EncryptedMessage + return envelope } finally { - cek?.handle.free() senderKey?.key.handle.free() - senderExchangeKey?.handle.free() } } @@ -363,101 +336,21 @@ export abstract class AskarBaseWallet implements Wallet { */ public async unpack(messagePackage: EncryptedMessage): Promise { const protectedJson = JsonEncoder.fromBase64(messagePackage.protected) + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const recipientKids: string[] = protectedJson.recipients.map((r: any) => r.header.kid) - const alg = protectedJson.alg - if (!['Anoncrypt', 'Authcrypt'].includes(alg)) { - throw new WalletError(`Unsupported pack algorithm: ${alg}`) - } - - const recipients = [] - - for (const recip of protectedJson.recipients) { - const kid = recip.header.kid - if (!kid) { - throw new WalletError('Blank recipient key') - } - const sender = recip.header.sender ? TypedArrayEncoder.fromBase64(recip.header.sender) : undefined - const iv = recip.header.iv ? TypedArrayEncoder.fromBase64(recip.header.iv) : undefined - if (sender && !iv) { - throw new WalletError('Missing IV') - } else if (!sender && iv) { - throw new WalletError('Unexpected IV') - } - recipients.push({ - kid, - sender, - iv, - encrypted_key: TypedArrayEncoder.fromBase64(recip.encrypted_key), - }) - } - - let payloadKey, senderKey, recipientKey - - for (const recipient of recipients) { - let recipientKeyEntry: KeyEntryObject | null | undefined - let sender_x: AskarKey | undefined - let recip_x: AskarKey | undefined - + for (const recipientKid of recipientKids) { + const recipientKeyEntry = await this.session.fetchKey({ name: recipientKid }) try { - recipientKeyEntry = await this.session.fetchKey({ name: recipient.kid }) if (recipientKeyEntry) { - const recip_x = recipientKeyEntry.key.convertkey({ algorithm: KeyAlgs.X25519 }) - recipientKey = recipient.kid - - if (recipient.sender && recipient.iv) { - senderKey = TypedArrayEncoder.toUtf8String( - CryptoBox.sealOpen({ - recipientKey: recip_x, - ciphertext: recipient.sender, - }) - ) - const sender_x = AskarKey.fromPublicBytes({ - algorithm: KeyAlgs.Ed25519, - publicKey: TypedArrayEncoder.fromBase58(senderKey), - }).convertkey({ algorithm: KeyAlgs.X25519 }) - - payloadKey = CryptoBox.open({ - recipientKey: recip_x, - senderKey: sender_x, - message: recipient.encrypted_key, - nonce: recipient.iv, - }) - } else { - payloadKey = CryptoBox.sealOpen({ ciphertext: recipient.encrypted_key, recipientKey: recip_x }) - } - break + return didcommV1Unpack(messagePackage, recipientKeyEntry.key) } } finally { recipientKeyEntry?.key.handle.free() - sender_x?.handle.free() - recip_x?.handle.free() } } - if (!payloadKey) { - throw new WalletError('No corresponding recipient key found') - } - - if (!senderKey && alg === 'Authcrypt') { - throw new WalletError('Sender public key not provided for Authcrypt') - } - let cek: AskarKey | undefined - try { - cek = AskarKey.fromSecretBytes({ algorithm: KeyAlgs.Chacha20C20P, secretKey: payloadKey }) - const message = cek.aeadDecrypt({ - ciphertext: TypedArrayEncoder.fromBase64(messagePackage.ciphertext), - nonce: TypedArrayEncoder.fromBase64(messagePackage.iv), - tag: TypedArrayEncoder.fromBase64(messagePackage.tag), - aad: TypedArrayEncoder.fromString(messagePackage.protected), - }) - return { - plaintextMessage: JsonEncoder.fromBuffer(message), - senderKey, - recipientKey, - } - } finally { - cek?.handle.free() - } + throw new WalletError('No corresponding recipient key found') } public async generateNonce(): Promise { @@ -481,20 +374,26 @@ export abstract class AskarBaseWallet implements Wallet { } } - private async retrieveKeyPair(publicKeyBase58: string): Promise { + private async retrieveKeyPair(publicKeyBase58: string): Promise { try { const entryObject = await this.session.fetch({ category: 'KeyPairRecord', name: `key-${publicKeyBase58}` }) - if (entryObject?.value) { - return JsonEncoder.fromString(entryObject?.value as string) as KeyPair - } else { - throw new WalletError(`No content found for record with public key: ${publicKeyBase58}`) - } + if (!entryObject) return null + + return JsonEncoder.fromString(entryObject?.value as string) as KeyPair } catch (error) { throw new WalletError('Error retrieving KeyPair record', { cause: error }) } } + private async deleteKeyPair(publicKeyBase58: string): Promise { + try { + await this.session.remove({ category: 'KeyPairRecord', name: `key-${publicKeyBase58}` }) + } catch (error) { + throw new WalletError('Error removing KeyPair record', { cause: error }) + } + } + private async storeKeyPair(keyPair: KeyPair): Promise { try { await this.session.insert({ diff --git a/packages/askar/src/wallet/AskarWallet.ts b/packages/askar/src/wallet/AskarWallet.ts index 8f74d91ba3..078c75f647 100644 --- a/packages/askar/src/wallet/AskarWallet.ts +++ b/packages/askar/src/wallet/AskarWallet.ts @@ -23,6 +23,7 @@ import { AskarErrorCode, isAskarError, keyDerivationMethodToStoreKeyMethod, uriF import { AskarBaseWallet } from './AskarBaseWallet' import { AskarProfileWallet } from './AskarProfileWallet' +import { isAskarWalletSqliteStorageConfig } from './AskarWalletStorageConfig' /** * @todo: rename after 0.5.0, as we now have multiple types of AskarWallet @@ -218,7 +219,9 @@ export class AskarWallet extends AskarBaseWallet { if ( isAskarError(error) && (error.code === AskarErrorCode.NotFound || - (error.code === AskarErrorCode.Backend && walletConfig.storage?.inMemory)) + (error.code === AskarErrorCode.Backend && + isAskarWalletSqliteStorageConfig(walletConfig.storage) && + walletConfig.storage.config?.inMemory)) ) { const errorMessage = `Wallet '${walletConfig.id}' not found` this.logger.debug(errorMessage) @@ -281,6 +284,10 @@ export class AskarWallet extends AskarBaseWallet { const { path: destinationPath, key: exportKey } = exportConfig const { path: sourcePath } = uriFromWalletConfig(this.walletConfig, this.fileSystem.dataPath) + + if (isAskarWalletSqliteStorageConfig(this.walletConfig.storage) && this.walletConfig.storage?.inMemory) { + throw new WalletError('Export is not supported for in memory wallet') + } if (!sourcePath) { throw new WalletError('Export is only supported for SQLite backend') } @@ -295,7 +302,7 @@ export class AskarWallet extends AskarBaseWallet { const exportedWalletConfig = await this.getAskarWalletConfig({ ...this.walletConfig, key: exportKey, - storage: { type: 'sqlite', path: destinationPath }, + storage: { type: 'sqlite', config: { path: destinationPath } }, }) // Make sure destination path exists diff --git a/packages/askar/src/wallet/AskarWalletPostgresStorageConfig.ts b/packages/askar/src/wallet/AskarWalletPostgresStorageConfig.ts deleted file mode 100644 index e921792530..0000000000 --- a/packages/askar/src/wallet/AskarWalletPostgresStorageConfig.ts +++ /dev/null @@ -1,22 +0,0 @@ -import type { WalletStorageConfig } from '@credo-ts/core' - -export interface AskarWalletPostgresConfig { - host: string - connectTimeout?: number - idleTimeout?: number - maxConnections?: number - minConnections?: number -} - -export interface AskarWalletPostgresCredentials { - account: string - password: string - adminAccount?: string - adminPassword?: string -} - -export interface AskarWalletPostgresStorageConfig extends WalletStorageConfig { - type: 'postgres' - config: AskarWalletPostgresConfig - credentials: AskarWalletPostgresCredentials -} diff --git a/packages/askar/src/wallet/AskarWalletStorageConfig.ts b/packages/askar/src/wallet/AskarWalletStorageConfig.ts new file mode 100644 index 0000000000..be73af4546 --- /dev/null +++ b/packages/askar/src/wallet/AskarWalletStorageConfig.ts @@ -0,0 +1,47 @@ +import type { WalletStorageConfig } from '@credo-ts/core' + +export interface AskarWalletPostgresConfig { + host: string + connectTimeout?: number + idleTimeout?: number + maxConnections?: number + minConnections?: number +} + +export interface AskarWalletSqliteConfig { + // TODO: add other sqlite config options + maxConnections?: number + minConnections?: number + inMemory?: boolean + path?: string +} + +export interface AskarWalletPostgresCredentials { + account: string + password: string + adminAccount?: string + adminPassword?: string +} + +export interface AskarWalletPostgresStorageConfig extends WalletStorageConfig { + type: 'postgres' + config: AskarWalletPostgresConfig + credentials: AskarWalletPostgresCredentials +} + +export interface AskarWalletSqliteStorageConfig extends WalletStorageConfig { + type: 'sqlite' + config?: AskarWalletSqliteConfig +} + +export function isAskarWalletSqliteStorageConfig( + config?: WalletStorageConfig +): config is AskarWalletSqliteStorageConfig { + return config?.type === 'sqlite' +} + +export function isAskarWalletPostgresStorageConfig( + config?: WalletStorageConfig +): config is AskarWalletPostgresStorageConfig { + return config?.type === 'postgres' +} diff --git a/packages/askar/src/wallet/didcommV1.ts b/packages/askar/src/wallet/didcommV1.ts new file mode 100644 index 0000000000..6ab9a7f76d --- /dev/null +++ b/packages/askar/src/wallet/didcommV1.ts @@ -0,0 +1,177 @@ +import type { EncryptedMessage } from '@credo-ts/core' + +import { WalletError, JsonEncoder, JsonTransformer, Key, KeyType, TypedArrayEncoder, Buffer } from '@credo-ts/core' +import { CryptoBox, Key as AskarKey, KeyAlgs } from '@hyperledger/aries-askar-shared' + +import { JweEnvelope, JweRecipient } from './JweEnvelope' + +export function didcommV1Pack(payload: Record, recipientKeys: string[], senderKey?: AskarKey) { + let cek: AskarKey | undefined + let senderExchangeKey: AskarKey | undefined + + try { + cek = AskarKey.generate(KeyAlgs.Chacha20C20P) + + senderExchangeKey = senderKey ? senderKey.convertkey({ algorithm: KeyAlgs.X25519 }) : undefined + + const recipients: JweRecipient[] = [] + + for (const recipientKey of recipientKeys) { + let targetExchangeKey: AskarKey | undefined + try { + targetExchangeKey = AskarKey.fromPublicBytes({ + publicKey: Key.fromPublicKeyBase58(recipientKey, KeyType.Ed25519).publicKey, + algorithm: KeyAlgs.Ed25519, + }).convertkey({ algorithm: KeyAlgs.X25519 }) + + if (senderKey && senderExchangeKey) { + const encryptedSender = CryptoBox.seal({ + recipientKey: targetExchangeKey, + message: TypedArrayEncoder.fromString(TypedArrayEncoder.toBase58(senderKey.publicBytes)), + }) + const nonce = CryptoBox.randomNonce() + const encryptedCek = CryptoBox.cryptoBox({ + recipientKey: targetExchangeKey, + senderKey: senderExchangeKey, + message: cek.secretBytes, + nonce, + }) + + recipients.push( + new JweRecipient({ + encryptedKey: encryptedCek, + header: { + kid: recipientKey, + sender: TypedArrayEncoder.toBase64URL(encryptedSender), + iv: TypedArrayEncoder.toBase64URL(nonce), + }, + }) + ) + } else { + const encryptedCek = CryptoBox.seal({ + recipientKey: targetExchangeKey, + message: cek.secretBytes, + }) + recipients.push( + new JweRecipient({ + encryptedKey: encryptedCek, + header: { + kid: recipientKey, + }, + }) + ) + } + } finally { + targetExchangeKey?.handle.free() + } + } + + const protectedJson = { + enc: 'xchacha20poly1305_ietf', + typ: 'JWM/1.0', + alg: senderKey ? 'Authcrypt' : 'Anoncrypt', + recipients: recipients.map((item) => JsonTransformer.toJSON(item)), + } + + const { ciphertext, tag, nonce } = cek.aeadEncrypt({ + message: Buffer.from(JSON.stringify(payload)), + aad: Buffer.from(JsonEncoder.toBase64URL(protectedJson)), + }).parts + + const envelope = new JweEnvelope({ + ciphertext: TypedArrayEncoder.toBase64URL(ciphertext), + iv: TypedArrayEncoder.toBase64URL(nonce), + protected: JsonEncoder.toBase64URL(protectedJson), + tag: TypedArrayEncoder.toBase64URL(tag), + }).toJson() + + return envelope as EncryptedMessage + } finally { + cek?.handle.free() + senderExchangeKey?.handle.free() + } +} + +export function didcommV1Unpack(messagePackage: EncryptedMessage, recipientKey: AskarKey) { + const protectedJson = JsonEncoder.fromBase64(messagePackage.protected) + + const alg = protectedJson.alg + if (!['Anoncrypt', 'Authcrypt'].includes(alg)) { + throw new WalletError(`Unsupported pack algorithm: ${alg}`) + } + + const recipient = protectedJson.recipients.find( + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (r: any) => r.header.kid === TypedArrayEncoder.toBase58(recipientKey.publicBytes) + ) + + if (!recipient) { + throw new WalletError('No corresponding recipient key found') + } + + const sender = recipient?.header.sender ? TypedArrayEncoder.fromBase64(recipient.header.sender) : undefined + const iv = recipient?.header.iv ? TypedArrayEncoder.fromBase64(recipient.header.iv) : undefined + const encrypted_key = TypedArrayEncoder.fromBase64(recipient.encrypted_key) + + if (sender && !iv) { + throw new WalletError('Missing IV') + } else if (!sender && iv) { + throw new WalletError('Unexpected IV') + } + + let payloadKey, senderKey + + let sender_x: AskarKey | undefined + let recip_x: AskarKey | undefined + + try { + recip_x = recipientKey.convertkey({ algorithm: KeyAlgs.X25519 }) + + if (sender && iv) { + senderKey = TypedArrayEncoder.toUtf8String( + CryptoBox.sealOpen({ + recipientKey: recip_x, + ciphertext: sender, + }) + ) + sender_x = AskarKey.fromPublicBytes({ + algorithm: KeyAlgs.Ed25519, + publicKey: TypedArrayEncoder.fromBase58(senderKey), + }).convertkey({ algorithm: KeyAlgs.X25519 }) + + payloadKey = CryptoBox.open({ + recipientKey: recip_x, + senderKey: sender_x, + message: encrypted_key, + nonce: iv, + }) + } else { + payloadKey = CryptoBox.sealOpen({ ciphertext: encrypted_key, recipientKey: recip_x }) + } + } finally { + sender_x?.handle.free() + recip_x?.handle.free() + } + + if (!senderKey && alg === 'Authcrypt') { + throw new WalletError('Sender public key not provided for Authcrypt') + } + + let cek: AskarKey | undefined + try { + cek = AskarKey.fromSecretBytes({ algorithm: KeyAlgs.Chacha20C20P, secretKey: payloadKey }) + const message = cek.aeadDecrypt({ + ciphertext: TypedArrayEncoder.fromBase64(messagePackage.ciphertext), + nonce: TypedArrayEncoder.fromBase64(messagePackage.iv), + tag: TypedArrayEncoder.fromBase64(messagePackage.tag), + aad: TypedArrayEncoder.fromString(messagePackage.protected), + }) + return { + plaintextMessage: JsonEncoder.fromBuffer(message), + senderKey, + recipientKey: TypedArrayEncoder.toBase58(recipientKey.publicBytes), + } + } finally { + cek?.handle.free() + } +} diff --git a/packages/askar/src/wallet/index.ts b/packages/askar/src/wallet/index.ts index fb71764d57..49e1da0a79 100644 --- a/packages/askar/src/wallet/index.ts +++ b/packages/askar/src/wallet/index.ts @@ -1,3 +1,3 @@ export { AskarWallet } from './AskarWallet' export { AskarProfileWallet } from './AskarProfileWallet' -export * from './AskarWalletPostgresStorageConfig' +export * from './AskarWalletStorageConfig' diff --git a/packages/askar/tests/askar-inmemory.e2e.test.ts b/packages/askar/tests/askar-inmemory.e2e.test.ts index e848602aab..d98e762fa5 100644 --- a/packages/askar/tests/askar-inmemory.e2e.test.ts +++ b/packages/askar/tests/askar-inmemory.e2e.test.ts @@ -7,16 +7,16 @@ import { Subject } from 'rxjs' import { SubjectInboundTransport } from '../../../tests/transport/SubjectInboundTransport' import { SubjectOutboundTransport } from '../../../tests/transport/SubjectOutboundTransport' -import { e2eTest, getSqliteAgentOptions } from './helpers' +import { e2eTest, getAskarSqliteAgentOptions } from './helpers' -const aliceInMemoryAgentOptions = getSqliteAgentOptions( +const aliceInMemoryAgentOptions = getAskarSqliteAgentOptions( 'AgentsAlice', { endpoints: ['rxjs:alice'], }, true ) -const bobInMemoryAgentOptions = getSqliteAgentOptions( +const bobInMemoryAgentOptions = getAskarSqliteAgentOptions( 'AgentsBob', { endpoints: ['rxjs:bob'], diff --git a/packages/askar/tests/askar-postgres.e2e.test.ts b/packages/askar/tests/askar-postgres.e2e.test.ts index f21c19ec73..92a7168b5f 100644 --- a/packages/askar/tests/askar-postgres.e2e.test.ts +++ b/packages/askar/tests/askar-postgres.e2e.test.ts @@ -1,6 +1,5 @@ /* eslint-disable @typescript-eslint/no-non-null-assertion */ import type { SubjectMessage } from '../../../tests/transport/SubjectInboundTransport' -import type { AskarWalletPostgresStorageConfig } from '../src/wallet' import { Agent } from '@credo-ts/core' import { Subject } from 'rxjs' @@ -8,23 +7,12 @@ import { Subject } from 'rxjs' import { SubjectInboundTransport } from '../../../tests/transport/SubjectInboundTransport' import { SubjectOutboundTransport } from '../../../tests/transport/SubjectOutboundTransport' -import { e2eTest, getPostgresAgentOptions } from './helpers' +import { askarPostgresStorageConfig, e2eTest, getAskarPostgresAgentOptions } from './helpers' -const storageConfig: AskarWalletPostgresStorageConfig = { - type: 'postgres', - config: { - host: 'localhost:5432', - }, - credentials: { - account: 'postgres', - password: 'postgres', - }, -} - -const alicePostgresAgentOptions = getPostgresAgentOptions('AgentsAlice', storageConfig, { +const alicePostgresAgentOptions = getAskarPostgresAgentOptions('AgentsAlice', askarPostgresStorageConfig, { endpoints: ['rxjs:alice'], }) -const bobPostgresAgentOptions = getPostgresAgentOptions('AgentsBob', storageConfig, { +const bobPostgresAgentOptions = getAskarPostgresAgentOptions('AgentsBob', askarPostgresStorageConfig, { endpoints: ['rxjs:bob'], }) diff --git a/packages/askar/tests/askar-sqlite.e2e.test.ts b/packages/askar/tests/askar-sqlite.e2e.test.ts index 3a3797ec4b..7de1f8408b 100644 --- a/packages/askar/tests/askar-sqlite.e2e.test.ts +++ b/packages/askar/tests/askar-sqlite.e2e.test.ts @@ -15,10 +15,10 @@ import { Store } from '@hyperledger/aries-askar-shared' import { tmpdir } from 'os' import path from 'path' -import { getSqliteAgentOptions } from './helpers' +import { getAskarSqliteAgentOptions } from './helpers' -const aliceAgentOptions = getSqliteAgentOptions('AgentsAlice') -const bobAgentOptions = getSqliteAgentOptions('AgentsBob') +const aliceAgentOptions = getAskarSqliteAgentOptions('AgentsAlice') +const bobAgentOptions = getAskarSqliteAgentOptions('AgentsBob') describe('Askar SQLite agents', () => { let aliceAgent: Agent diff --git a/packages/askar/tests/helpers.ts b/packages/askar/tests/helpers.ts index 0300735c1c..af6fddea15 100644 --- a/packages/askar/tests/helpers.ts +++ b/packages/askar/tests/helpers.ts @@ -15,6 +15,8 @@ import { AskarWallet } from '../src/wallet' export const askarModuleConfig = new AskarModuleConfig({ ariesAskar }) registerAriesAskar({ askar: askarModuleConfig.ariesAskar }) +export const askarModule = new AskarModule(askarModuleConfig) +export { ariesAskar } // When using the AskarWallet directly, the native dependency won't be loaded by default. // So in tests depending on Askar, we import this wallet so we're sure the native dependency is loaded. @@ -26,7 +28,18 @@ export const genesisPath = process.env.GENESIS_TXN_PATH export const publicDidSeed = process.env.TEST_AGENT_PUBLIC_DID_SEED ?? '000000000000000000000000Trustee9' -export function getPostgresAgentOptions( +export const askarPostgresStorageConfig: AskarWalletPostgresStorageConfig = { + type: 'postgres', + config: { + host: 'localhost:5432', + }, + credentials: { + account: 'postgres', + password: 'postgres', + }, +} + +export function getAskarPostgresAgentOptions( name: string, storageConfig: AskarWalletPostgresStorageConfig, extraConfig: Partial = {} @@ -55,7 +68,7 @@ export function getPostgresAgentOptions( } as const } -export function getSqliteAgentOptions(name: string, extraConfig: Partial = {}, inMemory?: boolean) { +export function getAskarSqliteAgentOptions(name: string, extraConfig: Partial = {}, inMemory?: boolean) { const random = utils.uuid().slice(0, 4) const config: InitConfig = { label: `SQLiteAgent: ${name} - ${random}`, diff --git a/packages/bbs-signatures/src/BbsModule.ts b/packages/bbs-signatures/src/BbsModule.ts index 152e92b9ff..5cd1c4206d 100644 --- a/packages/bbs-signatures/src/BbsModule.ts +++ b/packages/bbs-signatures/src/BbsModule.ts @@ -20,7 +20,7 @@ export class BbsModule implements Module { dependencyManager .resolve(AgentConfig) .logger.warn( - "The '@credo-ts/bbs-signatures' module is experimental and could have unexpected breaking changes. When using this module, make sure to use strict versions for all @aries-framework packages." + "The '@credo-ts/bbs-signatures' module is experimental and could have unexpected breaking changes. When using this module, make sure to use strict versions for all @credo-ts packages." ) // Signing providers. diff --git a/packages/bbs-signatures/tests/bbs-signatures.e2e.test.ts b/packages/bbs-signatures/tests/bbs-signatures.e2e.test.ts index fcdc8d49b9..0a6c098624 100644 --- a/packages/bbs-signatures/tests/bbs-signatures.e2e.test.ts +++ b/packages/bbs-signatures/tests/bbs-signatures.e2e.test.ts @@ -20,14 +20,13 @@ import { W3cJsonLdVerifiableCredential, } from '@credo-ts/core' +import { RegisteredAskarTestWallet } from '../../askar/tests/helpers' import { W3cCredentialsModuleConfig } from '../../core/src/modules/vc/W3cCredentialsModuleConfig' import { SignatureSuiteRegistry } from '../../core/src/modules/vc/data-integrity/SignatureSuiteRegistry' import { W3cJsonLdCredentialService } from '../../core/src/modules/vc/data-integrity/W3cJsonLdCredentialService' import { customDocumentLoader } from '../../core/src/modules/vc/data-integrity/__tests__/documentLoader' import { LinkedDataProof } from '../../core/src/modules/vc/data-integrity/models/LinkedDataProof' -import { getAgentConfig, getAgentContext } from '../../core/tests/helpers' -import { IndySdkWallet } from '../../indy-sdk/src' -import { indySdk } from '../../indy-sdk/tests/setupIndySdkModule' +import { agentDependencies, getAgentConfig, getAgentContext } from '../../core/tests/helpers' import { BbsBlsSignature2020, BbsBlsSignatureProof2020, Bls12381g2SigningProvider } from '../src' import { BbsBlsSignature2020Fixtures } from './fixtures' @@ -66,11 +65,17 @@ describeSkipNode18('BBS W3cCredentialService', () => { let agentContext: AgentContext let w3cJsonLdCredentialService: W3cJsonLdCredentialService let w3cCredentialService: W3cCredentialService - const seed = TypedArrayEncoder.fromString('testseed000000000000000000000001') const privateKey = TypedArrayEncoder.fromString('testseed000000000000000000000001') beforeAll(async () => { - wallet = new IndySdkWallet(indySdk, agentConfig.logger, signingProviderRegistry) + // Use askar wallet so we can use the signing provider registry + // TODO: support signing provider registry in memory wallet + // so we don't have to use askar here + wallet = new RegisteredAskarTestWallet( + agentConfig.logger, + new agentDependencies.FileSystem(), + signingProviderRegistry + ) await wallet.createAndOpen(agentConfig.walletConfig) agentContext = getAgentContext({ agentConfig, @@ -124,7 +129,13 @@ describeSkipNode18('BBS W3cCredentialService', () => { let verificationMethod: string beforeAll(async () => { - const key = await wallet.createKey({ keyType: KeyType.Bls12381g2, seed }) + // FIXME: askar doesn't create the same privateKey based on the same seed as when generated used askar BBS library... + // See https://github.com/hyperledger/aries-askar/issues/219 + const key = await wallet.createKey({ + keyType: KeyType.Bls12381g2, + privateKey: TypedArrayEncoder.fromBase58('2szQ7zB4tKLJPsGK3YTp9SNQ6hoWYFG5rGhmgfQM4nb7'), + }) + issuerDidKey = new DidKey(key) verificationMethod = `${issuerDidKey.did}#${issuerDidKey.key.fingerprint}` }) @@ -140,7 +151,7 @@ describeSkipNode18('BBS W3cCredentialService', () => { format: ClaimFormat.LdpVc, credential, proofType: 'BbsBlsSignature2020', - verificationMethod: verificationMethod, + verificationMethod, }) expect(vc).toBeInstanceOf(W3cJsonLdVerifiableCredential) diff --git a/packages/bbs-signatures/tests/bbs-signing-provider.e2e.test.ts b/packages/bbs-signatures/tests/bbs-signing-provider.e2e.test.ts index 6c1ab056a6..6b8515aed0 100644 --- a/packages/bbs-signatures/tests/bbs-signing-provider.e2e.test.ts +++ b/packages/bbs-signatures/tests/bbs-signing-provider.e2e.test.ts @@ -3,9 +3,8 @@ import type { Wallet, WalletConfig } from '@credo-ts/core' import { KeyDerivationMethod, KeyType, WalletError, TypedArrayEncoder, SigningProviderRegistry } from '@credo-ts/core' import { BBS_SIGNATURE_LENGTH } from '@mattrglobal/bbs-signatures' -import testLogger from '../../core/tests/logger' -import { IndySdkWallet } from '../../indy-sdk/src' -import { indySdk } from '../../indy-sdk/tests/setupIndySdkModule' +import { RegisteredAskarTestWallet } from '../../askar/tests/helpers' +import { testLogger, agentDependencies } from '../../core/tests' import { Bls12381g2SigningProvider } from '../src' import { describeSkipNode18 } from './util' @@ -24,7 +23,11 @@ describeSkipNode18('BBS Signing Provider', () => { const message = TypedArrayEncoder.fromString('sample-message') beforeEach(async () => { - wallet = new IndySdkWallet(indySdk, testLogger, new SigningProviderRegistry([new Bls12381g2SigningProvider()])) + wallet = new RegisteredAskarTestWallet( + testLogger, + new agentDependencies.FileSystem(), + new SigningProviderRegistry([new Bls12381g2SigningProvider()]) + ) await wallet.createAndOpen(walletConfig) }) @@ -33,15 +36,24 @@ describeSkipNode18('BBS Signing Provider', () => { }) test('Create bls12381g2 keypair', async () => { - await expect(wallet.createKey({ seed, keyType: KeyType.Bls12381g2 })).resolves.toMatchObject({ - publicKeyBase58: - '25TvGExLTWRTgn9h2wZuohrQmmLafXiacY4dhv66wcbY8pLbuNTBRMTgWVcPKh2wsEyrRPmnhLdc4C7LEcJ2seoxzBkoydJEdQD8aqg5dw8wesBTS9Twg8EjuFG1WPRAiERd', - keyType: KeyType.Bls12381g2, - }) + const key = await wallet.createKey({ seed, keyType: KeyType.Bls12381g2 }) + expect(key.keyType).toStrictEqual(KeyType.Bls12381g2) + expect(key.publicKeyBase58).toStrictEqual( + 'yVLZ92FeZ3AYco43LXtJgtM8kUD1WPUyQPw4VwxZ1iYSak85GYGSJwURhVJM4R6ASRGuM9vjjSU91pKbaqTWQgLjPJjFuK8HdDmAHi3thYun9QUGjarrK7BzC11LurcpYqD' + ) }) - test('Fail to create bls12381g1g2 keypair', async () => { - await expect(wallet.createKey({ seed, keyType: KeyType.Bls12381g1g2 })).rejects.toThrowError(WalletError) + test('Fail to sign with bls12381g1g2 keypair', async () => { + const key = await wallet.createKey({ seed, keyType: KeyType.Bls12381g1g2 }) + + await expect( + wallet.sign({ + data: message, + key, + }) + ).rejects.toThrow( + 'Error signing data with verkey AeAihfn5UFf7y9oesemKE1oLmTwKMRv7fafTepespr3qceF4RUMggAbogkoC8n6rXgtJytq4oGy59DsVHxmNj9WGWwkiRnP3Sz2r924RLVbc2NdP4T7yEPsSFZPsWmLjgnP1vXHpj4bVXNcTmkUmF6mSXinF3HehnQVip14vRFuMzYVxMUh28ofTJzbtUqxMWZQRu. Unsupported keyType: bls12381g1g2' + ) }) test('Create a signature with a bls12381g2 keypair', async () => { diff --git a/packages/bbs-signatures/tests/v2.ldproof.credentials.propose-offerBbs.test.ts b/packages/bbs-signatures/tests/v2.ldproof.credentials.propose-offerBbs.test.ts index feaead2f3e..f6b1983c15 100644 --- a/packages/bbs-signatures/tests/v2.ldproof.credentials.propose-offerBbs.test.ts +++ b/packages/bbs-signatures/tests/v2.ldproof.credentials.propose-offerBbs.test.ts @@ -63,15 +63,18 @@ describeSkipNode18('credentials, BBS+ signature', () => { } = await setupJsonLdTests({ issuerName: 'Faber Agent Credentials LD BBS+', holderName: 'Alice Agent Credentials LD BBS+', + useBbs: true, })) await faberAgent.context.wallet.createKey({ keyType: KeyType.Ed25519, privateKey: TypedArrayEncoder.fromString('testseed000000000000000000000001'), }) + // FIXME: askar doesn't create the same privateKey based on the same seed as when generated used askar BBS library... + // See https://github.com/hyperledger/aries-askar/issues/219 await faberAgent.context.wallet.createKey({ keyType: KeyType.Bls12381g2, - seed: TypedArrayEncoder.fromString('testseed000000000000000000000001'), + privateKey: TypedArrayEncoder.fromBase58('2szQ7zB4tKLJPsGK3YTp9SNQ6hoWYFG5rGhmgfQM4nb7'), }) }) diff --git a/packages/cheqd/package.json b/packages/cheqd/package.json index 2ee4f995d2..f13502ab40 100644 --- a/packages/cheqd/package.json +++ b/packages/cheqd/package.json @@ -37,8 +37,6 @@ "tsyringe": "^4.8.0" }, "devDependencies": { - "@credo-ts/indy-sdk": "0.4.2", - "@types/indy-sdk": "*", "rimraf": "^4.0.7", "typescript": "~4.9.4" } diff --git a/packages/cheqd/src/CheqdModule.ts b/packages/cheqd/src/CheqdModule.ts index fa9d393f44..af739a194e 100644 --- a/packages/cheqd/src/CheqdModule.ts +++ b/packages/cheqd/src/CheqdModule.ts @@ -18,7 +18,7 @@ export class CheqdModule implements Module { dependencyManager .resolve(AgentConfig) .logger.warn( - "The '@credo-ts/cheqd' module is experimental and could have unexpected breaking changes. When using this module, make sure to use strict versions for all @aries-framework packages." + "The '@credo-ts/cheqd' module is experimental and could have unexpected breaking changes. When using this module, make sure to use strict versions for all @credo-ts packages." ) // Register config diff --git a/packages/cheqd/tests/cheqd-did-registrar.e2e.test.ts b/packages/cheqd/tests/cheqd-did-registrar.e2e.test.ts index 69f0f524c2..d86a9c7f77 100644 --- a/packages/cheqd/tests/cheqd-did-registrar.e2e.test.ts +++ b/packages/cheqd/tests/cheqd-did-registrar.e2e.test.ts @@ -4,12 +4,12 @@ import type { DidDocument } from '@credo-ts/core' import { Agent, TypedArrayEncoder } from '@credo-ts/core' import { generateKeyPairFromSeed } from '@stablelib/ed25519' -import { getAgentOptions } from '../../core/tests/helpers' +import { getInMemoryAgentOptions } from '../../core/tests/helpers' import { validService } from './setup' import { getCheqdModules } from './setupCheqdModule' -const agentOptions = getAgentOptions('Faber Dids Registrar', {}, getCheqdModules()) +const agentOptions = getInMemoryAgentOptions('Faber Dids Registrar', {}, getCheqdModules()) describe('Cheqd DID registrar', () => { let agent: Agent> diff --git a/packages/cheqd/tests/cheqd-did-resolver.e2e.test.ts b/packages/cheqd/tests/cheqd-did-resolver.e2e.test.ts index 4a11e53ed5..498cd6e4ec 100644 --- a/packages/cheqd/tests/cheqd-did-resolver.e2e.test.ts +++ b/packages/cheqd/tests/cheqd-did-resolver.e2e.test.ts @@ -1,13 +1,13 @@ import { Agent, JsonTransformer } from '@credo-ts/core' -import { getAgentOptions } from '../../core/tests/helpers' +import { getInMemoryAgentOptions } from '../../core/tests/helpers' import { getClosestResourceVersion } from '../src/dids/didCheqdUtil' import { DefaultRPCUrl } from '../src/ledger/CheqdLedgerService' import { getCheqdModules } from './setupCheqdModule' export const resolverAgent = new Agent( - getAgentOptions('Cheqd resolver', {}, getCheqdModules(undefined, DefaultRPCUrl.Testnet)) + getInMemoryAgentOptions('Cheqd resolver', {}, getCheqdModules(undefined, DefaultRPCUrl.Testnet)) ) describe('Cheqd DID resolver', () => { diff --git a/packages/cheqd/tests/cheqd-sdk-anoncreds-registry.e2e.test.ts b/packages/cheqd/tests/cheqd-sdk-anoncreds-registry.e2e.test.ts index 77c6caaf6c..39802bb20e 100644 --- a/packages/cheqd/tests/cheqd-sdk-anoncreds-registry.e2e.test.ts +++ b/packages/cheqd/tests/cheqd-sdk-anoncreds-registry.e2e.test.ts @@ -2,21 +2,21 @@ import type { CheqdDidCreateOptions } from '../src' import { Agent, JsonTransformer, TypedArrayEncoder } from '@credo-ts/core' -import { agentDependencies, getAgentConfig } from '../../core/tests/helpers' +import { getInMemoryAgentOptions } from '../../core/tests/helpers' import { CheqdAnonCredsRegistry } from '../src/anoncreds' import { resolverAgent } from './cheqd-did-resolver.e2e.test' import { getCheqdModules } from './setupCheqdModule' -const agentConfig = getAgentConfig('cheqdAnonCredsRegistry') - -const agent = new Agent({ - config: agentConfig, - dependencies: agentDependencies, - modules: getCheqdModules( - 'ugly dirt sorry girl prepare argue door man that manual glow scout bomb pigeon matter library transfer flower clown cat miss pluck drama dizzy' - ), -}) +const agent = new Agent( + getInMemoryAgentOptions( + 'cheqdAnonCredsRegistry', + {}, + getCheqdModules( + 'ugly dirt sorry girl prepare argue door man that manual glow scout bomb pigeon matter library transfer flower clown cat miss pluck drama dizzy' + ) + ) +) const cheqdAnonCredsRegistry = new CheqdAnonCredsRegistry() diff --git a/packages/cheqd/tests/setupCheqdModule.ts b/packages/cheqd/tests/setupCheqdModule.ts index 885f7a2e5d..b4a6f39fea 100644 --- a/packages/cheqd/tests/setupCheqdModule.ts +++ b/packages/cheqd/tests/setupCheqdModule.ts @@ -1,16 +1,9 @@ import type { CheqdModuleConfigOptions } from '../src' import { DidsModule } from '@credo-ts/core' -import { IndySdkModule, IndySdkModuleConfig } from '@credo-ts/indy-sdk' -import indySdk from 'indy-sdk' import { CheqdModule, CheqdDidRegistrar, CheqdDidResolver } from '../src' -export const getIndySdkModuleConfig = () => - new IndySdkModuleConfig({ - indySdk, - }) - export const getCheqdModuleConfig = (seed?: string, rpcUrl?: string) => ({ networks: [ @@ -30,5 +23,4 @@ export const getCheqdModules = (seed?: string, rpcUrl?: string) => ({ registrars: [new CheqdDidRegistrar()], resolvers: [new CheqdDidResolver()], }), - indySdk: new IndySdkModule(getIndySdkModuleConfig()), }) diff --git a/packages/core/src/agent/Agent.ts b/packages/core/src/agent/Agent.ts index 952e610c82..9c25006433 100644 --- a/packages/core/src/agent/Agent.ts +++ b/packages/core/src/agent/Agent.ts @@ -79,7 +79,7 @@ export class Agent extends BaseAge // Register possibly already defined services if (!dependencyManager.isRegistered(InjectionSymbols.Wallet)) { throw new AriesFrameworkError( - "Missing required dependency: 'Wallet'. You can register it using one of the provided modules such as the AskarModule or the IndySdkModule, or implement your own." + "Missing required dependency: 'Wallet'. You can register it using the AskarModule, or implement your own." ) } if (!dependencyManager.isRegistered(InjectionSymbols.Logger)) { @@ -87,7 +87,7 @@ export class Agent extends BaseAge } if (!dependencyManager.isRegistered(InjectionSymbols.StorageService)) { throw new AriesFrameworkError( - "Missing required dependency: 'StorageService'. You can register it using one of the provided modules such as the AskarModule or the IndySdkModule, or implement your own." + "Missing required dependency: 'StorageService'. You can register it using the AskarModule, or implement your own." ) } if (!dependencyManager.isRegistered(InjectionSymbols.MessageRepository)) { diff --git a/packages/core/src/agent/Dispatcher.ts b/packages/core/src/agent/Dispatcher.ts index 5301745040..4a2bf62a38 100644 --- a/packages/core/src/agent/Dispatcher.ts +++ b/packages/core/src/agent/Dispatcher.ts @@ -89,11 +89,7 @@ class Dispatcher { outboundMessage.inboundMessageContext = messageContext } - if (outboundMessage.isOutboundServiceMessage()) { - await this.messageSender.sendMessageToService(outboundMessage) - } else { - await this.messageSender.sendMessage(outboundMessage) - } + await this.messageSender.sendMessage(outboundMessage) } // Emit event that allows to hook into received messages this.eventEmitter.emit(agentContext, { diff --git a/packages/core/src/agent/MessageSender.ts b/packages/core/src/agent/MessageSender.ts index 215aba845e..82efd2129d 100644 --- a/packages/core/src/agent/MessageSender.ts +++ b/packages/core/src/agent/MessageSender.ts @@ -219,6 +219,7 @@ export class MessageSender { if (session) { this.logger.debug(`Found session with return routing for message '${message.id}' (connection '${connection.id}'`) + try { await this.sendMessageToSession(agentContext, session, message) this.emitMessageSentEvent(outboundMessageContext, OutboundMessageSendStatus.SentToSession) @@ -348,10 +349,7 @@ export class MessageSender { ) } - /** - * @deprecated Use `sendMessage` directly instead. Will be made private in 0.5.0 - */ - public async sendMessageToService(outboundMessageContext: OutboundMessageContext) { + private async sendMessageToService(outboundMessageContext: OutboundMessageContext) { const session = this.findSessionForOutboundContext(outboundMessageContext) if (session) { diff --git a/packages/core/src/agent/__tests__/Agent.test.ts b/packages/core/src/agent/__tests__/Agent.test.ts index cddd819d76..662dd2ccc6 100644 --- a/packages/core/src/agent/__tests__/Agent.test.ts +++ b/packages/core/src/agent/__tests__/Agent.test.ts @@ -2,8 +2,8 @@ import type { DependencyManager, Module } from '../../plugins' import { injectable } from 'tsyringe' -import { getIndySdkModules } from '../../../../indy-sdk/tests/setupIndySdkModule' -import { getAgentOptions } from '../../../tests/helpers' +import { InMemoryWalletModule } from '../../../../../tests/InMemoryWalletModule' +import { getInMemoryAgentOptions } from '../../../tests/helpers' import { InjectionSymbols } from '../../constants' import { BasicMessageRepository, BasicMessageService } from '../../modules/basic-messages' import { BasicMessagesApi } from '../../modules/basic-messages/BasicMessagesApi' @@ -34,7 +34,7 @@ import { FeatureRegistry } from '../FeatureRegistry' import { MessageReceiver } from '../MessageReceiver' import { MessageSender } from '../MessageSender' -const agentOptions = getAgentOptions('Agent Class Test', {}, getIndySdkModules()) +const agentOptions = getInMemoryAgentOptions('Agent Class Test') const myModuleMethod = jest.fn() @injectable() @@ -62,7 +62,7 @@ describe('Agent', () => { ...agentOptions, modules: { myModule: new MyModule(), - ...getIndySdkModules(), + inMemory: new InMemoryWalletModule(), }, }) @@ -80,7 +80,7 @@ describe('Agent', () => { mediationRecipient: new MediationRecipientModule({ maximumMessagePickup: 42, }), - ...getIndySdkModules(), + inMemory: new InMemoryWalletModule(), }, }) diff --git a/packages/core/src/agent/__tests__/MessageSender.test.ts b/packages/core/src/agent/__tests__/MessageSender.test.ts index 6c96bf1008..4312591684 100644 --- a/packages/core/src/agent/__tests__/MessageSender.test.ts +++ b/packages/core/src/agent/__tests__/MessageSender.test.ts @@ -335,6 +335,7 @@ describe('MessageSender', () => { transportServiceFindSessionByIdMock.mockReturnValue(session) messageSender.registerOutboundTransport(outboundTransport) const sendMessageSpy = jest.spyOn(outboundTransport, 'sendMessage') + // @ts-ignore const sendMessageToServiceSpy = jest.spyOn(messageSender, 'sendMessageToService') const contextWithSessionId = new OutboundMessageContext(outboundMessageContext.message, { @@ -521,7 +522,7 @@ describe('MessageSender', () => { service, }, }) - await expect(messageSender.sendMessageToService(outboundMessageContext)).rejects.toThrow( + await expect(messageSender.sendMessage(outboundMessageContext)).rejects.toThrow( `Agent has no outbound transport!` ) @@ -549,7 +550,7 @@ describe('MessageSender', () => { }, }) - await messageSender.sendMessageToService(outboundMessageContext) + await messageSender.sendMessage(outboundMessageContext) expect(eventListenerMock).toHaveBeenCalledWith({ type: AgentEventTypes.AgentMessageSent, @@ -585,7 +586,7 @@ describe('MessageSender', () => { }, }) - await messageSender.sendMessageToService(outboundMessageContext) + await messageSender.sendMessage(outboundMessageContext) expect(eventListenerMock).toHaveBeenCalledWith({ type: AgentEventTypes.AgentMessageSent, @@ -616,7 +617,7 @@ describe('MessageSender', () => { }, }) - await expect(messageSender.sendMessageToService(outboundMessageContext)).rejects.toThrow( + await expect(messageSender.sendMessage(outboundMessageContext)).rejects.toThrow( /Unable to send message to service/ ) expect(eventListenerMock).toHaveBeenCalledWith({ diff --git a/packages/core/src/crypto/__tests__/JwsService.test.ts b/packages/core/src/crypto/__tests__/JwsService.test.ts index f43de829a1..d6654aaa0d 100644 --- a/packages/core/src/crypto/__tests__/JwsService.test.ts +++ b/packages/core/src/crypto/__tests__/JwsService.test.ts @@ -1,15 +1,14 @@ import type { AgentContext } from '../../agent' import type { Key, Wallet } from '@credo-ts/core' -import { RegisteredAskarTestWallet } from '../../../../askar/tests/helpers' -import { agentDependencies, getAgentConfig, getAgentContext } from '../../../tests/helpers' +import { InMemoryWallet } from '../../../../../tests/InMemoryWallet' +import { getAgentConfig, getAgentContext } from '../../../tests/helpers' import { DidKey } from '../../modules/dids' import { JsonEncoder, TypedArrayEncoder } from '../../utils' import { JwsService } from '../JwsService' import { KeyType } from '../KeyType' import { JwaSignatureAlgorithm } from '../jose/jwa' import { getJwkFromKey } from '../jose/jwk' -import { SigningProviderRegistry } from '../signing-provider' import * as didJwsz6Mkf from './__fixtures__/didJwsz6Mkf' import * as didJwsz6Mkv from './__fixtures__/didJwsz6Mkv' @@ -25,11 +24,7 @@ describe('JwsService', () => { beforeAll(async () => { const config = getAgentConfig('JwsService') - wallet = new RegisteredAskarTestWallet( - config.logger, - new agentDependencies.FileSystem(), - new SigningProviderRegistry([]) - ) + wallet = new InMemoryWallet() agentContext = getAgentContext({ wallet, }) diff --git a/packages/core/src/decorators/signature/SignatureDecoratorUtils.test.ts b/packages/core/src/decorators/signature/SignatureDecoratorUtils.test.ts index 93d3610f29..e3fbdbfe11 100644 --- a/packages/core/src/decorators/signature/SignatureDecoratorUtils.test.ts +++ b/packages/core/src/decorators/signature/SignatureDecoratorUtils.test.ts @@ -1,10 +1,8 @@ import type { Wallet } from '../../wallet' -import { IndySdkWallet } from '../../../../indy-sdk/src' -import { indySdk } from '../../../../indy-sdk/tests/setupIndySdkModule' +import { InMemoryWallet } from '../../../../../tests/InMemoryWallet' import { getAgentConfig } from '../../../tests/helpers' import { KeyType } from '../../crypto' -import { SigningProviderRegistry } from '../../crypto/signing-provider' import { TypedArrayEncoder } from '../../utils' import { SignatureDecorator } from './SignatureDecorator' @@ -47,7 +45,7 @@ describe('Decorators | Signature | SignatureDecoratorUtils', () => { beforeAll(async () => { const config = getAgentConfig('SignatureDecoratorUtilsTest') - wallet = new IndySdkWallet(indySdk, config.logger, new SigningProviderRegistry([])) + wallet = new InMemoryWallet() // eslint-disable-next-line @typescript-eslint/no-non-null-assertion await wallet.createAndOpen(config.walletConfig!) }) diff --git a/packages/core/src/modules/basic-messages/__tests__/basic-messages.e2e.test.ts b/packages/core/src/modules/basic-messages/__tests__/basic-messages.e2e.test.ts index 77f746030c..57ceae6bb5 100644 --- a/packages/core/src/modules/basic-messages/__tests__/basic-messages.e2e.test.ts +++ b/packages/core/src/modules/basic-messages/__tests__/basic-messages.e2e.test.ts @@ -6,29 +6,20 @@ import { Subject } from 'rxjs' import { SubjectInboundTransport } from '../../../../../../tests/transport/SubjectInboundTransport' import { SubjectOutboundTransport } from '../../../../../../tests/transport/SubjectOutboundTransport' -import { getIndySdkModules } from '../../../../../indy-sdk/tests/setupIndySdkModule' -import { getAgentOptions, makeConnection, waitForBasicMessage } from '../../../../tests/helpers' +import { getInMemoryAgentOptions, makeConnection, waitForBasicMessage } from '../../../../tests/helpers' import testLogger from '../../../../tests/logger' import { Agent } from '../../../agent/Agent' import { MessageSendingError, RecordNotFoundError } from '../../../error' import { BasicMessage } from '../messages' import { BasicMessageRecord } from '../repository' -const faberConfig = getAgentOptions( - 'Faber Basic Messages', - { - endpoints: ['rxjs:faber'], - }, - getIndySdkModules() -) - -const aliceConfig = getAgentOptions( - 'Alice Basic Messages', - { - endpoints: ['rxjs:alice'], - }, - getIndySdkModules() -) +const faberConfig = getInMemoryAgentOptions('Faber Basic Messages', { + endpoints: ['rxjs:faber'], +}) + +const aliceConfig = getInMemoryAgentOptions('Alice Basic Messages', { + endpoints: ['rxjs:alice'], +}) describe('Basic Messages E2E', () => { let faberAgent: Agent diff --git a/packages/core/src/modules/connections/__tests__/ConnectionService.test.ts b/packages/core/src/modules/connections/__tests__/ConnectionService.test.ts index 378596a888..6ec32e78c3 100644 --- a/packages/core/src/modules/connections/__tests__/ConnectionService.test.ts +++ b/packages/core/src/modules/connections/__tests__/ConnectionService.test.ts @@ -5,8 +5,7 @@ import type { Routing } from '../services/ConnectionService' import { Subject } from 'rxjs' -import { IndySdkWallet } from '../../../../../indy-sdk/src' -import { indySdk } from '../../../../../indy-sdk/tests/setupIndySdkModule' +import { InMemoryWallet } from '../../../../../../tests/InMemoryWallet' import { getAgentConfig, getAgentContext, @@ -18,7 +17,6 @@ import { AgentMessage } from '../../../agent/AgentMessage' import { EventEmitter } from '../../../agent/EventEmitter' import { InboundMessageContext } from '../../../agent/models/InboundMessageContext' import { Key, KeyType } from '../../../crypto' -import { SigningProviderRegistry } from '../../../crypto/signing-provider' import { signData, unpackAndVerifySignatureDecorator } from '../../../decorators/signature/SignatureDecoratorUtils' import { JsonTransformer } from '../../../utils/JsonTransformer' import { indyDidFromPublicKeyBase58 } from '../../../utils/did' @@ -92,7 +90,7 @@ describe('ConnectionService', () => { let agentContext: AgentContext beforeAll(async () => { - wallet = new IndySdkWallet(indySdk, agentConfig.logger, new SigningProviderRegistry([])) + wallet = new InMemoryWallet() agentContext = getAgentContext({ wallet, agentConfig, diff --git a/packages/core/src/modules/connections/__tests__/connection-manual.e2e.test.ts b/packages/core/src/modules/connections/__tests__/connection-manual.e2e.test.ts index 9e029a27df..fe519c8950 100644 --- a/packages/core/src/modules/connections/__tests__/connection-manual.e2e.test.ts +++ b/packages/core/src/modules/connections/__tests__/connection-manual.e2e.test.ts @@ -4,9 +4,8 @@ import type { ConnectionStateChangedEvent } from '../ConnectionEvents' import { firstValueFrom } from 'rxjs' import { filter, first, map, timeout } from 'rxjs/operators' -import { getIndySdkModules } from '../../../../../indy-sdk/tests/setupIndySdkModule' import { setupSubjectTransports } from '../../../../tests' -import { getAgentOptions } from '../../../../tests/helpers' +import { getInMemoryAgentOptions } from '../../../../tests/helpers' import { Agent } from '../../../agent/Agent' import { ConnectionEventTypes } from '../ConnectionEvents' import { ConnectionsModule } from '../ConnectionsModule' @@ -46,39 +45,36 @@ describe('Manual Connection Flow', () => { // This test was added to reproduce a bug where all connections based on a reusable invitation would use the same keys // This was only present in the manual flow, which is almost never used. it('can connect multiple times using the same reusable invitation without manually using the connections api', async () => { - const aliceAgentOptions = getAgentOptions( + const aliceAgentOptions = getInMemoryAgentOptions( 'Manual Connection Flow Alice', { label: 'alice', endpoints: ['rxjs:alice'], }, { - ...getIndySdkModules(), connections: new ConnectionsModule({ autoAcceptConnections: false, }), } ) - const bobAgentOptions = getAgentOptions( + const bobAgentOptions = getInMemoryAgentOptions( 'Manual Connection Flow Bob', { label: 'bob', endpoints: ['rxjs:bob'], }, { - ...getIndySdkModules(), connections: new ConnectionsModule({ autoAcceptConnections: false, }), } ) - const faberAgentOptions = getAgentOptions( + const faberAgentOptions = getInMemoryAgentOptions( 'Manual Connection Flow Faber', { endpoints: ['rxjs:faber'], }, { - ...getIndySdkModules(), connections: new ConnectionsModule({ autoAcceptConnections: false, }), diff --git a/packages/core/src/modules/connections/__tests__/did-rotate.e2e.test.ts b/packages/core/src/modules/connections/__tests__/did-rotate.e2e.test.ts index 14c8496094..a6f885cb5f 100644 --- a/packages/core/src/modules/connections/__tests__/did-rotate.e2e.test.ts +++ b/packages/core/src/modules/connections/__tests__/did-rotate.e2e.test.ts @@ -5,10 +5,9 @@ import type { ConnectionRecord } from '../repository' import { ReplaySubject, first, firstValueFrom, timeout } from 'rxjs' import { MessageSender } from '../../..//agent/MessageSender' -import { getIndySdkModules } from '../../../../../indy-sdk/tests/setupIndySdkModule' import { setupSubjectTransports, testLogger } from '../../../../tests' import { - getAgentOptions, + getInMemoryAgentOptions, makeConnection, waitForAgentMessageProcessedEvent, waitForBasicMessage, @@ -32,7 +31,7 @@ describe('Rotation E2E tests', () => { let bobAliceConnection: ConnectionRecord | undefined beforeEach(async () => { - const aliceAgentOptions = getAgentOptions( + const aliceAgentOptions = getInMemoryAgentOptions( 'DID Rotate Alice', { label: 'alice', @@ -40,13 +39,12 @@ describe('Rotation E2E tests', () => { logger: testLogger, }, { - ...getIndySdkModules(), connections: new ConnectionsModule({ autoAcceptConnections: true, }), } ) - const bobAgentOptions = getAgentOptions( + const bobAgentOptions = getInMemoryAgentOptions( 'DID Rotate Bob', { label: 'bob', @@ -54,7 +52,6 @@ describe('Rotation E2E tests', () => { logger: testLogger, }, { - ...getIndySdkModules(), connections: new ConnectionsModule({ autoAcceptConnections: true, }), diff --git a/packages/core/src/modules/connections/__tests__/didexchange-numalgo.e2e.test.ts b/packages/core/src/modules/connections/__tests__/didexchange-numalgo.e2e.test.ts index 50cf2742ee..3edcc48d0f 100644 --- a/packages/core/src/modules/connections/__tests__/didexchange-numalgo.e2e.test.ts +++ b/packages/core/src/modules/connections/__tests__/didexchange-numalgo.e2e.test.ts @@ -4,9 +4,8 @@ import type { ConnectionStateChangedEvent } from '../ConnectionEvents' import { firstValueFrom } from 'rxjs' import { filter, first, map, timeout } from 'rxjs/operators' -import { getIndySdkModules } from '../../../../../indy-sdk/tests/setupIndySdkModule' import { setupSubjectTransports } from '../../../../tests' -import { getAgentOptions } from '../../../../tests/helpers' +import { getInMemoryAgentOptions } from '../../../../tests/helpers' import { Agent } from '../../../agent/Agent' import { uuid } from '../../../utils/uuid' import { DidsModule, PeerDidNumAlgo, createPeerDidDocumentFromServices } from '../../dids' @@ -96,14 +95,13 @@ async function didExchangeNumAlgoBaseTest(options: { // Make a common in-memory did registry for both agents const didRegistry = new InMemoryDidRegistry() - const aliceAgentOptions = getAgentOptions( + const aliceAgentOptions = getInMemoryAgentOptions( 'DID Exchange numalgo settings Alice', { label: 'alice', endpoints: ['rxjs:alice'], }, { - ...getIndySdkModules(), connections: new ConnectionsModule({ autoAcceptConnections: false, peerNumAlgoForDidExchangeRequests: options.requesterNumAlgoSetting, @@ -111,13 +109,12 @@ async function didExchangeNumAlgoBaseTest(options: { dids: new DidsModule({ registrars: [didRegistry], resolvers: [didRegistry] }), } ) - const faberAgentOptions = getAgentOptions( + const faberAgentOptions = getInMemoryAgentOptions( 'DID Exchange numalgo settings Alice', { endpoints: ['rxjs:faber'], }, { - ...getIndySdkModules(), connections: new ConnectionsModule({ autoAcceptConnections: false, peerNumAlgoForDidExchangeRequests: options.responderNumAlgoSetting, diff --git a/packages/core/src/modules/credentials/protocol/v2/__tests__/v2-connectionless-credentials.e2e.test.ts b/packages/core/src/modules/credentials/protocol/v2/__tests__/v2-connectionless-credentials.e2e.test.ts index 7fdb14f74a..2a90d4ec88 100644 --- a/packages/core/src/modules/credentials/protocol/v2/__tests__/v2-connectionless-credentials.e2e.test.ts +++ b/packages/core/src/modules/credentials/protocol/v2/__tests__/v2-connectionless-credentials.e2e.test.ts @@ -8,10 +8,10 @@ import { ReplaySubject, Subject } from 'rxjs' import { SubjectInboundTransport } from '../../../../../../../../tests/transport/SubjectInboundTransport' import { SubjectOutboundTransport } from '../../../../../../../../tests/transport/SubjectOutboundTransport' import { - getLegacyAnonCredsModules, + getAnonCredsIndyModules, prepareForAnonCredsIssuance, } from '../../../../../../../anoncreds/tests/legacyAnonCredsSetup' -import { waitForCredentialRecordSubject, getAgentOptions } from '../../../../../../tests/helpers' +import { waitForCredentialRecordSubject, getInMemoryAgentOptions } from '../../../../../../tests/helpers' import testLogger from '../../../../../../tests/logger' import { Agent } from '../../../../../agent/Agent' import { CredentialEventTypes } from '../../../CredentialEvents' @@ -20,20 +20,20 @@ import { CredentialState } from '../../../models/CredentialState' import { CredentialExchangeRecord } from '../../../repository/CredentialExchangeRecord' import { V2CredentialPreview } from '../messages' -const faberAgentOptions = getAgentOptions( +const faberAgentOptions = getInMemoryAgentOptions( 'Faber connection-less Credentials V2', { endpoints: ['rxjs:faber'], }, - getLegacyAnonCredsModules() + getAnonCredsIndyModules() ) -const aliceAgentOptions = getAgentOptions( +const aliceAgentOptions = getInMemoryAgentOptions( 'Alice connection-less Credentials V2', { endpoints: ['rxjs:alice'], }, - getLegacyAnonCredsModules() + getAnonCredsIndyModules() ) const credentialPreview = V2CredentialPreview.fromRecord({ diff --git a/packages/core/src/modules/credentials/protocol/v2/__tests__/v2-credentials-auto-accept.e2e.test.ts b/packages/core/src/modules/credentials/protocol/v2/__tests__/v2-credentials-auto-accept.e2e.test.ts index 88422a79c4..5e909c1457 100644 --- a/packages/core/src/modules/credentials/protocol/v2/__tests__/v2-credentials-auto-accept.e2e.test.ts +++ b/packages/core/src/modules/credentials/protocol/v2/__tests__/v2-credentials-auto-accept.e2e.test.ts @@ -2,11 +2,16 @@ import type { AnonCredsTestsAgent } from '../../../../../../../anoncreds/tests/l import type { EventReplaySubject } from '../../../../../../tests' import { setupAnonCredsTests } from '../../../../../../../anoncreds/tests/legacyAnonCredsSetup' -import { waitForCredentialRecord, waitForCredentialRecordSubject } from '../../../../../../tests/helpers' +import { + waitForCredentialRecord, + waitForCredentialRecordSubject, + waitForAgentMessageProcessedEventSubject, +} from '../../../../../../tests/helpers' import testLogger from '../../../../../../tests/logger' import { AutoAcceptCredential } from '../../../models/CredentialAutoAcceptType' import { CredentialState } from '../../../models/CredentialState' import { CredentialExchangeRecord } from '../../../repository/CredentialExchangeRecord' +import { V2ProposeCredentialMessage } from '../messages' import { V2CredentialPreview } from '../messages/V2CredentialPreview' describe('V2 Credentials Auto Accept', () => { @@ -435,6 +440,13 @@ describe('V2 Credentials Auto Accept', () => { state: CredentialState.ProposalReceived, threadId: aliceCredentialRecord.threadId, }) + + // ProposalReceived is emitted before the whole message is finished processing + // So to not get errors when shutting down the agent, we wait for the message to be processed + await waitForAgentMessageProcessedEventSubject(faberReplay, { + threadId: aliceCredentialRecord.threadId, + messageType: V2ProposeCredentialMessage.type.messageTypeUri, + }) }) }) }) diff --git a/packages/core/src/modules/credentials/protocol/v2/__tests__/v2.ldproof.credentials.propose-offerED25519.test.ts b/packages/core/src/modules/credentials/protocol/v2/__tests__/v2.ldproof.credentials.propose-offerED25519.test.ts index 860b29a43e..bde3f9def5 100644 --- a/packages/core/src/modules/credentials/protocol/v2/__tests__/v2.ldproof.credentials.propose-offerED25519.test.ts +++ b/packages/core/src/modules/credentials/protocol/v2/__tests__/v2.ldproof.credentials.propose-offerED25519.test.ts @@ -1,30 +1,19 @@ import type { EventReplaySubject } from '../../../../../../tests' -import { randomUUID } from 'crypto' - import { LegacyIndyCredentialFormatService, LegacyIndyProofFormatService, V1CredentialProtocol, V1ProofProtocol, - AnonCredsModule, } from '../../../../../../../anoncreds/src' -import { prepareForAnonCredsIssuance } from '../../../../../../../anoncreds/tests/legacyAnonCredsSetup' import { - IndySdkAnonCredsRegistry, - IndySdkIndyDidRegistrar, - IndySdkIndyDidResolver, - IndySdkModule, - IndySdkSovDidResolver, -} from '../../../../../../../indy-sdk/src' -import { indySdk } from '../../../../../../../indy-sdk/tests/setupIndySdkModule' + getAnonCredsIndyModules, + prepareForAnonCredsIssuance, +} from '../../../../../../../anoncreds/tests/legacyAnonCredsSetup' import { + getInMemoryAgentOptions, setupEventReplaySubjects, setupSubjectTransports, - genesisPath, - taaAcceptanceMechanism, - taaVersion, - getAgentOptions, waitForCredentialRecordSubject, testLogger, makeConnection, @@ -34,7 +23,6 @@ import { KeyType } from '../../../../../crypto' import { TypedArrayEncoder } from '../../../../../utils' import { JsonTransformer } from '../../../../../utils/JsonTransformer' import { CacheModule, InMemoryLruCache } from '../../../../cache' -import { DidsModule } from '../../../../dids' import { ProofEventTypes, ProofsModule, V2ProofProtocol } from '../../../../proofs' import { W3cCredentialsModule } from '../../../../vc' import { customDocumentLoader } from '../../../../vc/data-integrity/__tests__/documentLoader' @@ -88,6 +76,7 @@ const indyProofFormat = new LegacyIndyProofFormatService() const getIndyJsonLdModules = () => ({ + ...getAnonCredsIndyModules(), credentials: new CredentialsModule({ credentialProtocols: [ new V1CredentialProtocol({ indyCredentialFormat }), @@ -104,25 +93,6 @@ const getIndyJsonLdModules = () => }), ], }), - anoncreds: new AnonCredsModule({ - registries: [new IndySdkAnonCredsRegistry()], - }), - dids: new DidsModule({ - resolvers: [new IndySdkSovDidResolver(), new IndySdkIndyDidResolver()], - registrars: [new IndySdkIndyDidRegistrar()], - }), - indySdk: new IndySdkModule({ - indySdk, - networks: [ - { - isProduction: false, - genesisPath, - id: randomUUID(), - indyNamespace: `pool:localtest`, - transactionAuthorAgreement: { version: taaVersion, acceptanceMechanism: taaAcceptanceMechanism }, - }, - ], - }), cache: new CacheModule({ cache: new InMemoryLruCache({ limit: 100 }), }), @@ -142,7 +112,7 @@ describe('V2 Credentials - JSON-LD - Ed25519', () => { beforeAll(async () => { faberAgent = new Agent( - getAgentOptions( + getInMemoryAgentOptions( 'Faber Agent Indy/JsonLD', { endpoints: ['rxjs:faber'], @@ -151,7 +121,7 @@ describe('V2 Credentials - JSON-LD - Ed25519', () => { ) ) aliceAgent = new Agent( - getAgentOptions( + getInMemoryAgentOptions( 'Alice Agent Indy/JsonLD', { endpoints: ['rxjs:alice'], diff --git a/packages/core/src/modules/dids/__tests__/DidsApi.test.ts b/packages/core/src/modules/dids/__tests__/DidsApi.test.ts index 7760694d8d..274a5bc031 100644 --- a/packages/core/src/modules/dids/__tests__/DidsApi.test.ts +++ b/packages/core/src/modules/dids/__tests__/DidsApi.test.ts @@ -1,6 +1,4 @@ -import { IndySdkModule } from '../../../../../indy-sdk/src' -import { indySdk } from '../../../../tests' -import { getAgentOptions } from '../../../../tests/helpers' +import { getInMemoryAgentOptions } from '../../../../tests/helpers' import { Agent } from '../../../agent/Agent' import { isLongFormDidPeer4, isShortFormDidPeer4 } from '../methods/peer/peerDidNumAlgo4' @@ -13,15 +11,7 @@ import { createPeerDidDocumentFromServices, } from '@credo-ts/core' -const agentOptions = getAgentOptions( - 'DidsApi', - {}, - { - indySdk: new IndySdkModule({ - indySdk, - }), - } -) +const agentOptions = getInMemoryAgentOptions('DidsApi') const agent = new Agent(agentOptions) @@ -70,6 +60,8 @@ describe('DidsApi', () => { method: 'key', methodSpecificIdentifier: 'z6MkjEayvPpjVJKFLirX8SomBTPDboHm1XSCkUev2M4siQty', role: 'created', + alternativeDids: undefined, + recipientKeyFingerprints: [], }) expect(createdDids[0].toJSON()).toMatchObject({ @@ -153,6 +145,8 @@ describe('DidsApi', () => { method: 'peer', methodSpecificIdentifier: '0z6Mkhu3G8viiebsWmCiSgWiQoCZrTeuX76oLDow81YNYvJQM', role: 'created', + alternativeDids: undefined, + recipientKeyFingerprints: [], }) expect(createdDids[0].toJSON()).toMatchObject({ diff --git a/packages/core/src/modules/dids/__tests__/dids-registrar.e2e.test.ts b/packages/core/src/modules/dids/__tests__/dids-registrar.e2e.test.ts index 1f6478d73e..457cb2d73d 100644 --- a/packages/core/src/modules/dids/__tests__/dids-registrar.e2e.test.ts +++ b/packages/core/src/modules/dids/__tests__/dids-registrar.e2e.test.ts @@ -1,24 +1,14 @@ import type { KeyDidCreateOptions } from '../methods/key/KeyDidRegistrar' import type { PeerDidNumAlgo0CreateOptions } from '../methods/peer/PeerDidRegistrar' -import { IndySdkModule } from '../../../../../indy-sdk/src' -import { indySdk } from '../../../../tests' -import { getAgentOptions } from '../../../../tests/helpers' +import { getInMemoryAgentOptions } from '../../../../tests/helpers' import { Agent } from '../../../agent/Agent' import { KeyType } from '../../../crypto' import { PeerDidNumAlgo } from '../methods/peer/didPeer' import { JsonTransformer, TypedArrayEncoder } from '@credo-ts/core' -const agentOptions = getAgentOptions( - 'Faber Dids Registrar', - {}, - { - indySdk: new IndySdkModule({ - indySdk, - }), - } -) +const agentOptions = getInMemoryAgentOptions('Faber Dids Registrar') describe('dids', () => { let agent: Agent diff --git a/packages/core/src/modules/dids/__tests__/dids-resolver.e2e.test.ts b/packages/core/src/modules/dids/__tests__/dids-resolver.e2e.test.ts index 3e46ada4f0..feba6ee688 100644 --- a/packages/core/src/modules/dids/__tests__/dids-resolver.e2e.test.ts +++ b/packages/core/src/modules/dids/__tests__/dids-resolver.e2e.test.ts @@ -1,20 +1,8 @@ -import { IndySdkModule } from '../../../../../indy-sdk/src' -import { indySdk } from '../../../../tests' -import { getAgentOptions } from '../../../../tests/helpers' +import { getInMemoryAgentOptions } from '../../../../tests/helpers' import { Agent } from '../../../agent/Agent' import { JsonTransformer } from '../../../utils' -const agent = new Agent( - getAgentOptions( - 'Faber Dids', - {}, - { - indySdk: new IndySdkModule({ - indySdk, - }), - } - ) -) +const agent = new Agent(getInMemoryAgentOptions('Faber Dids')) describe('dids', () => { beforeAll(async () => { diff --git a/packages/core/src/modules/dids/__tests__/peer-did.test.ts b/packages/core/src/modules/dids/__tests__/peer-did.test.ts index 566e580d17..6f5afc193b 100644 --- a/packages/core/src/modules/dids/__tests__/peer-did.test.ts +++ b/packages/core/src/modules/dids/__tests__/peer-did.test.ts @@ -4,13 +4,11 @@ import type { Wallet } from '../../../wallet' import { Subject } from 'rxjs' import { InMemoryStorageService } from '../../../../../../tests/InMemoryStorageService' -import { IndySdkWallet } from '../../../../../indy-sdk/src' -import { indySdk } from '../../../../../indy-sdk/tests/setupIndySdkModule' +import { InMemoryWallet } from '../../../../../../tests/InMemoryWallet' import { getAgentConfig, getAgentContext } from '../../../../tests/helpers' import { EventEmitter } from '../../../agent/EventEmitter' import { InjectionSymbols } from '../../../constants' import { Key, KeyType } from '../../../crypto' -import { SigningProviderRegistry } from '../../../crypto/signing-provider' import { JsonTransformer, TypedArrayEncoder } from '../../../utils' import { DidsModuleConfig } from '../DidsModuleConfig' import { @@ -41,7 +39,7 @@ describe('peer dids', () => { let eventEmitter: EventEmitter beforeEach(async () => { - wallet = new IndySdkWallet(indySdk, config.logger, new SigningProviderRegistry([])) + wallet = new InMemoryWallet() const storageService = new InMemoryStorageService() eventEmitter = new EventEmitter(config.agentDependencies, new Subject()) didRepository = new DidRepository(storageService, eventEmitter) diff --git a/packages/core/src/modules/dif-presentation-exchange/DifPresentationExchangeModule.ts b/packages/core/src/modules/dif-presentation-exchange/DifPresentationExchangeModule.ts index 7cb2c86c5a..ee426de40f 100644 --- a/packages/core/src/modules/dif-presentation-exchange/DifPresentationExchangeModule.ts +++ b/packages/core/src/modules/dif-presentation-exchange/DifPresentationExchangeModule.ts @@ -16,7 +16,7 @@ export class DifPresentationExchangeModule implements Module { dependencyManager .resolve(AgentConfig) .logger.warn( - "The 'DifPresentationExchangeModule' module is experimental and could have unexpected breaking changes. When using this module, make sure to use strict versions for all @aries-framework packages." + "The 'DifPresentationExchangeModule' module is experimental and could have unexpected breaking changes. When using this module, make sure to use strict versions for all @credo-ts packages." ) // service diff --git a/packages/core/src/modules/discover-features/__tests__/v1-discover-features.e2e.test.ts b/packages/core/src/modules/discover-features/__tests__/v1-discover-features.e2e.test.ts index 68fb1a0103..9ca14efd37 100644 --- a/packages/core/src/modules/discover-features/__tests__/v1-discover-features.e2e.test.ts +++ b/packages/core/src/modules/discover-features/__tests__/v1-discover-features.e2e.test.ts @@ -6,29 +6,20 @@ import type { import { ReplaySubject } from 'rxjs' -import { getIndySdkModules } from '../../../../../indy-sdk/tests/setupIndySdkModule' import { setupSubjectTransports } from '../../../../tests' -import { getAgentOptions, makeConnection } from '../../../../tests/helpers' +import { getInMemoryAgentOptions, makeConnection } from '../../../../tests/helpers' import { Agent } from '../../../agent/Agent' import { DiscoverFeaturesEventTypes } from '../DiscoverFeaturesEvents' import { waitForDisclosureSubject, waitForQuerySubject } from './helpers' -const faberAgentOptions = getAgentOptions( - 'Faber Discover Features V1 E2E', - { - endpoints: ['rxjs:faber'], - }, - getIndySdkModules() -) - -const aliceAgentOptions = getAgentOptions( - 'Alice Discover Features V1 E2E', - { - endpoints: ['rxjs:alice'], - }, - getIndySdkModules() -) +const faberAgentOptions = getInMemoryAgentOptions('Faber Discover Features V1 E2E', { + endpoints: ['rxjs:faber'], +}) + +const aliceAgentOptions = getInMemoryAgentOptions('Alice Discover Features V1 E2E', { + endpoints: ['rxjs:alice'], +}) describe('v1 discover features', () => { let faberAgent: Agent diff --git a/packages/core/src/modules/discover-features/__tests__/v2-discover-features.e2e.test.ts b/packages/core/src/modules/discover-features/__tests__/v2-discover-features.e2e.test.ts index f5a4b9f782..c76a574992 100644 --- a/packages/core/src/modules/discover-features/__tests__/v2-discover-features.e2e.test.ts +++ b/packages/core/src/modules/discover-features/__tests__/v2-discover-features.e2e.test.ts @@ -6,30 +6,21 @@ import type { import { ReplaySubject } from 'rxjs' -import { getIndySdkModules } from '../../../../../indy-sdk/tests/setupIndySdkModule' import { setupSubjectTransports } from '../../../../tests' -import { getAgentOptions, makeConnection } from '../../../../tests/helpers' +import { getInMemoryAgentOptions, makeConnection } from '../../../../tests/helpers' import { Agent } from '../../../agent/Agent' import { GoalCode, Feature } from '../../../agent/models' import { DiscoverFeaturesEventTypes } from '../DiscoverFeaturesEvents' import { waitForDisclosureSubject, waitForQuerySubject } from './helpers' -const faberAgentOptions = getAgentOptions( - 'Faber Discover Features V2 E2E', - { - endpoints: ['rxjs:faber'], - }, - getIndySdkModules() -) - -const aliceAgentOptions = getAgentOptions( - 'Alice Discover Features V2 E2E', - { - endpoints: ['rxjs:alice'], - }, - getIndySdkModules() -) +const faberAgentOptions = getInMemoryAgentOptions('Faber Discover Features V2 E2E', { + endpoints: ['rxjs:faber'], +}) + +const aliceAgentOptions = getInMemoryAgentOptions('Alice Discover Features V2 E2E', { + endpoints: ['rxjs:alice'], +}) describe('v2 discover features', () => { let faberAgent: Agent diff --git a/packages/core/src/modules/message-pickup/__tests__/pickup.test.ts b/packages/core/src/modules/message-pickup/__tests__/pickup.test.ts index 6285f2828d..beb622c7fd 100644 --- a/packages/core/src/modules/message-pickup/__tests__/pickup.test.ts +++ b/packages/core/src/modules/message-pickup/__tests__/pickup.test.ts @@ -5,19 +5,15 @@ import { Subject } from 'rxjs' import { SubjectInboundTransport } from '../../../../../../tests/transport/SubjectInboundTransport' import { SubjectOutboundTransport } from '../../../../../../tests/transport/SubjectOutboundTransport' -import { getIndySdkModules } from '../../../../../indy-sdk/tests/setupIndySdkModule' -import { getAgentOptions, waitForBasicMessage, waitForTrustPingReceivedEvent } from '../../../../tests/helpers' +import { getInMemoryAgentOptions, waitForBasicMessage, waitForTrustPingReceivedEvent } from '../../../../tests/helpers' import { Agent } from '../../../agent/Agent' import { HandshakeProtocol } from '../../connections' -const recipientOptions = getAgentOptions('Mediation: Recipient Pickup', {}, getIndySdkModules()) -const mediatorOptions = getAgentOptions( - 'Mediation: Mediator Pickup', - { - endpoints: ['wss://mediator'], - }, - getIndySdkModules() -) +const recipientOptions = getInMemoryAgentOptions('Mediation: Recipient Pickup') +const mediatorOptions = getInMemoryAgentOptions('Mediation: Mediator Pickup', { + // Agent is shutdown during test, so we can't use in-memory wallet + endpoints: ['wss://mediator'], +}) describe('E2E Pick Up protocol', () => { let recipientAgent: Agent @@ -72,9 +68,6 @@ describe('E2E Pick Up protocol', () => { // Now they are connected, reinitialize recipient agent in order to lose the session (as with SubjectTransport it remains open) await recipientAgent.shutdown() - - recipientAgent = new Agent(recipientOptions) - recipientAgent.registerOutboundTransport(new SubjectOutboundTransport(subjectMap)) await recipientAgent.initialize() const message = 'hello pickup V1' diff --git a/packages/core/src/modules/oob/__tests__/connect-to-self.e2e.test.ts b/packages/core/src/modules/oob/__tests__/connect-to-self.e2e.test.ts index 6f80f36419..2532e9e0af 100644 --- a/packages/core/src/modules/oob/__tests__/connect-to-self.e2e.test.ts +++ b/packages/core/src/modules/oob/__tests__/connect-to-self.e2e.test.ts @@ -5,20 +5,15 @@ import { Subject } from 'rxjs' import { SubjectInboundTransport } from '../../../../../../tests/transport/SubjectInboundTransport' import { SubjectOutboundTransport } from '../../../../../../tests/transport/SubjectOutboundTransport' -import { getIndySdkModules } from '../../../../../indy-sdk/tests/setupIndySdkModule' -import { getAgentOptions } from '../../../../tests/helpers' +import { getInMemoryAgentOptions } from '../../../../tests/helpers' import { HandshakeProtocol, DidExchangeState } from '../../connections' import { OutOfBandState } from '../domain/OutOfBandState' import { Agent } from '@credo-ts/core' -const faberAgentOptions = getAgentOptions( - 'Faber Agent OOB Connect to Self', - { - endpoints: ['rxjs:faber'], - }, - getIndySdkModules() -) +const faberAgentOptions = getInMemoryAgentOptions('Faber Agent OOB Connect to Self', { + endpoints: ['rxjs:faber'], +}) describe('out of band', () => { let faberAgent: Agent diff --git a/packages/core/src/modules/oob/__tests__/implicit.e2e.test.ts b/packages/core/src/modules/oob/__tests__/implicit.e2e.test.ts index 388622da0d..41535e27ae 100644 --- a/packages/core/src/modules/oob/__tests__/implicit.e2e.test.ts +++ b/packages/core/src/modules/oob/__tests__/implicit.e2e.test.ts @@ -1,10 +1,10 @@ /* eslint-disable @typescript-eslint/no-non-null-assertion */ -import type { IndySdkIndyDidCreateOptions } from '@credo-ts/indy-sdk' +import type { IndyVdrDidCreateOptions } from '@credo-ts/indy-vdr' -import { getLegacyAnonCredsModules } from '../../../../../anoncreds/tests/legacyAnonCredsSetup' +import { getAnonCredsIndyModules } from '../../../../../anoncreds/tests/legacyAnonCredsSetup' import { setupSubjectTransports } from '../../../../tests' import { - getAgentOptions, + getInMemoryAgentOptions, importExistingIndyDidFromPrivateKey, publicDidSeed, waitForConnectionRecord, @@ -13,20 +13,21 @@ import { Agent } from '../../../agent/Agent' import { TypedArrayEncoder } from '../../../utils' import { sleep } from '../../../utils/sleep' import { DidExchangeState, HandshakeProtocol } from '../../connections' +import { DidCommV1Service, DidCommV2Service, DidDocumentService } from '../../dids' -const faberAgentOptions = getAgentOptions( +const faberAgentOptions = getInMemoryAgentOptions( 'Faber Agent OOB Implicit', { endpoints: ['rxjs:faber'], }, - getLegacyAnonCredsModules() + getAnonCredsIndyModules() ) -const aliceAgentOptions = getAgentOptions( +const aliceAgentOptions = getInMemoryAgentOptions( 'Alice Agent OOB Implicit', { endpoints: ['rxjs:alice'], }, - getLegacyAnonCredsModules() + getAnonCredsIndyModules() ) describe('out of band implicit', () => { @@ -230,15 +231,34 @@ describe('out of band implicit', () => { }) async function createPublicDid(agent: Agent, unqualifiedSubmitterDid: string, endpoint: string) { - const createResult = await agent.dids.create({ + const createResult = await agent.dids.create({ method: 'indy', options: { - submitterDid: `did:indy:pool:localtest:${unqualifiedSubmitterDid}`, + endorserMode: 'internal', + endorserDid: `did:indy:pool:localtest:${unqualifiedSubmitterDid}`, + useEndpointAttrib: true, + services: [ + new DidDocumentService({ + id: `#endpoint`, + serviceEndpoint: endpoint, + type: 'endpoint', + }), + new DidCommV1Service({ + id: `#did-communication`, + priority: 0, + recipientKeys: [`#key-agreement-1`], + routingKeys: [], + serviceEndpoint: endpoint, + accept: ['didcomm/aip2;env=rfc19'], + }), + new DidCommV2Service({ + accept: ['didcomm/v2'], + id: `#didcomm-1`, + routingKeys: [], + serviceEndpoint: endpoint, + }), + ], alias: 'Alias', - endpoints: { - endpoint, - types: ['DIDComm', 'did-communication', 'endpoint'], - }, }, }) diff --git a/packages/core/src/modules/proofs/formats/dif-presentation-exchange/__tests__/PresentationExchangeProofFormatService.test.ts b/packages/core/src/modules/proofs/formats/dif-presentation-exchange/__tests__/PresentationExchangeProofFormatService.test.ts index 316927aaf8..f2b82f120c 100644 --- a/packages/core/src/modules/proofs/formats/dif-presentation-exchange/__tests__/PresentationExchangeProofFormatService.test.ts +++ b/packages/core/src/modules/proofs/formats/dif-presentation-exchange/__tests__/PresentationExchangeProofFormatService.test.ts @@ -4,8 +4,7 @@ import type { DifPresentationExchangeProofFormat } from '../DifPresentationExcha import { PresentationSubmissionLocation } from '@sphereon/pex' -import { getIndySdkModules } from '../../../../../../../indy-sdk/tests/setupIndySdkModule' -import { agentDependencies, getAgentConfig } from '../../../../../../tests' +import { getInMemoryAgentOptions } from '../../../../../../tests' import { Agent } from '../../../../../agent/Agent' import { DifPresentationExchangeModule, DifPresentationExchangeService } from '../../../../dif-presentation-exchange' import { @@ -92,17 +91,18 @@ describe('Presentation Exchange ProofFormatService', () => { let agent: Agent beforeAll(async () => { - agent = new Agent({ - config: getAgentConfig('PresentationExchangeProofFormatService'), - modules: { - someModule: new DifPresentationExchangeModule(), - proofs: new ProofsModule({ - proofProtocols: [new V2ProofProtocol({ proofFormats: [new PresentationExchangeProofFormatService()] })], - }), - ...getIndySdkModules(), - }, - dependencies: agentDependencies, - }) + agent = new Agent( + getInMemoryAgentOptions( + 'PresentationExchangeProofFormatService', + {}, + { + pex: new DifPresentationExchangeModule(), + proofs: new ProofsModule({ + proofProtocols: [new V2ProofProtocol({ proofFormats: [new PresentationExchangeProofFormatService()] })], + }), + } + ) + ) await agent.initialize() diff --git a/packages/core/src/modules/proofs/protocol/v2/__tests__/v2-indy-connectionless-proofs.e2e.test.ts b/packages/core/src/modules/proofs/protocol/v2/__tests__/v2-indy-connectionless-proofs.e2e.test.ts index e83dc5809a..4fecad52ea 100644 --- a/packages/core/src/modules/proofs/protocol/v2/__tests__/v2-indy-connectionless-proofs.e2e.test.ts +++ b/packages/core/src/modules/proofs/protocol/v2/__tests__/v2-indy-connectionless-proofs.e2e.test.ts @@ -7,18 +7,18 @@ import { SubjectInboundTransport } from '../../../../../../../../tests/transport import { SubjectOutboundTransport } from '../../../../../../../../tests/transport/SubjectOutboundTransport' import { V1CredentialPreview } from '../../../../../../../anoncreds/src' import { - getLegacyAnonCredsModules, + getAnonCredsIndyModules, issueLegacyAnonCredsCredential, prepareForAnonCredsIssuance, setupAnonCredsTests, } from '../../../../../../../anoncreds/tests/legacyAnonCredsSetup' import { waitForProofExchangeRecordSubject, - getAgentOptions, makeConnection, testLogger, setupEventReplaySubjects, waitForProofExchangeRecord, + getInMemoryAgentOptions, } from '../../../../../../tests' import { Agent } from '../../../../../agent/Agent' import { Attachment, AttachmentData } from '../../../../../decorators/attachment/Attachment' @@ -265,13 +265,13 @@ describe('V2 Connectionless Proofs - Indy', () => { const unique = uuid().substring(0, 4) - const mediatorOptions = getAgentOptions( + const mediatorOptions = getInMemoryAgentOptions( `Connectionless proofs with mediator Mediator-${unique}`, { endpoints: ['rxjs:mediator'], }, { - ...getLegacyAnonCredsModules({ + ...getAnonCredsIndyModules({ autoAcceptProofs: AutoAcceptProof.Always, }), mediator: new MediatorModule({ @@ -299,11 +299,11 @@ describe('V2 Connectionless Proofs - Indy', () => { handshakeProtocols: [HandshakeProtocol.Connections], }) - const faberOptions = getAgentOptions( + const faberOptions = getInMemoryAgentOptions( `Connectionless proofs with mediator Faber-${unique}`, {}, { - ...getLegacyAnonCredsModules({ + ...getAnonCredsIndyModules({ autoAcceptProofs: AutoAcceptProof.Always, }), mediationRecipient: new MediationRecipientModule({ @@ -315,11 +315,11 @@ describe('V2 Connectionless Proofs - Indy', () => { } ) - const aliceOptions = getAgentOptions( + const aliceOptions = getInMemoryAgentOptions( `Connectionless proofs with mediator Alice-${unique}`, {}, { - ...getLegacyAnonCredsModules({ + ...getAnonCredsIndyModules({ autoAcceptProofs: AutoAcceptProof.Always, }), mediationRecipient: new MediationRecipientModule({ diff --git a/packages/core/src/modules/proofs/protocol/v2/__tests__/v2-indy-proofs.e2e.test.ts b/packages/core/src/modules/proofs/protocol/v2/__tests__/v2-indy-proofs.e2e.test.ts index 29a7fce4c8..a942e4744f 100644 --- a/packages/core/src/modules/proofs/protocol/v2/__tests__/v2-indy-proofs.e2e.test.ts +++ b/packages/core/src/modules/proofs/protocol/v2/__tests__/v2-indy-proofs.e2e.test.ts @@ -345,11 +345,16 @@ describe('Present Proof', () => { presentation: { indy: { proof: { + // FIXME: Indy SDK only had one proof: https://github.com/hyperledger/anoncreds-rs/issues/292 proofs: [ { primary_proof: expect.any(Object), non_revoc_proof: null, }, + { + primary_proof: expect.any(Object), + non_revoc_proof: null, + }, ], aggregated_proof: { c_hash: expect.any(String), diff --git a/packages/core/src/modules/proofs/protocol/v2/__tests__/v2-presentation-exchange-presentation.e2e.test.ts b/packages/core/src/modules/proofs/protocol/v2/__tests__/v2-presentation-exchange-presentation.e2e.test.ts index a0901029a6..fdea6b6698 100644 --- a/packages/core/src/modules/proofs/protocol/v2/__tests__/v2-presentation-exchange-presentation.e2e.test.ts +++ b/packages/core/src/modules/proofs/protocol/v2/__tests__/v2-presentation-exchange-presentation.e2e.test.ts @@ -110,7 +110,7 @@ describe('Present Proof', () => { const verifierProofExchangeRecord = await verifierPresentationRecordPromise const didCommMessageRepository = - proverAgent.dependencyManager.resolve(DidCommMessageRepository) + verifierAgent.dependencyManager.resolve(DidCommMessageRepository) const proposal = await didCommMessageRepository.findAgentMessage(verifierAgent.context, { associatedRecordId: verifierProofExchangeRecord.id, diff --git a/packages/core/src/modules/routing/__tests__/mediation.test.ts b/packages/core/src/modules/routing/__tests__/mediation.test.ts index 574f999297..cd5b284cdf 100644 --- a/packages/core/src/modules/routing/__tests__/mediation.test.ts +++ b/packages/core/src/modules/routing/__tests__/mediation.test.ts @@ -8,8 +8,7 @@ import { Subject } from 'rxjs' import { SubjectInboundTransport } from '../../../../../../tests/transport/SubjectInboundTransport' import { SubjectOutboundTransport } from '../../../../../../tests/transport/SubjectOutboundTransport' -import { getIndySdkModules } from '../../../../../indy-sdk/tests/setupIndySdkModule' -import { getAgentOptions, waitForBasicMessage } from '../../../../tests/helpers' +import { getInMemoryAgentOptions, waitForBasicMessage } from '../../../../tests/helpers' import { Agent } from '../../../agent/Agent' import { sleep } from '../../../utils/sleep' import { ConnectionRecord, HandshakeProtocol } from '../../connections' @@ -18,27 +17,22 @@ import { MediatorModule } from '../MediatorModule' import { MediatorPickupStrategy } from '../MediatorPickupStrategy' import { MediationState } from '../models/MediationState' -const recipientAgentOptions = getAgentOptions('Mediation: Recipient', {}, getIndySdkModules()) -const mediatorAgentOptions = getAgentOptions( +const recipientAgentOptions = getInMemoryAgentOptions('Mediation: Recipient') +const mediatorAgentOptions = getInMemoryAgentOptions( 'Mediation: Mediator', { endpoints: ['rxjs:mediator'], }, { - ...getIndySdkModules(), mediator: new MediatorModule({ autoAcceptMediationRequests: true, }), } ) -const senderAgentOptions = getAgentOptions( - 'Mediation: Sender', - { - endpoints: ['rxjs:sender'], - }, - getIndySdkModules() -) +const senderAgentOptions = getInMemoryAgentOptions('Mediation: Sender', { + endpoints: ['rxjs:sender'], +}) describe('mediator establishment', () => { let recipientAgent: Agent @@ -245,22 +239,10 @@ describe('mediator establishment', () => { expect(recipientMediator?.state).toBe(MediationState.Granted) + await recipientAgent.mediationRecipient.stopMessagePickup() + // Restart recipient agent await recipientAgent.shutdown() - recipientAgent = new Agent({ - ...recipientAgentOptions, - modules: { - ...recipientAgentOptions.modules, - mediationRecipient: new MediationRecipientModule({ - mediatorInvitationUrl: mediatorOutOfBandRecord.outOfBandInvitation.toUrl({ - domain: 'https://example.com/ssi', - }), - mediatorPickupStrategy: MediatorPickupStrategy.PickUpV1, - }), - }, - }) - recipientAgent.registerOutboundTransport(new SubjectOutboundTransport(subjectMap)) - recipientAgent.registerInboundTransport(new SubjectInboundTransport(recipientMessages)) await recipientAgent.initialize() // Initialize sender agent diff --git a/packages/core/src/modules/vc/__tests__/W3cCredentialService.test.ts b/packages/core/src/modules/vc/__tests__/W3cCredentialService.test.ts index 2a3961fa89..f708a56e96 100644 --- a/packages/core/src/modules/vc/__tests__/W3cCredentialService.test.ts +++ b/packages/core/src/modules/vc/__tests__/W3cCredentialService.test.ts @@ -1,9 +1,9 @@ import type { AgentContext } from '../../../agent' import type { Wallet } from '../../../wallet' -import { IndySdkWallet } from '../../../../../indy-sdk/src' -import { getAgentConfig, indySdk, getAgentContext, mockFunction } from '../../../../tests' -import { SigningProviderRegistry, JwsService } from '../../../crypto' +import { InMemoryWallet } from '../../../../../../tests/InMemoryWallet' +import { getAgentConfig, getAgentContext, mockFunction } from '../../../../tests' +import { JwsService } from '../../../crypto' import { JsonTransformer, asArray } from '../../../utils' import { W3cCredentialService } from '../W3cCredentialService' import { W3cCredentialsModuleConfig } from '../W3cCredentialsModuleConfig' @@ -17,8 +17,6 @@ import { W3cJwtCredentialService } from '../jwt-vc' import { W3cPresentation } from '../models' import { W3cCredentialRepository, W3cCredentialRecord } from '../repository' -const signingProviderRegistry = new SigningProviderRegistry([]) - jest.mock('../repository/W3cCredentialRepository') const W3cCredentialsRepositoryMock = W3cCredentialRepository as jest.Mock @@ -48,7 +46,7 @@ describe('W3cCredentialsService', () => { let w3cCredentialsRepository: W3cCredentialRepository beforeAll(async () => { - wallet = new IndySdkWallet(indySdk, agentConfig.logger, signingProviderRegistry) + wallet = new InMemoryWallet() await wallet.createAndOpen(agentConfig.walletConfig) agentContext = getAgentContext({ agentConfig, diff --git a/packages/core/src/modules/vc/__tests__/W3cCredentialsApi.test.ts b/packages/core/src/modules/vc/__tests__/W3cCredentialsApi.test.ts index 01a67407cf..c39f408452 100644 --- a/packages/core/src/modules/vc/__tests__/W3cCredentialsApi.test.ts +++ b/packages/core/src/modules/vc/__tests__/W3cCredentialsApi.test.ts @@ -1,5 +1,4 @@ -import { IndySdkModule } from '../../../../../indy-sdk/src' -import { getAgentOptions, indySdk } from '../../../../tests' +import { getInMemoryAgentOptions } from '../../../../tests' import { Agent } from '../../../agent/Agent' import { JsonTransformer } from '../../../utils' import { W3cCredentialService } from '../W3cCredentialService' @@ -9,16 +8,15 @@ import { Ed25519Signature2018Fixtures } from '../data-integrity/__tests__/fixtur import { W3cJsonLdVerifiableCredential } from '../data-integrity/models' import { W3cCredentialRepository } from '../repository' -const modules = { - indySdk: new IndySdkModule({ - indySdk, - }), - w3cCredentials: new W3cCredentialsModule({ - documentLoader: customDocumentLoader, - }), -} - -const agentOptions = getAgentOptions('W3cCredentialsApi', {}, modules) +const agentOptions = getInMemoryAgentOptions( + 'W3cCredentialsApi', + {}, + { + w3cCredentials: new W3cCredentialsModule({ + documentLoader: customDocumentLoader, + }), + } +) const agent = new Agent(agentOptions) diff --git a/packages/core/src/modules/vc/data-integrity/__tests__/W3cJsonLdCredentialService.test.ts b/packages/core/src/modules/vc/data-integrity/__tests__/W3cJsonLdCredentialService.test.ts index 0e1a416dd2..b6170844f7 100644 --- a/packages/core/src/modules/vc/data-integrity/__tests__/W3cJsonLdCredentialService.test.ts +++ b/packages/core/src/modules/vc/data-integrity/__tests__/W3cJsonLdCredentialService.test.ts @@ -1,11 +1,9 @@ import type { AgentContext } from '../../../../agent' import type { Wallet } from '../../../../wallet' -import { IndySdkWallet } from '../../../../../../indy-sdk/src' -import { indySdk } from '../../../../../../indy-sdk/tests/setupIndySdkModule' +import { InMemoryWallet } from '../../../../../../../tests/InMemoryWallet' import { getAgentConfig, getAgentContext } from '../../../../../tests/helpers' import { KeyType } from '../../../../crypto' -import { SigningProviderRegistry } from '../../../../crypto/signing-provider' import { asArray, TypedArrayEncoder } from '../../../../utils' import { JsonTransformer } from '../../../../utils/JsonTransformer' import { WalletError } from '../../../../wallet/error' @@ -41,7 +39,6 @@ const signatureSuiteRegistry = new SignatureSuiteRegistry([ }, ]) -const signingProviderRegistry = new SigningProviderRegistry([]) const agentConfig = getAgentConfig('W3cJsonLdCredentialServiceTest') describe('W3cJsonLdCredentialsService', () => { @@ -51,7 +48,7 @@ describe('W3cJsonLdCredentialsService', () => { const privateKey = TypedArrayEncoder.fromString('testseed000000000000000000000001') beforeAll(async () => { - wallet = new IndySdkWallet(indySdk, agentConfig.logger, signingProviderRegistry) + wallet = new InMemoryWallet() await wallet.createAndOpen(agentConfig.walletConfig) agentContext = getAgentContext({ agentConfig, diff --git a/packages/core/src/modules/vc/data-integrity/deriveProof.ts b/packages/core/src/modules/vc/data-integrity/deriveProof.ts index fe89595115..47d0dc550b 100644 --- a/packages/core/src/modules/vc/data-integrity/deriveProof.ts +++ b/packages/core/src/modules/vc/data-integrity/deriveProof.ts @@ -38,6 +38,7 @@ export interface W3cJsonLdDeriveProofOptions { export const deriveProof = async ( proofDocument: JsonObject, revealDocument: JsonObject, + // eslint-disable-next-line @typescript-eslint/no-explicit-any { suite, skipProofCompaction, documentLoader, nonce }: any ): Promise => { if (!suite) { diff --git a/packages/core/src/modules/vc/data-integrity/proof-purposes/ProofPurpose.ts b/packages/core/src/modules/vc/data-integrity/proof-purposes/ProofPurpose.ts index 2695f3276c..af04ec9f41 100644 --- a/packages/core/src/modules/vc/data-integrity/proof-purposes/ProofPurpose.ts +++ b/packages/core/src/modules/vc/data-integrity/proof-purposes/ProofPurpose.ts @@ -1 +1,2 @@ +// eslint-disable-next-line @typescript-eslint/no-explicit-any export type ProofPurpose = any diff --git a/packages/core/src/modules/vc/jwt-vc/W3cJwtCredentialService.ts b/packages/core/src/modules/vc/jwt-vc/W3cJwtCredentialService.ts index 87bf4b476c..0abeb864cf 100644 --- a/packages/core/src/modules/vc/jwt-vc/W3cJwtCredentialService.ts +++ b/packages/core/src/modules/vc/jwt-vc/W3cJwtCredentialService.ts @@ -40,7 +40,7 @@ export class W3cJwtCredentialService { // Warn about experimental module agentContext.config.logger.warn( - "The 'W3cJwtCredentialService' is experimental and could have unexpected breaking changes. When using this service, make sure to use strict versions for all @aries-framework packages." + "The 'W3cJwtCredentialService' is experimental and could have unexpected breaking changes. When using this service, make sure to use strict versions for all @credo-ts packages." ) this.hasWarned = true diff --git a/packages/core/src/modules/vc/jwt-vc/__tests__/W3cJwtCredentialService.test.ts b/packages/core/src/modules/vc/jwt-vc/__tests__/W3cJwtCredentialService.test.ts index 42fb659cb0..51aa0706b0 100644 --- a/packages/core/src/modules/vc/jwt-vc/__tests__/W3cJwtCredentialService.test.ts +++ b/packages/core/src/modules/vc/jwt-vc/__tests__/W3cJwtCredentialService.test.ts @@ -1,7 +1,7 @@ -import { RegisteredAskarTestWallet } from '../../../../../../askar/tests/helpers' -import { agentDependencies, getAgentConfig, getAgentContext, testLogger } from '../../../../../tests' +import { InMemoryWallet } from '../../../../../../../tests/InMemoryWallet' +import { getAgentConfig, getAgentContext, testLogger } from '../../../../../tests' import { InjectionSymbols } from '../../../../constants' -import { JwsService, KeyType, SigningProviderRegistry } from '../../../../crypto' +import { JwsService, KeyType } from '../../../../crypto' import { JwaSignatureAlgorithm } from '../../../../crypto/jose/jwa' import { getJwkFromKey } from '../../../../crypto/jose/jwk' import { AriesFrameworkError, ClassValidationError } from '../../../../error' @@ -23,11 +23,7 @@ import { didIonJwtVcPresentationProfileJwtVc } from './fixtures/jwt-vc-presentat import { didKeyTransmuteJwtVc, didKeyTransmuteJwtVp } from './fixtures/transmute-verifiable-data' const config = getAgentConfig('W3cJwtCredentialService') -const wallet = new RegisteredAskarTestWallet( - config.logger, - new agentDependencies.FileSystem(), - new SigningProviderRegistry([]) -) +const wallet = new InMemoryWallet() const agentContext = getAgentContext({ wallet, registerInstances: [ diff --git a/packages/core/src/storage/migration/__tests__/0.1.test.ts b/packages/core/src/storage/migration/__tests__/0.1.test.ts index ff2033f3ba..deaf622249 100644 --- a/packages/core/src/storage/migration/__tests__/0.1.test.ts +++ b/packages/core/src/storage/migration/__tests__/0.1.test.ts @@ -4,9 +4,7 @@ import { readFileSync } from 'fs' import path from 'path' import { InMemoryStorageService } from '../../../../../../tests/InMemoryStorageService' -import { IndySdkWallet } from '../../../../../indy-sdk/src' -import { IndySdkSymbol } from '../../../../../indy-sdk/src/types' -import { indySdk } from '../../../../../indy-sdk/tests/setupIndySdkModule' +import { RegisteredAskarTestWallet } from '../../../../../askar/tests/helpers' import { Agent } from '../../../../src' import { agentDependencies as dependencies } from '../../../../tests/helpers' import { InjectionSymbols } from '../../../constants' @@ -40,9 +38,8 @@ describe('UpdateAssistant | v0.1 - v0.2', () => { const dependencyManager = new DependencyManager() const storageService = new InMemoryStorageService() dependencyManager.registerInstance(InjectionSymbols.StorageService, storageService) - // If we register the IndySdkModule it will register the storage service, but we use in memory storage here - dependencyManager.registerContextScoped(InjectionSymbols.Wallet, IndySdkWallet) - dependencyManager.registerInstance(IndySdkSymbol, indySdk) + // If we register the AskarModule it will register the storage service, but we use in memory storage here + dependencyManager.registerContextScoped(InjectionSymbols.Wallet, RegisteredAskarTestWallet) const agent = new Agent( { @@ -62,7 +59,12 @@ describe('UpdateAssistant | v0.1 - v0.2', () => { // Set storage after initialization. This mimics as if this wallet // is opened as an existing wallet instead of a new wallet - storageService.records = JSON.parse(aliceMediationRecordsString) + storageService.contextCorrelationIdToRecords = { + default: { + records: JSON.parse(aliceMediationRecordsString), + creationDate: new Date(), + }, + } expect(await updateAssistant.getNeededUpdates('0.2')).toEqual([ { @@ -77,9 +79,9 @@ describe('UpdateAssistant | v0.1 - v0.2', () => { expect(await updateAssistant.isUpToDate('0.2')).toBe(true) expect(await updateAssistant.getNeededUpdates('0.2')).toEqual([]) - // MEDIATOR_ROUTING_RECORD recipientKeys will be different every time, and is not what we're testing here - delete storageService.records.MEDIATOR_ROUTING_RECORD - expect(storageService.records).toMatchSnapshot(mediationRoleUpdateStrategy) + expect(storageService.contextCorrelationIdToRecords[agent.context.contextCorrelationId].records).toMatchSnapshot( + mediationRoleUpdateStrategy + ) await agent.shutdown() await agent.wallet.delete() @@ -99,9 +101,8 @@ describe('UpdateAssistant | v0.1 - v0.2', () => { const dependencyManager = new DependencyManager() const storageService = new InMemoryStorageService() dependencyManager.registerInstance(InjectionSymbols.StorageService, storageService) - // If we register the IndySdkModule it will register the storage service, but we use in memory storage here - dependencyManager.registerContextScoped(InjectionSymbols.Wallet, IndySdkWallet) - dependencyManager.registerInstance(IndySdkSymbol, indySdk) + // If we register the AskarModule it will register the storage service, but we use in memory storage here + dependencyManager.registerContextScoped(InjectionSymbols.Wallet, RegisteredAskarTestWallet) const agent = new Agent( { @@ -121,7 +122,12 @@ describe('UpdateAssistant | v0.1 - v0.2', () => { // Set storage after initialization. This mimics as if this wallet // is opened as an existing wallet instead of a new wallet - storageService.records = JSON.parse(aliceCredentialRecordsString) + storageService.contextCorrelationIdToRecords = { + default: { + records: JSON.parse(aliceCredentialRecordsString), + creationDate: new Date(), + }, + } expect(await updateAssistant.isUpToDate('0.2')).toBe(false) expect(await updateAssistant.getNeededUpdates('0.2')).toEqual([ @@ -137,9 +143,7 @@ describe('UpdateAssistant | v0.1 - v0.2', () => { expect(await updateAssistant.isUpToDate('0.2')).toBe(true) expect(await updateAssistant.getNeededUpdates('0.2')).toEqual([]) - // MEDIATOR_ROUTING_RECORD recipientKeys will be different every time, and is not what we're testing here - delete storageService.records.MEDIATOR_ROUTING_RECORD - expect(storageService.records).toMatchSnapshot() + expect(storageService.contextCorrelationIdToRecords[agent.context.contextCorrelationId].records).toMatchSnapshot() await agent.shutdown() await agent.wallet.delete() @@ -160,9 +164,8 @@ describe('UpdateAssistant | v0.1 - v0.2', () => { const dependencyManager = new DependencyManager() const storageService = new InMemoryStorageService() dependencyManager.registerInstance(InjectionSymbols.StorageService, storageService) - // If we register the IndySdkModule it will register the storage service, but we use in memory storage here - dependencyManager.registerContextScoped(InjectionSymbols.Wallet, IndySdkWallet) - dependencyManager.registerInstance(IndySdkSymbol, indySdk) + // If we register the AskarModule it will register the storage service, but we use in memory storage here + dependencyManager.registerContextScoped(InjectionSymbols.Wallet, RegisteredAskarTestWallet) const agent = new Agent( { @@ -182,7 +185,12 @@ describe('UpdateAssistant | v0.1 - v0.2', () => { // Set storage after initialization. This mimics as if this wallet // is opened as an existing wallet instead of a new wallet - storageService.records = JSON.parse(aliceCredentialRecordsString) + storageService.contextCorrelationIdToRecords = { + default: { + records: JSON.parse(aliceCredentialRecordsString), + creationDate: new Date(), + }, + } expect(await updateAssistant.isUpToDate('0.2')).toBe(false) expect(await updateAssistant.getNeededUpdates('0.2')).toEqual([ @@ -198,9 +206,7 @@ describe('UpdateAssistant | v0.1 - v0.2', () => { expect(await updateAssistant.isUpToDate('0.2')).toBe(true) expect(await updateAssistant.getNeededUpdates('0.2')).toEqual([]) - // MEDIATOR_ROUTING_RECORD recipientKeys will be different every time, and is not what we're testing here - delete storageService.records.MEDIATOR_ROUTING_RECORD - expect(storageService.records).toMatchSnapshot() + expect(storageService.contextCorrelationIdToRecords[agent.context.contextCorrelationId].records).toMatchSnapshot() await agent.shutdown() await agent.wallet.delete() @@ -221,9 +227,8 @@ describe('UpdateAssistant | v0.1 - v0.2', () => { const dependencyManager = new DependencyManager() const storageService = new InMemoryStorageService() dependencyManager.registerInstance(InjectionSymbols.StorageService, storageService) - // If we register the IndySdkModule it will register the storage service, but we use in memory storage here - dependencyManager.registerContextScoped(InjectionSymbols.Wallet, IndySdkWallet) - dependencyManager.registerInstance(IndySdkSymbol, indySdk) + // If we register the AskarModule it will register the storage service, but we use in memory storage here + dependencyManager.registerContextScoped(InjectionSymbols.Wallet, RegisteredAskarTestWallet) const agent = new Agent( { @@ -247,7 +252,12 @@ describe('UpdateAssistant | v0.1 - v0.2', () => { // Set storage after initialization. This mimics as if this wallet // is opened as an existing wallet instead of a new wallet - storageService.records = JSON.parse(aliceConnectionRecordsString) + storageService.contextCorrelationIdToRecords = { + default: { + records: JSON.parse(aliceConnectionRecordsString), + creationDate: new Date(), + }, + } expect(await updateAssistant.isUpToDate('0.2')).toBe(false) expect(await updateAssistant.getNeededUpdates('0.2')).toEqual([ @@ -263,9 +273,7 @@ describe('UpdateAssistant | v0.1 - v0.2', () => { expect(await updateAssistant.isUpToDate('0.2')).toBe(true) expect(await updateAssistant.getNeededUpdates('0.2')).toEqual([]) - // MEDIATOR_ROUTING_RECORD recipientKeys will be different every time, and is not what we're testing here - delete storageService.records.MEDIATOR_ROUTING_RECORD - expect(storageService.records).toMatchSnapshot() + expect(storageService.contextCorrelationIdToRecords[agent.context.contextCorrelationId].records).toMatchSnapshot() await agent.shutdown() await agent.wallet.delete() diff --git a/packages/core/src/storage/migration/__tests__/0.2.test.ts b/packages/core/src/storage/migration/__tests__/0.2.test.ts index a66ef7c832..4ad72fca11 100644 --- a/packages/core/src/storage/migration/__tests__/0.2.test.ts +++ b/packages/core/src/storage/migration/__tests__/0.2.test.ts @@ -2,17 +2,15 @@ import { readFileSync } from 'fs' import path from 'path' import { InMemoryStorageService } from '../../../../../../tests/InMemoryStorageService' -import { IndySdkWallet } from '../../../../../indy-sdk/src' -import { IndySdkSymbol } from '../../../../../indy-sdk/src/types' -import { Agent } from '../../../../src' -import { indySdk } from '../../../../tests' +import { RegisteredAskarTestWallet } from '../../../../../askar/tests/helpers' +import { Agent, MediatorRoutingRecord } from '../../../../src' import { agentDependencies } from '../../../../tests/helpers' import { InjectionSymbols } from '../../../constants' import { DependencyManager } from '../../../plugins' import * as uuid from '../../../utils/uuid' import { UpdateAssistant } from '../UpdateAssistant' -const backupDate = new Date('2022-01-21T22:50:20.522Z') +const backupDate = new Date('2023-01-21T22:50:20.522Z') jest.useFakeTimers().setSystemTime(backupDate) const walletConfig = { @@ -34,9 +32,8 @@ describe('UpdateAssistant | v0.2 - v0.3.1', () => { const dependencyManager = new DependencyManager() const storageService = new InMemoryStorageService() dependencyManager.registerInstance(InjectionSymbols.StorageService, storageService) - // If we register the IndySdkModule it will register the storage service, but we use in memory storage here - dependencyManager.registerContextScoped(InjectionSymbols.Wallet, IndySdkWallet) - dependencyManager.registerInstance(IndySdkSymbol, indySdk) + // If we register the AskarModule it will register the storage service, but we use in memory storage here + dependencyManager.registerContextScoped(InjectionSymbols.Wallet, RegisteredAskarTestWallet) const agent = new Agent( { @@ -59,7 +56,12 @@ describe('UpdateAssistant | v0.2 - v0.3.1', () => { // Set storage after initialization. This mimics as if this wallet // is opened as an existing wallet instead of a new wallet - storageService.records = JSON.parse(aliceCredentialRecordsString) + storageService.contextCorrelationIdToRecords = { + default: { + records: JSON.parse(aliceCredentialRecordsString), + creationDate: new Date(), + }, + } expect(await updateAssistant.isUpToDate()).toBe(false) expect(await updateAssistant.getNeededUpdates('0.3.1')).toEqual([ @@ -79,10 +81,7 @@ describe('UpdateAssistant | v0.2 - v0.3.1', () => { expect(await updateAssistant.isUpToDate()).toBe(true) expect(await updateAssistant.getNeededUpdates()).toEqual([]) - - // MEDIATOR_ROUTING_RECORD recipientKeys will be different every time, and is not what we're testing here - delete storageService.records.MEDIATOR_ROUTING_RECORD - expect(storageService.records).toMatchSnapshot() + expect(storageService.contextCorrelationIdToRecords[agent.context.contextCorrelationId].records).toMatchSnapshot() await agent.shutdown() await agent.wallet.delete() @@ -103,9 +102,8 @@ describe('UpdateAssistant | v0.2 - v0.3.1', () => { const dependencyManager = new DependencyManager() const storageService = new InMemoryStorageService() dependencyManager.registerInstance(InjectionSymbols.StorageService, storageService) - // If we register the IndySdkModule it will register the storage service, but we use in memory storage here - dependencyManager.registerContextScoped(InjectionSymbols.Wallet, IndySdkWallet) - dependencyManager.registerInstance(IndySdkSymbol, indySdk) + // If we register the AskarModule it will register the storage service, but we use in memory storage here + dependencyManager.registerContextScoped(InjectionSymbols.Wallet, RegisteredAskarTestWallet) const agent = new Agent( { @@ -127,13 +125,16 @@ describe('UpdateAssistant | v0.2 - v0.3.1', () => { // Set storage after initialization. This mimics as if this wallet // is opened as an existing wallet instead of a new wallet - storageService.records = JSON.parse(aliceCredentialRecordsString) + storageService.contextCorrelationIdToRecords = { + default: { + records: JSON.parse(aliceCredentialRecordsString), + creationDate: new Date(), + }, + } await agent.initialize() - - // MEDIATOR_ROUTING_RECORD recipientKeys will be different every time, and is not what we're testing here - delete storageService.records.MEDIATOR_ROUTING_RECORD - expect(storageService.records).toMatchSnapshot() + await storageService.deleteById(agent.context, MediatorRoutingRecord, 'MEDIATOR_ROUTING_RECORD') + expect(storageService.contextCorrelationIdToRecords[agent.context.contextCorrelationId].records).toMatchSnapshot() await agent.shutdown() await agent.wallet.delete() @@ -150,9 +151,8 @@ describe('UpdateAssistant | v0.2 - v0.3.1', () => { const dependencyManager = new DependencyManager() const storageService = new InMemoryStorageService() - // If we register the IndySdkModule it will register the storage service, but we use in memory storage here - dependencyManager.registerContextScoped(InjectionSymbols.Wallet, IndySdkWallet) - dependencyManager.registerInstance(IndySdkSymbol, indySdk) + // If we register the AskarModule it will register the storage service, but we use in memory storage here + dependencyManager.registerContextScoped(InjectionSymbols.Wallet, RegisteredAskarTestWallet) dependencyManager.registerInstance(InjectionSymbols.StorageService, storageService) const agent = new Agent( @@ -175,14 +175,17 @@ describe('UpdateAssistant | v0.2 - v0.3.1', () => { // Set storage after initialization. This mimics as if this wallet // is opened as an existing wallet instead of a new wallet - storageService.records = JSON.parse(aliceDidRecordsString) + storageService.contextCorrelationIdToRecords = { + default: { + records: JSON.parse(aliceDidRecordsString), + creationDate: new Date(), + }, + } await agent.initialize() - // MEDIATOR_ROUTING_RECORD recipientKeys will be different every time, and is not what we're testing here - delete storageService.records.MEDIATOR_ROUTING_RECORD - - expect(storageService.records).toMatchSnapshot() + await storageService.deleteById(agent.context, MediatorRoutingRecord, 'MEDIATOR_ROUTING_RECORD') + expect(storageService.contextCorrelationIdToRecords[agent.context.contextCorrelationId].records).toMatchSnapshot() await agent.shutdown() await agent.wallet.delete() diff --git a/packages/core/src/storage/migration/__tests__/0.3.test.ts b/packages/core/src/storage/migration/__tests__/0.3.test.ts index e8479803fc..7cef8aafd7 100644 --- a/packages/core/src/storage/migration/__tests__/0.3.test.ts +++ b/packages/core/src/storage/migration/__tests__/0.3.test.ts @@ -2,9 +2,7 @@ import { readFileSync } from 'fs' import path from 'path' import { InMemoryStorageService } from '../../../../../../tests/InMemoryStorageService' -import { IndySdkWallet } from '../../../../../indy-sdk/src' -import { IndySdkSymbol } from '../../../../../indy-sdk/src/types' -import { indySdk } from '../../../../tests' +import { RegisteredAskarTestWallet } from '../../../../../askar/tests/helpers' import { agentDependencies } from '../../../../tests/helpers' import { Agent } from '../../../agent/Agent' import { InjectionSymbols } from '../../../constants' @@ -34,9 +32,8 @@ describe('UpdateAssistant | v0.3.1 - v0.4', () => { const dependencyManager = new DependencyManager() const storageService = new InMemoryStorageService() dependencyManager.registerInstance(InjectionSymbols.StorageService, storageService) - // If we register the IndySdkModule it will register the storage service, but we use in memory storage here - dependencyManager.registerContextScoped(InjectionSymbols.Wallet, IndySdkWallet) - dependencyManager.registerInstance(IndySdkSymbol, indySdk) + // If we register the AskarModule it will register the storage service, but we use in memory storage here + dependencyManager.registerContextScoped(InjectionSymbols.Wallet, RegisteredAskarTestWallet) const agent = new Agent( { @@ -59,7 +56,12 @@ describe('UpdateAssistant | v0.3.1 - v0.4', () => { // Set storage after initialization. This mimics as if this wallet // is opened as an existing wallet instead of a new wallet - storageService.records = JSON.parse(aliceDidRecordsString) + storageService.contextCorrelationIdToRecords = { + default: { + records: JSON.parse(aliceDidRecordsString), + creationDate: new Date(), + }, + } expect(await updateAssistant.isUpToDate()).toBe(false) expect(await updateAssistant.getNeededUpdates('0.4')).toEqual([ @@ -75,9 +77,7 @@ describe('UpdateAssistant | v0.3.1 - v0.4', () => { expect(await updateAssistant.isUpToDate()).toBe(true) expect(await updateAssistant.getNeededUpdates()).toEqual([]) - // MEDIATOR_ROUTING_RECORD recipientKeys will be different every time, and is not what we're testing here - delete storageService.records.MEDIATOR_ROUTING_RECORD - expect(storageService.records).toMatchSnapshot() + expect(storageService.contextCorrelationIdToRecords[agent.context.contextCorrelationId].records).toMatchSnapshot() await agent.shutdown() await agent.wallet.delete() diff --git a/packages/core/src/storage/migration/__tests__/UpdateAssistant.test.ts b/packages/core/src/storage/migration/__tests__/UpdateAssistant.test.ts index 2f9e3e80a3..eac4d95755 100644 --- a/packages/core/src/storage/migration/__tests__/UpdateAssistant.test.ts +++ b/packages/core/src/storage/migration/__tests__/UpdateAssistant.test.ts @@ -1,17 +1,13 @@ +import type { InMemoryStorageService } from '../../../../../../tests/InMemoryStorageService' import type { BaseRecord } from '../../BaseRecord' -import { InMemoryStorageService } from '../../../../../../tests/InMemoryStorageService' -import { IndySdkWallet } from '../../../../../indy-sdk/src' -import { IndySdkSymbol } from '../../../../../indy-sdk/src/types' -import { indySdk } from '../../../../../indy-sdk/tests/setupIndySdkModule' -import { getAgentOptions } from '../../../../tests/helpers' +import { getInMemoryAgentOptions } from '../../../../tests/helpers' import { Agent } from '../../../agent/Agent' import { InjectionSymbols } from '../../../constants' -import { DependencyManager } from '../../../plugins' import { UpdateAssistant } from '../UpdateAssistant' import { CURRENT_FRAMEWORK_STORAGE_VERSION } from '../updates' -const agentOptions = getAgentOptions('UpdateAssistant', {}) +const agentOptions = getInMemoryAgentOptions('UpdateAssistant', {}) describe('UpdateAssistant', () => { let updateAssistant: UpdateAssistant @@ -19,14 +15,7 @@ describe('UpdateAssistant', () => { let storageService: InMemoryStorageService beforeEach(async () => { - const dependencyManager = new DependencyManager() - storageService = new InMemoryStorageService() - // If we register the IndySdkModule it will register the storage service, but we use in memory storage here - dependencyManager.registerContextScoped(InjectionSymbols.Wallet, IndySdkWallet) - dependencyManager.registerInstance(IndySdkSymbol, indySdk) - dependencyManager.registerInstance(InjectionSymbols.StorageService, storageService) - - agent = new Agent(agentOptions, dependencyManager) + agent = new Agent(agentOptions) updateAssistant = new UpdateAssistant(agent, { v0_1ToV0_2: { @@ -34,6 +23,8 @@ describe('UpdateAssistant', () => { }, }) + storageService = agent.dependencyManager.resolve(InjectionSymbols.StorageService) + await updateAssistant.initialize() }) @@ -44,10 +35,13 @@ describe('UpdateAssistant', () => { describe('upgrade()', () => { it('should not upgrade records when upgrading after a new wallet is created', async () => { - const beforeStorage = JSON.stringify(storageService.records) + const beforeStorage = JSON.stringify(storageService.contextCorrelationIdToRecords) await updateAssistant.update() - expect(JSON.parse(beforeStorage)).toEqual(storageService.records) + // We parse and stringify so the dates are equal (both string) + expect(JSON.parse(beforeStorage)).toEqual( + JSON.parse(JSON.stringify(storageService.contextCorrelationIdToRecords)) + ) }) }) diff --git a/packages/core/src/storage/migration/__tests__/__snapshots__/0.2.test.ts.snap b/packages/core/src/storage/migration/__tests__/__snapshots__/0.2.test.ts.snap index c4767da0c1..cf2fb076af 100644 --- a/packages/core/src/storage/migration/__tests__/__snapshots__/0.2.test.ts.snap +++ b/packages/core/src/storage/migration/__tests__/__snapshots__/0.2.test.ts.snap @@ -122,7 +122,7 @@ exports[`UpdateAssistant | v0.2 - v0.3.1 should correctly update proof records a "id": "STORAGE_VERSION_RECORD_ID", "metadata": {}, "storageVersion": "0.4", - "updatedAt": "2022-01-21T22:50:20.522Z", + "updatedAt": "2023-01-21T22:50:20.522Z", }, }, "ea840186-3c77-45f4-a2e6-349811ad8994": { @@ -303,7 +303,7 @@ exports[`UpdateAssistant | v0.2 - v0.3.1 should correctly update the did records "id": "1-4e4f-41d9-94c4-f49351b811f1", "metadata": {}, "role": "created", - "updatedAt": "2022-01-21T22:50:20.522Z", + "updatedAt": "2023-01-21T22:50:20.522Z", }, }, "2-4e4f-41d9-94c4-f49351b811f1": { @@ -366,7 +366,7 @@ exports[`UpdateAssistant | v0.2 - v0.3.1 should correctly update the did records "id": "2-4e4f-41d9-94c4-f49351b811f1", "metadata": {}, "role": "received", - "updatedAt": "2022-01-21T22:50:20.522Z", + "updatedAt": "2023-01-21T22:50:20.522Z", }, }, "3-4e4f-41d9-94c4-f49351b811f1": { @@ -429,7 +429,7 @@ exports[`UpdateAssistant | v0.2 - v0.3.1 should correctly update the did records "id": "3-4e4f-41d9-94c4-f49351b811f1", "metadata": {}, "role": "created", - "updatedAt": "2022-01-21T22:50:20.522Z", + "updatedAt": "2023-01-21T22:50:20.522Z", }, }, "4-4e4f-41d9-94c4-f49351b811f1": { @@ -494,7 +494,7 @@ exports[`UpdateAssistant | v0.2 - v0.3.1 should correctly update the did records "id": "4-4e4f-41d9-94c4-f49351b811f1", "metadata": {}, "role": "created", - "updatedAt": "2022-01-21T22:50:20.522Z", + "updatedAt": "2023-01-21T22:50:20.522Z", }, }, "5-4e4f-41d9-94c4-f49351b811f1": { @@ -557,7 +557,7 @@ exports[`UpdateAssistant | v0.2 - v0.3.1 should correctly update the did records "id": "5-4e4f-41d9-94c4-f49351b811f1", "metadata": {}, "role": "received", - "updatedAt": "2022-01-21T22:50:20.522Z", + "updatedAt": "2023-01-21T22:50:20.522Z", }, }, "6-4e4f-41d9-94c4-f49351b811f1": { @@ -620,7 +620,7 @@ exports[`UpdateAssistant | v0.2 - v0.3.1 should correctly update the did records "id": "6-4e4f-41d9-94c4-f49351b811f1", "metadata": {}, "role": "received", - "updatedAt": "2022-01-21T22:50:20.522Z", + "updatedAt": "2023-01-21T22:50:20.522Z", }, }, "7-4e4f-41d9-94c4-f49351b811f1": { @@ -683,7 +683,7 @@ exports[`UpdateAssistant | v0.2 - v0.3.1 should correctly update the did records "id": "7-4e4f-41d9-94c4-f49351b811f1", "metadata": {}, "role": "received", - "updatedAt": "2022-01-21T22:50:20.522Z", + "updatedAt": "2023-01-21T22:50:20.522Z", }, }, "8-4e4f-41d9-94c4-f49351b811f1": { @@ -746,7 +746,7 @@ exports[`UpdateAssistant | v0.2 - v0.3.1 should correctly update the did records "id": "8-4e4f-41d9-94c4-f49351b811f1", "metadata": {}, "role": "created", - "updatedAt": "2022-01-21T22:50:20.522Z", + "updatedAt": "2023-01-21T22:50:20.522Z", }, }, "STORAGE_VERSION_RECORD_ID": { @@ -758,7 +758,7 @@ exports[`UpdateAssistant | v0.2 - v0.3.1 should correctly update the did records "id": "STORAGE_VERSION_RECORD_ID", "metadata": {}, "storageVersion": "0.4", - "updatedAt": "2022-01-21T22:50:20.522Z", + "updatedAt": "2023-01-21T22:50:20.522Z", }, }, } @@ -886,7 +886,7 @@ exports[`UpdateAssistant | v0.2 - v0.3.1 should correctly update the proofs reco "id": "STORAGE_VERSION_RECORD_ID", "metadata": {}, "storageVersion": "0.4", - "updatedAt": "2022-01-21T22:50:20.522Z", + "updatedAt": "2023-01-21T22:50:20.522Z", }, }, "ea840186-3c77-45f4-a2e6-349811ad8994": { diff --git a/packages/core/src/storage/migration/__tests__/backup-askar.test.ts b/packages/core/src/storage/migration/__tests__/backup-askar.test.ts index 1b83777bdd..3db486adc1 100644 --- a/packages/core/src/storage/migration/__tests__/backup-askar.test.ts +++ b/packages/core/src/storage/migration/__tests__/backup-askar.test.ts @@ -4,9 +4,8 @@ import type { StorageUpdateError } from '../error/StorageUpdateError' import { readFileSync, unlinkSync } from 'fs' import path from 'path' -import { AskarModule } from '../../../../../askar/src' -import { askarModuleConfig } from '../../../../../askar/tests/helpers' -import { getAgentOptions } from '../../../../tests/helpers' +import { askarModule } from '../../../../../askar/tests/helpers' +import { getAgentOptions, getAskarWalletConfig } from '../../../../tests/helpers' import { Agent } from '../../../agent/Agent' import { InjectionSymbols } from '../../../constants' import { AriesFrameworkError } from '../../../error' @@ -17,9 +16,11 @@ import { UpdateAssistant } from '../UpdateAssistant' const agentOptions = getAgentOptions( 'UpdateAssistant | Backup | Aries Askar', - {}, { - askar: new AskarModule(askarModuleConfig), + walletConfig: getAskarWalletConfig('UpdateAssistant | Backup | Aries Askar', { inMemory: false }), + }, + { + askar: askarModule, } ) diff --git a/packages/core/src/storage/migration/__tests__/backup.test.ts b/packages/core/src/storage/migration/__tests__/backup.test.ts index e582263b57..6001ac2a99 100644 --- a/packages/core/src/storage/migration/__tests__/backup.test.ts +++ b/packages/core/src/storage/migration/__tests__/backup.test.ts @@ -4,8 +4,8 @@ import type { StorageUpdateError } from '../error/StorageUpdateError' import { readFileSync, unlinkSync } from 'fs' import path from 'path' -import { getIndySdkModules } from '../../../../../indy-sdk/tests/setupIndySdkModule' -import { getAgentOptions } from '../../../../tests/helpers' +import { askarModule } from '../../../../../askar/tests/helpers' +import { getAgentOptions, getAskarWalletConfig } from '../../../../tests/helpers' import { Agent } from '../../../agent/Agent' import { InjectionSymbols } from '../../../constants' import { AriesFrameworkError } from '../../../error' @@ -14,7 +14,17 @@ import { JsonTransformer } from '../../../utils' import { StorageUpdateService } from '../StorageUpdateService' import { UpdateAssistant } from '../UpdateAssistant' -const agentOptions = getAgentOptions('UpdateAssistant | Backup', {}, getIndySdkModules()) +const agentOptions = getAgentOptions( + 'UpdateAssistant | Backup', + { + walletConfig: getAskarWalletConfig('UpdateAssistant | Backup', { + inMemory: false, + }), + }, + { askar: askarModule } +) +// eslint-disable-next-line @typescript-eslint/no-non-null-assertion +agentOptions.config.walletConfig!.storage!.inMemory = false const aliceCredentialRecordsString = readFileSync( path.join(__dirname, '__fixtures__/alice-4-credentials-0.1.json'), diff --git a/packages/core/tests/agents.test.ts b/packages/core/tests/agents.test.ts index 9bded8ba18..6a8a7b23b4 100644 --- a/packages/core/tests/agents.test.ts +++ b/packages/core/tests/agents.test.ts @@ -1,27 +1,18 @@ /* eslint-disable @typescript-eslint/no-non-null-assertion */ import type { ConnectionRecord } from '../src/modules/connections' -import { getIndySdkModules } from '../../indy-sdk/tests/setupIndySdkModule' import { Agent } from '../src/agent/Agent' import { HandshakeProtocol } from '../src/modules/connections' -import { waitForBasicMessage, getAgentOptions } from './helpers' +import { waitForBasicMessage, getInMemoryAgentOptions } from './helpers' import { setupSubjectTransports } from './transport' -const aliceAgentOptions = getAgentOptions( - 'Agents Alice', - { - endpoints: ['rxjs:alice'], - }, - getIndySdkModules() -) -const bobAgentOptions = getAgentOptions( - 'Agents Bob', - { - endpoints: ['rxjs:bob'], - }, - getIndySdkModules() -) +const aliceAgentOptions = getInMemoryAgentOptions('Agents Alice', { + endpoints: ['rxjs:alice'], +}) +const bobAgentOptions = getInMemoryAgentOptions('Agents Bob', { + endpoints: ['rxjs:bob'], +}) describe('agents', () => { let aliceAgent: Agent diff --git a/packages/core/tests/connections.test.ts b/packages/core/tests/connections.test.ts index 0f64b31d2c..d158acc272 100644 --- a/packages/core/tests/connections.test.ts +++ b/packages/core/tests/connections.test.ts @@ -3,7 +3,6 @@ import type { AgentMessageProcessedEvent, KeylistUpdate } from '../src' import { filter, firstValueFrom, map, timeout } from 'rxjs' -import { getIndySdkModules } from '../../indy-sdk/tests/setupIndySdkModule' import { MediatorModule, Key, @@ -17,7 +16,7 @@ import { Agent } from '../src/agent/Agent' import { didKeyToVerkey } from '../src/modules/dids/helpers' import { OutOfBandState } from '../src/modules/oob/domain/OutOfBandState' -import { getAgentOptions, waitForTrustPingResponseReceivedEvent } from './helpers' +import { getInMemoryAgentOptions, waitForTrustPingResponseReceivedEvent } from './helpers' import { setupSubjectTransports } from './transport' describe('connections', () => { @@ -27,34 +26,21 @@ describe('connections', () => { let mediatorAgent: Agent beforeEach(async () => { - const faberAgentOptions = getAgentOptions( - 'Faber Agent Connections', - { - endpoints: ['rxjs:faber'], - }, - getIndySdkModules() - ) - const aliceAgentOptions = getAgentOptions( - 'Alice Agent Connections', - { - endpoints: ['rxjs:alice'], - }, - getIndySdkModules() - ) - const acmeAgentOptions = getAgentOptions( - 'Acme Agent Connections', - { - endpoints: ['rxjs:acme'], - }, - getIndySdkModules() - ) - const mediatorAgentOptions = getAgentOptions( + const faberAgentOptions = getInMemoryAgentOptions('Faber Agent Connections', { + endpoints: ['rxjs:faber'], + }) + const aliceAgentOptions = getInMemoryAgentOptions('Alice Agent Connections', { + endpoints: ['rxjs:alice'], + }) + const acmeAgentOptions = getInMemoryAgentOptions('Acme Agent Connections', { + endpoints: ['rxjs:acme'], + }) + const mediatorAgentOptions = getInMemoryAgentOptions( 'Mediator Agent Connections', { endpoints: ['rxjs:mediator'], }, { - ...getIndySdkModules(), mediator: new MediatorModule({ autoAcceptMediationRequests: true, }), diff --git a/packages/core/tests/generic-records.test.ts b/packages/core/tests/generic-records.test.ts index 3d37def0ed..bdf605d517 100644 --- a/packages/core/tests/generic-records.test.ts +++ b/packages/core/tests/generic-records.test.ts @@ -1,18 +1,13 @@ import type { GenericRecord } from '../src/modules/generic-records/repository/GenericRecord' -import { getIndySdkModules } from '../../indy-sdk/tests/setupIndySdkModule' import { Agent } from '../src/agent/Agent' import { RecordNotFoundError } from '../src/error' -import { getAgentOptions } from './helpers' +import { getInMemoryAgentOptions } from './helpers' -const aliceAgentOptions = getAgentOptions( - 'Generic Records Alice', - { - endpoints: ['rxjs:alice'], - }, - getIndySdkModules() -) +const aliceAgentOptions = getInMemoryAgentOptions('Generic Records Alice', { + endpoints: ['rxjs:alice'], +}) describe('genericRecords', () => { let aliceAgent: Agent diff --git a/packages/core/tests/helpers.ts b/packages/core/tests/helpers.ts index b1312050a8..6372d3caaa 100644 --- a/packages/core/tests/helpers.ts +++ b/packages/core/tests/helpers.ts @@ -1,4 +1,5 @@ /* eslint-disable @typescript-eslint/no-non-null-assertion */ +import type { AskarWalletSqliteStorageConfig } from '../../askar/src/wallet' import type { AgentDependencies, BaseEvent, @@ -14,9 +15,8 @@ import type { CredentialState, ConnectionStateChangedEvent, Buffer, - RevocationNotificationReceivedEvent, AgentMessageProcessedEvent, - AgentMessageReceivedEvent, + RevocationNotificationReceivedEvent, } from '../src' import type { AgentModulesInput, EmptyModuleMap } from '../src/agent/AgentModules' import type { TrustPingReceivedEvent, TrustPingResponseReceivedEvent } from '../src/modules/connections/TrustPingEvents' @@ -29,8 +29,10 @@ import path from 'path' import { lastValueFrom, firstValueFrom, ReplaySubject } from 'rxjs' import { catchError, filter, map, take, timeout } from 'rxjs/operators' -import { agentDependencies, IndySdkPostgresWalletScheme } from '../../node/src' +import { InMemoryWalletModule } from '../../../tests/InMemoryWalletModule' +import { agentDependencies } from '../../node/src' import { + AgentEventTypes, OutOfBandDidCommService, ConnectionsModule, ConnectionEventTypes, @@ -47,7 +49,6 @@ import { InjectionSymbols, ProofEventTypes, TrustPingEventTypes, - AgentEventTypes, } from '../src' import { Key, KeyType } from '../src/crypto' import { DidKey } from '../src/modules/dids/methods/key' @@ -56,6 +57,7 @@ import { OutOfBandState } from '../src/modules/oob/domain/OutOfBandState' import { OutOfBandInvitation } from '../src/modules/oob/messages' import { OutOfBandRecord } from '../src/modules/oob/repository' import { KeyDerivationMethod } from '../src/types' +import { sleep } from '../src/utils/sleep' import { uuid } from '../src/utils/uuid' import testLogger, { TestLogger } from './logger' @@ -71,6 +73,29 @@ export const taaVersion = (process.env.TEST_AGENT_TAA_VERSION ?? '1') as `${numb export const taaAcceptanceMechanism = process.env.TEST_AGENT_TAA_ACCEPTANCE_MECHANISM ?? 'accept' export { agentDependencies } +export function getAskarWalletConfig( + name: string, + { + inMemory = true, + random = uuid().slice(0, 4), + maxConnections, + }: { inMemory?: boolean; random?: string; maxConnections?: number } = {} +) { + return { + id: `Wallet: ${name} - ${random}`, + key: 'DZ9hPqFWTPxemcGea72C1X1nusqk5wFNLq6QPjwXGqAa', // generated using indy.generateWalletKey + keyDerivationMethod: KeyDerivationMethod.Raw, + // Use in memory by default + storage: { + type: 'sqlite', + config: { + inMemory, + maxConnections, + }, + } satisfies AskarWalletSqliteStorageConfig, + } satisfies WalletConfig +} + export function getAgentOptions( name: string, extraConfig: Partial = {}, @@ -79,11 +104,7 @@ export function getAgentOptions( +export function getInMemoryAgentOptions( name: string, extraConfig: Partial = {}, inputModules?: AgentModules -) { +): { config: InitConfig; modules: AgentModules; dependencies: AgentDependencies } { const random = uuid().slice(0, 4) const config: InitConfig = { label: `Agent: ${name} - ${random}`, walletConfig: { - // NOTE: IndySDK Postgres database per wallet doesn't support special characters/spaces in the wallet name - id: `PostgresWallet${name}${random}`, - key: `Key${name}`, - storage: { - type: 'postgres_storage', - config: { - url: 'localhost:5432', - wallet_scheme: IndySdkPostgresWalletScheme.DatabasePerWallet, - }, - credentials: { - account: 'postgres', - password: 'postgres', - admin_account: 'postgres', - admin_password: 'postgres', - }, - }, + id: `Wallet: ${name} - ${random}`, + key: `Wallet: ${name}`, }, - autoUpdateStorageOnStartup: false, + // TODO: determine the log level based on an environment variable. This will make it + // possible to run e.g. failed github actions in debug mode for extra logs logger: TestLogger.fromLogger(testLogger, name), ...extraConfig, } @@ -138,13 +146,16 @@ export function getPostgresAgentOptions any>(fn: T): jest.Moc export function mockProperty(object: T, property: K, value: T[K]) { Object.defineProperty(object, property, { get: () => value }) } + +export async function retryUntilResult Promise>( + method: M, + { + intervalMs = 500, + delay = 1000, + maxAttempts = 5, + }: { + intervalMs?: number + delay?: number + maxAttempts?: number + } = {} +): Promise { + await sleep(delay) + + for (let i = 0; i < maxAttempts; i++) { + const result = await method() + if (result) return result + await sleep(intervalMs) + } + + throw new Error(`Unable to get result from method in ${maxAttempts} attempts`) +} diff --git a/packages/core/tests/index.ts b/packages/core/tests/index.ts index 2822fb23e1..b8ea2ca430 100644 --- a/packages/core/tests/index.ts +++ b/packages/core/tests/index.ts @@ -2,7 +2,6 @@ export * from './jsonld' export * from './transport' export * from './events' export * from './helpers' -export * from './indySdk' import testLogger from './logger' diff --git a/packages/core/tests/indySdk.ts b/packages/core/tests/indySdk.ts deleted file mode 100644 index b5e5a3075d..0000000000 --- a/packages/core/tests/indySdk.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { indySdk } from '../../indy-sdk/tests/setupIndySdkModule' - -export { indySdk } diff --git a/packages/core/tests/jsonld.ts b/packages/core/tests/jsonld.ts index 1cfb263ab0..9dd4760296 100644 --- a/packages/core/tests/jsonld.ts +++ b/packages/core/tests/jsonld.ts @@ -1,9 +1,9 @@ import type { EventReplaySubject } from './events' import type { AutoAcceptCredential, AutoAcceptProof, ConnectionRecord } from '../src' +import { InMemoryWalletModule } from '../../../tests/InMemoryWalletModule' +import { askarModule } from '../../askar/tests/helpers' import { BbsModule } from '../../bbs-signatures/src/BbsModule' -import { IndySdkModule } from '../../indy-sdk/src' -import { indySdk } from '../../indy-sdk/tests/setupIndySdkModule' import { PresentationExchangeProofFormatService, V2ProofProtocol, @@ -29,7 +29,8 @@ export type JsonLdTestsAgent = Agent> export const getJsonLdModules = ({ autoAcceptCredentials, autoAcceptProofs, -}: { autoAcceptCredentials?: AutoAcceptCredential; autoAcceptProofs?: AutoAcceptProof } = {}) => + useBbs = false, +}: { autoAcceptCredentials?: AutoAcceptCredential; autoAcceptProofs?: AutoAcceptProof; useBbs?: boolean } = {}) => ({ credentials: new CredentialsModule({ credentialProtocols: [new V2CredentialProtocol({ credentialFormats: [new JsonLdCredentialFormatService()] })], @@ -45,10 +46,15 @@ export const getJsonLdModules = ({ cache: new CacheModule({ cache: new InMemoryLruCache({ limit: 100 }), }), - indySdk: new IndySdkModule({ - indySdk, - }), - bbs: new BbsModule(), + // We don't support signing provider in in memory wallet yet, so if BBS is used we need to use Askar + ...(useBbs + ? { + askar: askarModule, + bbs: new BbsModule(), + } + : { + inMemory: new InMemoryWalletModule(), + }), } as const) interface SetupJsonLdTestsReturn { @@ -88,6 +94,7 @@ export async function setupJsonLdTests< autoAcceptCredentials, autoAcceptProofs, createConnections, + useBbs = false, }: { issuerName: string holderName: string @@ -95,10 +102,12 @@ export async function setupJsonLdTests< autoAcceptCredentials?: AutoAcceptCredential autoAcceptProofs?: AutoAcceptProof createConnections?: CreateConnections + useBbs?: boolean }): Promise> { const modules = getJsonLdModules({ autoAcceptCredentials, autoAcceptProofs, + useBbs, }) const issuerAgent = new Agent( diff --git a/packages/core/tests/migration.test.ts b/packages/core/tests/migration.test.ts index ac898caa73..bc39a9382a 100644 --- a/packages/core/tests/migration.test.ts +++ b/packages/core/tests/migration.test.ts @@ -1,12 +1,12 @@ import type { VersionString } from '../src/utils/version' -import { getIndySdkModules } from '../../indy-sdk/tests/setupIndySdkModule' +import { askarModule } from '../../askar/tests/helpers' import { Agent } from '../src/agent/Agent' import { UpdateAssistant } from '../src/storage/migration/UpdateAssistant' import { getAgentOptions } from './helpers' -const agentOptions = getAgentOptions('Migration', {}, getIndySdkModules()) +const agentOptions = getAgentOptions('Migration', {}, { askar: askarModule }) describe('migration', () => { test('manually initiating the update assistant to perform an update', async () => { diff --git a/packages/core/tests/multi-protocol-version.test.ts b/packages/core/tests/multi-protocol-version.test.ts index 4f7596d5ff..1f9fa3c915 100644 --- a/packages/core/tests/multi-protocol-version.test.ts +++ b/packages/core/tests/multi-protocol-version.test.ts @@ -2,29 +2,20 @@ import type { AgentMessageProcessedEvent } from '../src/agent/Events' import { filter, firstValueFrom, timeout } from 'rxjs' -import { getIndySdkModules } from '../../indy-sdk/tests/setupIndySdkModule' import { parseMessageType, MessageSender, AgentMessage, IsValidMessageType } from '../src' import { Agent } from '../src/agent/Agent' import { AgentEventTypes } from '../src/agent/Events' import { OutboundMessageContext } from '../src/agent/models' -import { getAgentOptions } from './helpers' +import { getInMemoryAgentOptions } from './helpers' import { setupSubjectTransports } from './transport' -const aliceAgentOptions = getAgentOptions( - 'Multi Protocol Versions - Alice', - { - endpoints: ['rxjs:alice'], - }, - getIndySdkModules() -) -const bobAgentOptions = getAgentOptions( - 'Multi Protocol Versions - Bob', - { - endpoints: ['rxjs:bob'], - }, - getIndySdkModules() -) +const aliceAgentOptions = getInMemoryAgentOptions('Multi Protocol Versions - Alice', { + endpoints: ['rxjs:alice'], +}) +const bobAgentOptions = getInMemoryAgentOptions('Multi Protocol Versions - Bob', { + endpoints: ['rxjs:bob'], +}) describe('multi version protocols', () => { let aliceAgent: Agent diff --git a/packages/core/tests/oob-mediation-provision.test.ts b/packages/core/tests/oob-mediation-provision.test.ts index 5e18f36197..3bf27ba9eb 100644 --- a/packages/core/tests/oob-mediation-provision.test.ts +++ b/packages/core/tests/oob-mediation-provision.test.ts @@ -1,7 +1,6 @@ /* eslint-disable @typescript-eslint/no-non-null-assertion */ import type { OutOfBandInvitation } from '../src/modules/oob/messages' -import { getIndySdkModules } from '../../indy-sdk/tests/setupIndySdkModule' import { Agent } from '../src/agent/Agent' import { DidExchangeState, HandshakeProtocol } from '../src/modules/connections' import { @@ -11,36 +10,29 @@ import { MediationRecipientModule, } from '../src/modules/routing' -import { getAgentOptions, waitForBasicMessage } from './helpers' +import { getInMemoryAgentOptions, waitForBasicMessage } from './helpers' import { setupSubjectTransports } from './transport' -const faberAgentOptions = getAgentOptions( - 'OOB mediation provision - Faber Agent', - { - endpoints: ['rxjs:faber'], - }, - getIndySdkModules() -) -const aliceAgentOptions = getAgentOptions( +const faberAgentOptions = getInMemoryAgentOptions('OOB mediation provision - Faber Agent', { + endpoints: ['rxjs:faber'], +}) +const aliceAgentOptions = getInMemoryAgentOptions( 'OOB mediation provision - Alice Recipient Agent', { endpoints: ['rxjs:alice'], }, { - ...getIndySdkModules(), mediationRecipient: new MediationRecipientModule({ - // FIXME: discover features returns that we support this protocol, but we don't support all roles - // we should return that we only support the mediator role so we don't have to explicitly declare this mediatorPickupStrategy: MediatorPickupStrategy.PickUpV1, }), } ) -const mediatorAgentOptions = getAgentOptions( +const mediatorAgentOptions = getInMemoryAgentOptions( 'OOB mediation provision - Mediator Agent', { endpoints: ['rxjs:mediator'], }, - { ...getIndySdkModules(), mediator: new MediatorModule({ autoAcceptMediationRequests: true }) } + { mediator: new MediatorModule({ autoAcceptMediationRequests: true }) } ) describe('out of band with mediation set up with provision method', () => { diff --git a/packages/core/tests/oob-mediation.test.ts b/packages/core/tests/oob-mediation.test.ts index 272c468d3b..3372ccc8cf 100644 --- a/packages/core/tests/oob-mediation.test.ts +++ b/packages/core/tests/oob-mediation.test.ts @@ -7,7 +7,6 @@ import { filter, firstValueFrom, map, Subject, timeout } from 'rxjs' import { SubjectInboundTransport } from '../../../tests/transport/SubjectInboundTransport' import { SubjectOutboundTransport } from '../../../tests/transport/SubjectOutboundTransport' -import { getIndySdkModules } from '../../indy-sdk/tests/setupIndySdkModule' import { Agent } from '../src/agent/Agent' import { AgentEventTypes } from '../src/agent/Events' import { DidExchangeState, HandshakeProtocol } from '../src/modules/connections' @@ -22,35 +21,28 @@ import { MediatorModule, } from '../src/modules/routing' -import { getAgentOptions, waitForBasicMessage } from './helpers' +import { getInMemoryAgentOptions, waitForBasicMessage } from './helpers' -const faberAgentOptions = getAgentOptions( - 'OOB mediation - Faber Agent', - { - endpoints: ['rxjs:faber'], - }, - getIndySdkModules() -) -const aliceAgentOptions = getAgentOptions( +const faberAgentOptions = getInMemoryAgentOptions('OOB mediation - Faber Agent', { + endpoints: ['rxjs:faber'], +}) +const aliceAgentOptions = getInMemoryAgentOptions( 'OOB mediation - Alice Recipient Agent', { endpoints: ['rxjs:alice'], }, { - ...getIndySdkModules(), mediationRecipient: new MediationRecipientModule({ - // FIXME: discover features returns that we support this protocol, but we don't support all roles - // we should return that we only support the mediator role so we don't have to explicitly declare this mediatorPickupStrategy: MediatorPickupStrategy.PickUpV1, }), } ) -const mediatorAgentOptions = getAgentOptions( +const mediatorAgentOptions = getInMemoryAgentOptions( 'OOB mediation - Mediator Agent', { endpoints: ['rxjs:mediator'], }, - { ...getIndySdkModules(), mediator: new MediatorModule({ autoAcceptMediationRequests: true }) } + { mediator: new MediatorModule({ autoAcceptMediationRequests: true }) } ) describe('out of band with mediation', () => { diff --git a/packages/core/tests/oob.test.ts b/packages/core/tests/oob.test.ts index c573c73215..278b7850f4 100644 --- a/packages/core/tests/oob.test.ts +++ b/packages/core/tests/oob.test.ts @@ -8,7 +8,7 @@ import { Subject } from 'rxjs' import { SubjectInboundTransport } from '../../../tests/transport/SubjectInboundTransport' import { SubjectOutboundTransport } from '../../../tests/transport/SubjectOutboundTransport' -import { getLegacyAnonCredsModules, prepareForAnonCredsIssuance } from '../../anoncreds/tests/legacyAnonCredsSetup' +import { getAnonCredsIndyModules, prepareForAnonCredsIssuance } from '../../anoncreds/tests/legacyAnonCredsSetup' import { Agent } from '../src/agent/Agent' import { Key } from '../src/crypto' import { DidExchangeState, HandshakeProtocol } from '../src/modules/connections' @@ -20,25 +20,26 @@ import { OutOfBandInvitation } from '../src/modules/oob/messages' import { JsonEncoder, JsonTransformer } from '../src/utils' import { TestMessage } from './TestMessage' -import { getAgentOptions, waitForCredentialRecord } from './helpers' +import { getInMemoryAgentOptions, waitForCredentialRecord } from './helpers' import { AgentEventTypes, AriesFrameworkError, AutoAcceptCredential, CredentialState } from '@credo-ts/core' -const faberAgentOptions = getAgentOptions( +// FIXME: oob.test doesn't need heavy AnonCreds / indy dependencies +const faberAgentOptions = getInMemoryAgentOptions( 'Faber Agent OOB', { endpoints: ['rxjs:faber'], }, - getLegacyAnonCredsModules({ + getAnonCredsIndyModules({ autoAcceptCredentials: AutoAcceptCredential.ContentApproved, }) ) -const aliceAgentOptions = getAgentOptions( +const aliceAgentOptions = getInMemoryAgentOptions( 'Alice Agent OOB', { endpoints: ['rxjs:alice'], }, - getLegacyAnonCredsModules({ + getAnonCredsIndyModules({ autoAcceptCredentials: AutoAcceptCredential.ContentApproved, }) ) @@ -63,8 +64,8 @@ describe('out of band', () => { autoAcceptConnection: false, } - let faberAgent: Agent> - let aliceAgent: Agent> + let faberAgent: Agent> + let aliceAgent: Agent> let credentialTemplate: CreateCredentialOfferOptions<[V1CredentialProtocol]> beforeAll(async () => { diff --git a/packages/core/tests/setup.ts b/packages/core/tests/setup.ts index b1f1d020b2..a2ba1429d2 100644 --- a/packages/core/tests/setup.ts +++ b/packages/core/tests/setup.ts @@ -2,9 +2,6 @@ import 'reflect-metadata' import type { ConnectionRecord } from '../src/modules/connections/repository/ConnectionRecord' -// eslint-disable-next-line @typescript-eslint/no-unused-vars -import { askarModuleConfig } from '../../askar/tests/helpers' - jest.setTimeout(120000) expect.extend({ toBeConnectedWith }) diff --git a/packages/core/tests/wallet.test.ts b/packages/core/tests/wallet.test.ts deleted file mode 100644 index 78e089482a..0000000000 --- a/packages/core/tests/wallet.test.ts +++ /dev/null @@ -1,186 +0,0 @@ -import { tmpdir } from 'os' -import path from 'path' - -import { getIndySdkModules } from '../../indy-sdk/tests/setupIndySdkModule' -import { Agent } from '../src/agent/Agent' -import { BasicMessageRepository, BasicMessageRecord, BasicMessageRole } from '../src/modules/basic-messages' -import { KeyDerivationMethod } from '../src/types' -import { uuid } from '../src/utils/uuid' -import { WalletInvalidKeyError } from '../src/wallet/error' -import { WalletDuplicateError } from '../src/wallet/error/WalletDuplicateError' -import { WalletNotFoundError } from '../src/wallet/error/WalletNotFoundError' - -import { getAgentOptions } from './helpers' - -const aliceAgentOptions = getAgentOptions('wallet-tests-Alice', {}, getIndySdkModules()) -const bobAgentOptions = getAgentOptions('wallet-tests-Bob', {}, getIndySdkModules()) - -describe('wallet', () => { - let aliceAgent: Agent - let bobAgent: Agent - - beforeEach(async () => { - aliceAgent = new Agent(aliceAgentOptions) - bobAgent = new Agent(bobAgentOptions) - }) - - afterEach(async () => { - await aliceAgent.shutdown() - await bobAgent.shutdown() - - if (aliceAgent.wallet.isProvisioned) { - await aliceAgent.wallet.delete() - } - - if (bobAgent.wallet.isProvisioned) { - await bobAgent.wallet.delete() - } - }) - - test('open, create and open wallet with different wallet key that it is in agent config', async () => { - const walletConfig = { - id: 'mywallet', - key: 'mysecretwalletkey', - } - - try { - await aliceAgent.wallet.open(walletConfig) - } catch (error) { - if (error instanceof WalletNotFoundError) { - await aliceAgent.wallet.create(walletConfig) - await aliceAgent.wallet.open(walletConfig) - } - } - - await aliceAgent.initialize() - - expect(aliceAgent.isInitialized).toBe(true) - }) - - test('when creating already existing wallet throw WalletDuplicateError', async () => { - const walletConfig = { - id: 'mywallet', - key: 'mysecretwalletkey', - } - - await aliceAgent.wallet.create(walletConfig) - - await expect(aliceAgent.wallet.create(walletConfig)).rejects.toThrowError(WalletDuplicateError) - }) - - test('when opening non-existing wallet throw WalletNotFoundError', async () => { - const walletConfig = { - id: 'mywallet', - key: 'mysecretwalletkey', - } - - await expect(aliceAgent.wallet.open(walletConfig)).rejects.toThrowError(WalletNotFoundError) - }) - - test('when opening wallet with invalid key throw WalletInvalidKeyError', async () => { - const walletConfig = { - id: 'mywallet', - key: 'mysecretwalletkey', - } - - await aliceAgent.wallet.create(walletConfig) - await expect(aliceAgent.wallet.open({ ...walletConfig, key: 'abcd' })).rejects.toThrowError(WalletInvalidKeyError) - }) - - test('when create wallet and shutdown, wallet is closed', async () => { - const walletConfig = { - id: 'mywallet', - key: 'mysecretwalletkey', - } - - await aliceAgent.wallet.create(walletConfig) - - await aliceAgent.shutdown() - - await expect(aliceAgent.wallet.open(walletConfig)).resolves.toBeUndefined() - }) - - test('create wallet with custom key derivation method', async () => { - const walletConfig = { - id: 'mywallet', - key: 'mysecretwalletkey', - keyDerivationMethod: KeyDerivationMethod.Argon2IInt, - } - - await aliceAgent.wallet.createAndOpen(walletConfig) - - expect(aliceAgent.wallet.isInitialized).toBe(true) - }) - - test('when exporting and importing a wallet, content is copied', async () => { - await bobAgent.initialize() - const bobBasicMessageRepository = bobAgent.dependencyManager.resolve(BasicMessageRepository) - - const basicMessageRecord = new BasicMessageRecord({ - id: 'some-id', - connectionId: 'connId', - content: 'hello', - role: BasicMessageRole.Receiver, - sentTime: 'sentIt', - }) - - // Save in wallet - await bobBasicMessageRepository.save(bobAgent.context, basicMessageRecord) - - if (!bobAgent.config.walletConfig) { - throw new Error('No wallet config on bobAgent') - } - - const backupKey = 'someBackupKey' - const backupWalletName = `backup-${uuid()}` - const backupPath = path.join(tmpdir(), backupWalletName) - - // Create backup and delete wallet - await bobAgent.wallet.export({ path: backupPath, key: backupKey }) - await bobAgent.wallet.delete() - - // Initialize the wallet again and assert record does not exist - // This should create a new wallet - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - await bobAgent.wallet.initialize(bobAgentOptions.config.walletConfig!) - expect(await bobBasicMessageRepository.findById(bobAgent.context, basicMessageRecord.id)).toBeNull() - await bobAgent.wallet.delete() - - // Import backup with different wallet id and initialize - await bobAgent.wallet.import({ id: backupWalletName, key: backupWalletName }, { path: backupPath, key: backupKey }) - await bobAgent.wallet.initialize({ id: backupWalletName, key: backupWalletName }) - - // Expect same basic message record to exist in new wallet - expect(await bobBasicMessageRepository.getById(bobAgent.context, basicMessageRecord.id)).toMatchObject({ - id: basicMessageRecord.id, - connectionId: basicMessageRecord.connectionId, - content: basicMessageRecord.content, - createdAt: basicMessageRecord.createdAt, - updatedAt: basicMessageRecord.updatedAt, - type: basicMessageRecord.type, - }) - }) - - test('changing wallet key', async () => { - const walletConfig = { - id: 'mywallet', - key: 'mysecretwalletkey', - } - - await aliceAgent.wallet.createAndOpen(walletConfig) - await aliceAgent.initialize() - - //Close agent - const walletConfigRekey = { - id: 'mywallet', - key: 'mysecretwalletkey', - rekey: '123', - } - - await aliceAgent.shutdown() - await aliceAgent.wallet.rotateKey(walletConfigRekey) - await aliceAgent.initialize() - - expect(aliceAgent.isInitialized).toBe(true) - }) -}) diff --git a/packages/indy-sdk-to-askar-migration/package.json b/packages/indy-sdk-to-askar-migration/package.json index c39397df01..53bfc2f452 100644 --- a/packages/indy-sdk-to-askar-migration/package.json +++ b/packages/indy-sdk-to-askar-migration/package.json @@ -30,10 +30,8 @@ "@credo-ts/node": "0.4.2" }, "devDependencies": { - "@credo-ts/indy-sdk": "0.4.2", "@hyperledger/aries-askar-nodejs": "^0.2.0-dev.5", "@hyperledger/aries-askar-shared": "^0.2.0-dev.5", - "indy-sdk": "^1.16.0-dev-1655", "rimraf": "^4.4.0", "typescript": "~4.9.5" }, diff --git a/packages/indy-sdk-to-askar-migration/src/IndySdkToAskarMigrationUpdater.ts b/packages/indy-sdk-to-askar-migration/src/IndySdkToAskarMigrationUpdater.ts index 9e1332533c..3d9f51aced 100644 --- a/packages/indy-sdk-to-askar-migration/src/IndySdkToAskarMigrationUpdater.ts +++ b/packages/indy-sdk-to-askar-migration/src/IndySdkToAskarMigrationUpdater.ts @@ -119,7 +119,7 @@ export class IndySdkToAskarMigrationUpdater { /** * Location of the new wallet */ - private get newWalletPath() { + public get newWalletPath() { return `${this.fs.dataPath}/wallet/${this.walletConfig.id}/sqlite.db` } diff --git a/packages/indy-sdk-to-askar-migration/tests/indy-sdk-040-wallet.db b/packages/indy-sdk-to-askar-migration/tests/indy-sdk-040-wallet.db new file mode 100644 index 0000000000000000000000000000000000000000..1fc1e28b4080b86ad51c7bed7e72af3cf8c2c817 GIT binary patch literal 57344 zcmeI4X;f3!7RQqqWezPxQWY@{P|{u{_a=lytcnmB1q@P^Dv=>b1VLsHQ34ckU@3^G zloq9Gg(^?<30jA$l@^>=eRhecsMJ|Ro>kvdD{r45u_)H{zW9OeySU`$oPGB2`|ljR zH%kL1`)Cr?f{57oxgm)HG3z}Rhr=2#5U^M*4xBtVyABh$;C8)%SN5N--*m}gjq+Py z#`9#E8CI~&lX*LMlTAf?wh0;b(oAXDlihj6dp(b2_OL^fCP{L5_p|Jl9>U2 zoRFH@Z}J&&l>{9gv@;< zp6OfSkrh3JBg4Y1(MAS*p^%;9kQfpg{fgu6Wf{K+GsR_skK$Ea#)21zE|{<16oGG` zj}N6E?yULs@fVmupeYJ>g;Makg}>5sl8bV>z*{lho;arjUDCYtKG9F9@O1ap*>uh7 zLzBdmiirxP!q-(1pj(|_uL&1+Gk^wgQ}`&LRa{*HTwUB0ug(VgyOBov^Q_R>xF6q7 z$Y$x3N{EYw(5jH6#8}!-UG>DAWH zyzFO#p88pDr+V4X`Z2?|1nu6>`epVn`ng|E{j9fA5lwYy^g{-3iKlC^u1~Cfm99CU zpSiE~v)-h8n7*&~v)p3~FYkPj(mh`dC-kvO{1Vjv>)`erh=kwWFA-XL~H?RBE zr<-0Km!vA8AA>Mn~dj3!Cqtt0VIQjGb)wSygwFYbh{@}rEZD$SS6A%uUU9X&O zm2`~?UUubQR`aI4w#Q7&Kr*(eoCQC4AOR$R1dsp{Kmter2_OL^fCPFbu-J{wWvwtx z9|pHQ3ByKzPCGFaLo*cZD5WIuB9l|JlbB*0B@``kgln3jr7#RHPI8K&#Bd=NQ8WXm z3?}4YBbHENCzzK}QVB&YC9qfw&O}m*5s4`oyp<4p83pd7GK!`hAt+5T5D0=WUP9<@1&LsuApl_l{6IveQxhTv$%6r%oE#~FK@KNPG6p}8JWYa90D`1M zRzcBF3Hc$0a0AD98*b;k!f>Z`+ zf+vVbz|#zrL^Ob8U_=Cyy3UYOAUqKtnv0PT0|+jLVnA~mq=#10$mTAs_Evhtw!+-tL@c_+t6$DOBqEDXy(IXg0AgsLEJfK}WO&8>BtT3zp$7j0Q( z|KTRJ%%uAKf+dFDH)kr<4OJJfY5$nxa?6v`V4YNESC(?Qb*|PWcU)vkm6gYw^7OLI z-`6=gUvF+wf3c?F;d;N)o8Px>jJTP0U0pSHU%sZK+5PH2!eaanht~8RIR5LKb|)gd zE-PzR&b#fm?8)AFoD_Ngyu7KrD^c;DyDS~#5h2e9)Eu{B4zeSoa(J#8kFD!7H;XJp z+gTf?a_pKo-=qd#s@peuQmtL$G}(?tyY?I#>*y}1U-IbK-4nx0?pJ5q9Bz@c6!lTTJA3dyP zCA&@3;lJ5D++?>g`pES!iz|I&yl#ur?tQmF`h8W7^`xx@hqSYvWPiU-wRE`u)A#Of z+VkK`b<@oGgA-N$rlx-G=h8pOwGj>c=&<2OmvgVy zb!>GwZZp~IN#0~9Md|3&M?dD61dbXJSNXGMjD75&hohC@;{wXoE{-}n^z8bm8F|Aq zHg}w}jci@NZ2GVp%WYCl)gQ4ud9J{h9kH`-+pT++S6gD%&uS_h)lxaTYVf*BzE+~K zowj84>>s@A!imrYc5y~UOA_Z|=D(U)7VXH2<`}U)(^_Y)Kh{68$hLN~(9JDqVN3e% zz#-ep1CKk;&%fyvp8BBJ?9BOxm-^iG$ZH%}kTk=cef8sIRW}YSG)%tK)>2`caPxyv zDQ6aL4&0VuQy6EuBHyCcI-}inUqQ>YoSh>Bw{KXw$Nkj3{I&tX@qs%-KfLtqREwXl z#dWl=x^cI?IB;Ub%#p|I7AxB(m_IvL7ZtY;{Th zbinM>yLOak{&!5lousk-fA?x@b@v!*rOeKqySI6G>~HnSdpOD0ciE=2{dy>Jsw6#%b)j;{wt$KCJcE9<2X@Y@sfdmc zRu3M$;>@x_A7l8_jmz_3nHQT6 { - beforeAll(() => { - registerAriesAskar({ askar: ariesAskar }) - }) - test('indy-sdk sqlite to aries-askar sqlite successful migration', async () => { const indySdkAndAskarConfig: InitConfig = { - label: `indy | indy-sdk sqlite to aries-askar sqlite successful migration | ${utils.uuid()}`, + label: `indy | indy-sdk sqlite to aries-askar sqlite successful migration`, walletConfig: { - id: `indy-sdk sqlite to aries-askar sqlite successful migration | ${utils.uuid()}`, + id: `indy-sdk sqlite to aries-askar sqlite successful migration`, key: 'GfwU1DC7gEZNs3w41tjBiZYj7BNToDoFEqKY6wZXqs1A', keyDerivationMethod: KeyDerivationMethod.Raw, }, } - const indySdkAgent = new Agent({ - config: indySdkAndAskarConfig, - modules: { indySdk: new IndySdkModule({ indySdk: indy }) }, - dependencies: agentDependencies, - }) - const indySdkAgentDbPath = `${homedir()}/.indy_client/wallet/${indySdkAndAskarConfig.walletConfig?.id}/sqlite.db` - - const genericRecordContent = { foo: 'bar' } - - await indySdkAgent.initialize() - - const record = await indySdkAgent.genericRecords.save({ content: genericRecordContent }) - - await indySdkAgent.shutdown() - + const indySdkWalletTestPath = path.join(__dirname, 'indy-sdk-040-wallet.db') const askarAgent = new Agent({ config: indySdkAndAskarConfig, - modules: { askar: new AskarModule({ ariesAskar }) }, + modules: { askar: askarModule }, dependencies: agentDependencies, }) - const updater = await IndySdkToAskarMigrationUpdater.initialize({ dbPath: indySdkAgentDbPath, agent: askarAgent }) - await updater.update() + // Remove new wallet path (if exists) + if (existsSync(updater.newWalletPath)) unlinkSync(updater.newWalletPath) + + // Create old wallet path and copy test wallet + mkdirSync(path.dirname(indySdkAgentDbPath), { recursive: true }) + copyFileSync(indySdkWalletTestPath, indySdkAgentDbPath) + + await updater.update() await askarAgent.initialize() - await expect(askarAgent.genericRecords.findById(record.id)).resolves.toMatchObject({ - content: genericRecordContent, - }) + await expect(askarAgent.genericRecords.getAll()).resolves.toMatchObject([ + { + content: { + foo: 'bar', + }, + }, + ]) await askarAgent.shutdown() }) @@ -70,38 +60,21 @@ describe('Indy SDK To Askar Migration', () => { */ test('indy-sdk sqlite to aries-askar sqlite fails and restores', async () => { const indySdkAndAskarConfig: InitConfig = { - label: `indy | indy-sdk sqlite to aries-askar sqlite fails and restores | ${utils.uuid()}`, + label: `indy | indy-sdk sqlite to aries-askar sqlite fails and restores`, walletConfig: { - id: `indy-sdk sqlite to aries-askar sqlite fails and restores | ${utils.uuid()}`, - key: 'GfwU1DC7gEZNs3w41tjBiZYj7BNToDoFEqKY6wZXqs1A', + id: `indy-sdk sqlite to aries-askar sqlite fails and restores`, + // NOTE: wrong key passed + key: 'wrong-key', keyDerivationMethod: KeyDerivationMethod.Raw, }, } - const indySdkAgent = new Agent({ - config: indySdkAndAskarConfig, - modules: { indySdk: new IndySdkModule({ indySdk: indy }) }, - dependencies: agentDependencies, - }) - const indySdkAgentDbPath = `${homedir()}/.indy_client/wallet/${indySdkAndAskarConfig.walletConfig?.id}/sqlite.db` - - const genericRecordContent = { foo: 'bar' } - - await indySdkAgent.initialize() - - const record = await indySdkAgent.genericRecords.save({ content: genericRecordContent }) - - await indySdkAgent.shutdown() + const indySdkWalletTestPath = path.join(__dirname, 'indy-sdk-040-wallet.db') const askarAgent = new Agent({ - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - config: { ...indySdkAndAskarConfig, walletConfig: { ...indySdkAndAskarConfig.walletConfig!, key: 'wrong-key' } }, - modules: { - askar: new AskarModule({ - ariesAskar, - }), - }, + config: indySdkAndAskarConfig, + modules: { askar: askarModule }, dependencies: agentDependencies, }) @@ -110,12 +83,14 @@ describe('Indy SDK To Askar Migration', () => { agent: askarAgent, }) - await expect(updater.update()).rejects.toThrowError(IndySdkToAskarMigrationError) + // Remove new wallet path (if exists) + if (existsSync(updater.newWalletPath)) unlinkSync(updater.newWalletPath) - await indySdkAgent.initialize() + // Create old wallet path and copy test wallet + mkdirSync(path.dirname(indySdkAgentDbPath), { recursive: true }) + copyFileSync(indySdkWalletTestPath, indySdkAgentDbPath) - await expect(indySdkAgent.genericRecords.findById(record.id)).resolves.toMatchObject({ - content: genericRecordContent, - }) + await expect(updater.update()).rejects.toThrowError(IndySdkToAskarMigrationError) + expect(existsSync(indySdkWalletTestPath)).toBe(true) }) }) diff --git a/packages/indy-sdk/CHANGELOG.md b/packages/indy-sdk/CHANGELOG.md deleted file mode 100644 index 162267c246..0000000000 --- a/packages/indy-sdk/CHANGELOG.md +++ /dev/null @@ -1,59 +0,0 @@ -# Change Log - -All notable changes to this project will be documented in this file. -See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. - -## [0.4.2](https://github.com/hyperledger/aries-framework-javascript/compare/v0.4.1...v0.4.2) (2023-10-05) - -### Bug Fixes - -- update tsyringe for ts 5 support ([#1588](https://github.com/hyperledger/aries-framework-javascript/issues/1588)) ([296955b](https://github.com/hyperledger/aries-framework-javascript/commit/296955b3a648416ac6b502da05a10001920af222)) - -## [0.4.1](https://github.com/hyperledger/aries-framework-javascript/compare/v0.4.0...v0.4.1) (2023-08-28) - -### Bug Fixes - -- **anoncreds:** wrong key name for predicates in proof object ([#1517](https://github.com/hyperledger/aries-framework-javascript/issues/1517)) ([d895c78](https://github.com/hyperledger/aries-framework-javascript/commit/d895c78e0e02954a95ad1fd7e2251ee9a02445dc)) -- force did:key resolver/registrar presence ([#1535](https://github.com/hyperledger/aries-framework-javascript/issues/1535)) ([aaa13dc](https://github.com/hyperledger/aries-framework-javascript/commit/aaa13dc77d6d5133cd02e768e4173462fa65064a)) - -### Features - -- **anoncreds:** auto create link secret ([#1521](https://github.com/hyperledger/aries-framework-javascript/issues/1521)) ([c6f03e4](https://github.com/hyperledger/aries-framework-javascript/commit/c6f03e49d79a33b1c4b459cef11add93dee051d0)) - -# [0.4.0](https://github.com/hyperledger/aries-framework-javascript/compare/v0.3.3...v0.4.0) (2023-06-03) - -### Bug Fixes - -- **anoncreds:** include prover_did for legacy indy ([#1342](https://github.com/hyperledger/aries-framework-javascript/issues/1342)) ([d38ecb1](https://github.com/hyperledger/aries-framework-javascript/commit/d38ecb14cb58f1eb78e01c91699bb990d805dc08)) -- **anoncreds:** make revocation status list inline with the spec ([#1421](https://github.com/hyperledger/aries-framework-javascript/issues/1421)) ([644e860](https://github.com/hyperledger/aries-framework-javascript/commit/644e860a05f40166e26c497a2e8619c9a38df11d)) -- did cache key not being set correctly ([#1394](https://github.com/hyperledger/aries-framework-javascript/issues/1394)) ([1125e81](https://github.com/hyperledger/aries-framework-javascript/commit/1125e81962ffa752bf40fa8f7f4226e186f22013)) -- expose indy pool configs and action menu messages ([#1333](https://github.com/hyperledger/aries-framework-javascript/issues/1333)) ([518e5e4](https://github.com/hyperledger/aries-framework-javascript/commit/518e5e4dfb59f9c0457bfd233409e9f4b3c429ee)) -- **indy-sdk:** import from core ([#1346](https://github.com/hyperledger/aries-framework-javascript/issues/1346)) ([254f661](https://github.com/hyperledger/aries-framework-javascript/commit/254f661c2e925b62dd07c3565099f9e226bd2b41)) -- issuance with unqualified identifiers ([#1431](https://github.com/hyperledger/aries-framework-javascript/issues/1431)) ([de90caf](https://github.com/hyperledger/aries-framework-javascript/commit/de90cafb8d12b7a940f881184cd745c4b5043cbc)) -- reference to indyLedgers in IndyXXXNotConfiguredError ([#1397](https://github.com/hyperledger/aries-framework-javascript/issues/1397)) ([d6e2ea2](https://github.com/hyperledger/aries-framework-javascript/commit/d6e2ea2194a4860265fe299ef8ee4cb4799ab1a6)) -- remove named capture groups ([#1378](https://github.com/hyperledger/aries-framework-javascript/issues/1378)) ([a4204ef](https://github.com/hyperledger/aries-framework-javascript/commit/a4204ef2db769de53d12f0d881d2c4422545c390)) -- seed and private key validation and return type in registrars ([#1324](https://github.com/hyperledger/aries-framework-javascript/issues/1324)) ([c0e5339](https://github.com/hyperledger/aries-framework-javascript/commit/c0e5339edfa32df92f23fb9c920796b4b59adf52)) -- various anoncreds revocation fixes ([#1416](https://github.com/hyperledger/aries-framework-javascript/issues/1416)) ([d9cfc7d](https://github.com/hyperledger/aries-framework-javascript/commit/d9cfc7df6679d2008d66070a6c8a818440d066ab)) - -- feat!: add data, cache and temp dirs to FileSystem (#1306) ([ff5596d](https://github.com/hyperledger/aries-framework-javascript/commit/ff5596d0631e93746494c017797d0191b6bdb0b1)), closes [#1306](https://github.com/hyperledger/aries-framework-javascript/issues/1306) - -### Features - -- 0.4.0 migration script ([#1392](https://github.com/hyperledger/aries-framework-javascript/issues/1392)) ([bc5455f](https://github.com/hyperledger/aries-framework-javascript/commit/bc5455f7b42612a2b85e504bc6ddd36283a42bfa)) -- add anoncreds-rs package ([#1275](https://github.com/hyperledger/aries-framework-javascript/issues/1275)) ([efe0271](https://github.com/hyperledger/aries-framework-javascript/commit/efe0271198f21f1307df0f934c380f7a5c720b06)) -- add fetch indy schema method ([#1290](https://github.com/hyperledger/aries-framework-javascript/issues/1290)) ([1d782f5](https://github.com/hyperledger/aries-framework-javascript/commit/1d782f54bbb4abfeb6b6db6cd4f7164501b6c3d9)) -- **anoncreds:** add anoncreds API ([#1232](https://github.com/hyperledger/aries-framework-javascript/issues/1232)) ([3a4c5ec](https://github.com/hyperledger/aries-framework-javascript/commit/3a4c5ecd940e49d4d192eef1d41f2aaedb34d85a)) -- **anoncreds:** add getCredential(s) methods ([#1386](https://github.com/hyperledger/aries-framework-javascript/issues/1386)) ([2efc009](https://github.com/hyperledger/aries-framework-javascript/commit/2efc0097138585391940fbb2eb504e50df57ec87)) -- **anoncreds:** add legacy indy credential format ([#1220](https://github.com/hyperledger/aries-framework-javascript/issues/1220)) ([13f3740](https://github.com/hyperledger/aries-framework-javascript/commit/13f374079262168f90ec7de7c3393beb9651295c)) -- **anoncreds:** legacy indy proof format service ([#1283](https://github.com/hyperledger/aries-framework-javascript/issues/1283)) ([c72fd74](https://github.com/hyperledger/aries-framework-javascript/commit/c72fd7416f2c1bc0497a84036e16adfa80585e49)) -- **anoncreds:** store method name in records ([#1387](https://github.com/hyperledger/aries-framework-javascript/issues/1387)) ([47636b4](https://github.com/hyperledger/aries-framework-javascript/commit/47636b4a08ffbfa9a3f2a5a3c5aebda44f7d16c8)) -- **anoncreds:** use legacy prover did ([#1374](https://github.com/hyperledger/aries-framework-javascript/issues/1374)) ([c17013c](https://github.com/hyperledger/aries-framework-javascript/commit/c17013c808a278d624210ce9e4333860cd78fc19)) -- **cache:** add caching interface ([#1229](https://github.com/hyperledger/aries-framework-javascript/issues/1229)) ([25b2bcf](https://github.com/hyperledger/aries-framework-javascript/commit/25b2bcf81648100b572784e4489a288cc9da0557)) -- **indy-vdr:** add IndyVdrAnonCredsRegistry ([#1270](https://github.com/hyperledger/aries-framework-javascript/issues/1270)) ([d056316](https://github.com/hyperledger/aries-framework-javascript/commit/d056316712b5ee5c42a159816b5dda0b05ad84a8)) -- **openid4vc:** jwt format and more crypto ([#1472](https://github.com/hyperledger/aries-framework-javascript/issues/1472)) ([bd4932d](https://github.com/hyperledger/aries-framework-javascript/commit/bd4932d34f7314a6d49097b6460c7570e1ebc7a8)) - -### BREAKING CHANGES - -- Agent-produced files will now be divided in different system paths depending on their nature: data, temp and cache. Previously, they were located at a single location, defaulting to a temporary directory. - -If you specified a custom path in `FileSystem` object constructor, you now must provide an object containing `baseDataPath`, `baseTempPath` and `baseCachePath`. They can point to the same path, although it's recommended to specify different path to avoid future file clashes. diff --git a/packages/indy-sdk/README.md b/packages/indy-sdk/README.md deleted file mode 100644 index 28cfde1767..0000000000 --- a/packages/indy-sdk/README.md +++ /dev/null @@ -1,31 +0,0 @@ -

-
- Credo Logo -

-

Credo IndySDK Module

-

- License - typescript - @credo-ts/indy-sdk version - -

-
- -IndySDK module for [Credo](https://github.com/openwallet-foundation/credo-ts.git). diff --git a/packages/indy-sdk/jest.config.ts b/packages/indy-sdk/jest.config.ts deleted file mode 100644 index 93c0197296..0000000000 --- a/packages/indy-sdk/jest.config.ts +++ /dev/null @@ -1,13 +0,0 @@ -import type { Config } from '@jest/types' - -import base from '../../jest.config.base' - -import packageJson from './package.json' - -const config: Config.InitialOptions = { - ...base, - displayName: packageJson.name, - setupFilesAfterEnv: ['./tests/setup.ts'], -} - -export default config diff --git a/packages/indy-sdk/package.json b/packages/indy-sdk/package.json deleted file mode 100644 index f9dfd67cf4..0000000000 --- a/packages/indy-sdk/package.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "name": "@credo-ts/indy-sdk", - "main": "build/index", - "types": "build/index", - "private": true, - "version": "0.4.2", - "files": [ - "build" - ], - "license": "Apache-2.0", - "publishConfig": { - "access": "public" - }, - "homepage": "https://github.com/openwallet-foundation/credo-ts/tree/main/packages/indy-sdk", - "repository": { - "type": "git", - "url": "https://github.com/openwallet-foundation/credo-ts", - "directory": "packages/indy-sdk" - }, - "scripts": { - "build": "yarn run clean && yarn run compile", - "clean": "rimraf ./build", - "compile": "tsc -p tsconfig.build.json", - "prepublishOnly": "yarn run build", - "test": "jest" - }, - "dependencies": { - "@credo-ts/anoncreds": "0.4.2", - "@credo-ts/core": "0.4.2", - "@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" - }, - "devDependencies": { - "rimraf": "^4.4.0", - "typescript": "~4.9.5" - } -} diff --git a/packages/indy-sdk/src/IndySdkModule.ts b/packages/indy-sdk/src/IndySdkModule.ts deleted file mode 100644 index d501ece519..0000000000 --- a/packages/indy-sdk/src/IndySdkModule.ts +++ /dev/null @@ -1,60 +0,0 @@ -import type { IndySdkModuleConfigOptions } from './IndySdkModuleConfig' -import type { AgentContext, DependencyManager, Module } from '@credo-ts/core' - -import { - AnonCredsHolderServiceSymbol, - AnonCredsIssuerServiceSymbol, - AnonCredsVerifierServiceSymbol, -} from '@credo-ts/anoncreds' -import { AriesFrameworkError, InjectionSymbols } from '@credo-ts/core' - -import { IndySdkModuleConfig } from './IndySdkModuleConfig' -import { IndySdkHolderService, IndySdkIssuerService, IndySdkVerifierService } from './anoncreds' -import { IndySdkPoolService } from './ledger' -import { IndySdkStorageService } from './storage' -import { IndySdkSymbol } from './types' -import { IndySdkWallet } from './wallet' - -export class IndySdkModule implements Module { - public readonly config: IndySdkModuleConfig - - public constructor(config: IndySdkModuleConfigOptions) { - this.config = new IndySdkModuleConfig(config) - } - - public register(dependencyManager: DependencyManager) { - dependencyManager.registerInstance(IndySdkSymbol, this.config.indySdk) - - // Register config - dependencyManager.registerInstance(IndySdkModuleConfig, this.config) - - if (dependencyManager.isRegistered(InjectionSymbols.Wallet)) { - throw new AriesFrameworkError('There is an instance of Wallet already registered') - } else { - dependencyManager.registerContextScoped(InjectionSymbols.Wallet, IndySdkWallet) - } - - if (dependencyManager.isRegistered(InjectionSymbols.StorageService)) { - throw new AriesFrameworkError('There is an instance of StorageService already registered') - } else { - dependencyManager.registerSingleton(InjectionSymbols.StorageService, IndySdkStorageService) - } - - // NOTE: for now we are registering the needed indy services. We may want to make this - // more explicit and require the user to register the services they need on the specific modules. - dependencyManager.registerSingleton(IndySdkPoolService) - dependencyManager.registerSingleton(AnonCredsIssuerServiceSymbol, IndySdkIssuerService) - dependencyManager.registerSingleton(AnonCredsHolderServiceSymbol, IndySdkHolderService) - dependencyManager.registerSingleton(AnonCredsVerifierServiceSymbol, IndySdkVerifierService) - } - - public async initialize(agentContext: AgentContext): Promise { - const indySdkPoolService = agentContext.dependencyManager.resolve(IndySdkPoolService) - - for (const pool of indySdkPoolService.pools) { - if (pool.config.connectOnStartup) { - await pool.connect() - } - } - } -} diff --git a/packages/indy-sdk/src/IndySdkModuleConfig.ts b/packages/indy-sdk/src/IndySdkModuleConfig.ts deleted file mode 100644 index 65478f507c..0000000000 --- a/packages/indy-sdk/src/IndySdkModuleConfig.ts +++ /dev/null @@ -1,81 +0,0 @@ -import type { IndySdkPoolConfig } from './ledger' -import type * as IndySdk from 'indy-sdk' - -/** - * IndySdkModuleConfigOptions defines the interface for the options of the IndySdkModuleConfig class. - */ -export interface IndySdkModuleConfigOptions { - /** - * Implementation of the IndySdk interface according to the @types/indy-sdk package. - * - * - * ## Node.JS - * - * ```ts - * import * as indySdk from 'indy-sdk' - * - * const indySdkModule = new IndySdkModule({ - * indySdk - * }) - * ``` - * - * ## React Native - * - * ```ts - * import indySdk from 'indy-sdk-react-native' - * - * const indySdkModule = new IndySdkModule({ - * indySdk - * }) - * ``` - */ - indySdk: typeof IndySdk - - /** - * Array of indy networks to connect to. Each item in the list must include either the `genesisPath` or `genesisTransactions` property. - * - * @default [] - * - * @example - * ``` - * { - * isProduction: false, - * genesisPath: '/path/to/genesis.txn', - * indyNamespace: 'localhost:test', - * transactionAuthorAgreement: { - * version: '1', - * acceptanceMechanism: 'accept' - * } - * } - * ``` - */ - networks?: IndySdkPoolConfig[] - - /** - * Create a default link secret if there are no created link secrets. - * @defaultValue true - */ - autoCreateLinkSecret?: boolean -} - -export class IndySdkModuleConfig { - private options: IndySdkModuleConfigOptions - - public constructor(options: IndySdkModuleConfigOptions) { - this.options = options - } - - /** See {@link IndySdkModuleConfigOptions.indySdk} */ - public get indySdk() { - return this.options.indySdk - } - - public get networks() { - return this.options.networks ?? [] - } - - /** See {@link AnonCredsModuleConfigOptions.autoCreateLinkSecret} */ - public get autoCreateLinkSecret() { - return this.options.autoCreateLinkSecret ?? true - } -} diff --git a/packages/indy-sdk/src/anoncreds/index.ts b/packages/indy-sdk/src/anoncreds/index.ts deleted file mode 100644 index adba521ce0..0000000000 --- a/packages/indy-sdk/src/anoncreds/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export { IndySdkAnonCredsRegistry } from './services/IndySdkAnonCredsRegistry' -export { IndySdkHolderService } from './services/IndySdkHolderService' -export { IndySdkIssuerService } from './services/IndySdkIssuerService' -export { IndySdkVerifierService } from './services/IndySdkVerifierService' diff --git a/packages/indy-sdk/src/anoncreds/services/IndySdkAnonCredsRegistry.ts b/packages/indy-sdk/src/anoncreds/services/IndySdkAnonCredsRegistry.ts deleted file mode 100644 index 96b398d567..0000000000 --- a/packages/indy-sdk/src/anoncreds/services/IndySdkAnonCredsRegistry.ts +++ /dev/null @@ -1,634 +0,0 @@ -import type { IndySdkPool } from '../../ledger' -import type { IndySdk } from '../../types' -import type { - AnonCredsRegistry, - GetCredentialDefinitionReturn, - GetRevocationStatusListReturn, - GetRevocationRegistryDefinitionReturn, - GetSchemaReturn, - RegisterCredentialDefinitionOptions, - RegisterCredentialDefinitionReturn, - RegisterSchemaOptions, - RegisterSchemaReturn, - RegisterRevocationRegistryDefinitionReturn, - RegisterRevocationStatusListReturn, -} from '@credo-ts/anoncreds' -import type { AgentContext } from '@credo-ts/core' -import type { Schema as IndySdkSchema } from 'indy-sdk' - -import { - getUnqualifiedCredentialDefinitionId, - getUnqualifiedRevocationRegistryDefinitionId, - getUnqualifiedSchemaId, - parseIndyCredentialDefinitionId, - parseIndyDid, - parseIndyRevocationRegistryId, - parseIndySchemaId, -} from '@credo-ts/anoncreds' -import { AriesFrameworkError } from '@credo-ts/core' - -import { verificationKeyForIndyDid } from '../../dids/didIndyUtil' -import { IndySdkError, isIndyError } from '../../error' -import { IndySdkPoolService } from '../../ledger' -import { IndySdkSymbol } from '../../types' -import { - getDidIndyCredentialDefinitionId, - getDidIndySchemaId, - indySdkAnonCredsRegistryIdentifierRegex, -} from '../utils/identifiers' -import { anonCredsRevocationStatusListFromIndySdk } from '../utils/transform' - -export class IndySdkAnonCredsRegistry implements AnonCredsRegistry { - public readonly methodName = 'indy' - - /** - * This class supports resolving and registering objects with did:indy as well as legacy indy identifiers. - * It needs to include support for the schema, credential definition, revocation registry as well - * as the issuer id (which is needed when registering objects). - */ - public readonly supportedIdentifier = indySdkAnonCredsRegistryIdentifierRegex - - public async getSchema(agentContext: AgentContext, schemaId: string): Promise { - try { - const indySdkPoolService = agentContext.dependencyManager.resolve(IndySdkPoolService) - const indySdk = agentContext.dependencyManager.resolve(IndySdkSymbol) - - // parse schema id (supports did:indy and legacy) - const { did, namespaceIdentifier, schemaName, schemaVersion } = parseIndySchemaId(schemaId) - const { pool } = await indySdkPoolService.getPoolForDid(agentContext, did) - agentContext.config.logger.debug(`Getting schema '${schemaId}' from ledger '${pool.didIndyNamespace}'`) - - // even though we support did:indy and legacy identifiers we always need to fetch using the legacy identifier - const legacySchemaId = getUnqualifiedSchemaId(namespaceIdentifier, schemaName, schemaVersion) - const request = await indySdk.buildGetSchemaRequest(null, legacySchemaId) - - agentContext.config.logger.trace( - `Submitting get schema request for schema '${schemaId}' to ledger '${pool.didIndyNamespace}'` - ) - const response = await indySdkPoolService.submitReadRequest(pool, request) - - agentContext.config.logger.trace(`Got un-parsed schema '${schemaId}' from ledger '${pool.didIndyNamespace}'`, { - response, - }) - - const [, schema] = await indySdk.parseGetSchemaResponse(response) - agentContext.config.logger.debug(`Got schema '${schemaId}' from ledger '${pool.didIndyNamespace}'`, { - schema, - }) - - return { - schema: { - attrNames: schema.attrNames, - name: schema.name, - version: schema.version, - issuerId: did, - }, - schemaId, - resolutionMetadata: {}, - schemaMetadata: { - didIndyNamespace: pool.didIndyNamespace, - // NOTE: the seqNo is required by the indy-sdk even though not present in AnonCreds v1. - // For this reason we return it in the metadata. - indyLedgerSeqNo: schema.seqNo, - }, - } - } catch (error) { - agentContext.config.logger.error(`Error retrieving schema '${schemaId}'`, { - error, - schemaId, - }) - - return { - schemaId, - resolutionMetadata: { - error: 'notFound', - message: `unable to resolve credential definition: ${error.message}`, - }, - schemaMetadata: {}, - } - } - } - - public async registerSchema( - agentContext: AgentContext, - options: RegisterSchemaOptions - ): Promise { - try { - // This will throw an error if trying to register a schema with a legacy indy identifier. We only support did:indy identifiers - // for registering, that will allow us to extract the namespace and means all stored records will use did:indy identifiers. - const { namespaceIdentifier, namespace } = parseIndyDid(options.schema.issuerId) - - const indySdkPoolService = agentContext.dependencyManager.resolve(IndySdkPoolService) - const indySdk = agentContext.dependencyManager.resolve(IndySdkSymbol) - - const pool = indySdkPoolService.getPoolForNamespace(namespace) - agentContext.config.logger.debug( - `Register schema on ledger '${pool.didIndyNamespace}' with did '${options.schema.issuerId}'`, - options.schema - ) - - const didIndySchemaId = getDidIndySchemaId( - namespace, - namespaceIdentifier, - options.schema.name, - options.schema.version - ) - const legacySchemaId = getUnqualifiedSchemaId(namespaceIdentifier, options.schema.name, options.schema.version) - - const schema = { - attrNames: options.schema.attrNames, - name: options.schema.name, - version: options.schema.version, - id: legacySchemaId, - ver: '1.0', - // Casted as because the type expect a seqNo, but that's not actually required for the input of - // buildSchemaRequest (seqNo is not yet known) - } as IndySdkSchema - - const request = await indySdk.buildSchemaRequest(namespaceIdentifier, schema) - const submitterKey = await verificationKeyForIndyDid(agentContext, options.schema.issuerId) - - const response = await indySdkPoolService.submitWriteRequest(agentContext, pool, request, submitterKey) - agentContext.config.logger.debug(`Registered schema '${schema.id}' on ledger '${pool.didIndyNamespace}'`, { - response, - schema, - }) - - return { - schemaState: { - state: 'finished', - schema: { - attrNames: schema.attrNames, - issuerId: options.schema.issuerId, - name: schema.name, - version: schema.version, - }, - schemaId: didIndySchemaId, - }, - registrationMetadata: {}, - schemaMetadata: { - // NOTE: the seqNo is required by the indy-sdk even though not present in AnonCreds v1. - // For this reason we return it in the metadata. - indyLedgerSeqNo: response.result.txnMetadata.seqNo, - }, - } - } catch (error) { - agentContext.config.logger.error(`Error registering schema for did '${options.schema.issuerId}'`, { - error, - did: options.schema.issuerId, - schema: options.schema, - }) - - return { - schemaMetadata: {}, - registrationMetadata: {}, - schemaState: { - state: 'failed', - schema: options.schema, - reason: `unknownError: ${error.message}`, - }, - } - } - } - - public async getCredentialDefinition( - agentContext: AgentContext, - credentialDefinitionId: string - ): Promise { - try { - const indySdkPoolService = agentContext.dependencyManager.resolve(IndySdkPoolService) - const indySdk = agentContext.dependencyManager.resolve(IndySdkSymbol) - - // we support did:indy and legacy identifiers - const { did, namespaceIdentifier, schemaSeqNo, tag } = parseIndyCredentialDefinitionId(credentialDefinitionId) - const { pool } = await indySdkPoolService.getPoolForDid(agentContext, did) - - agentContext.config.logger.debug( - `Using ledger '${pool.didIndyNamespace}' to retrieve credential definition '${credentialDefinitionId}'` - ) - - const legacyCredentialDefinitionId = getUnqualifiedCredentialDefinitionId(namespaceIdentifier, schemaSeqNo, tag) - const request = await indySdk.buildGetCredDefRequest(null, legacyCredentialDefinitionId) - - agentContext.config.logger.trace( - `Submitting get credential definition request for credential definition '${credentialDefinitionId}' to ledger '${pool.didIndyNamespace}'` - ) - - const response = await indySdkPoolService.submitReadRequest(pool, request) - agentContext.config.logger.trace( - `Got un-parsed credential definition '${credentialDefinitionId}' from ledger '${pool.didIndyNamespace}'`, - { - response, - } - ) - - const [, credentialDefinition] = await indySdk.parseGetCredDefResponse(response) - const { schema } = await this.fetchIndySchemaWithSeqNo(agentContext, pool, Number(credentialDefinition.schemaId)) - - if (credentialDefinition && schema) { - agentContext.config.logger.debug( - `Got credential definition '${credentialDefinitionId}' from ledger '${pool.didIndyNamespace}'`, - { - credentialDefinition, - } - ) - - // Format the schema id based on the type of the credential definition id - const schemaId = credentialDefinitionId.startsWith('did:indy') - ? getDidIndySchemaId(pool.didIndyNamespace, namespaceIdentifier, schema.name, schema.version) - : schema.schemaId - - return { - credentialDefinitionId, - credentialDefinition: { - issuerId: did, - schemaId, - tag: credentialDefinition.tag, - type: 'CL', - value: credentialDefinition.value, - }, - credentialDefinitionMetadata: { - didIndyNamespace: pool.didIndyNamespace, - }, - resolutionMetadata: {}, - } - } - - agentContext.config.logger.error(`Error retrieving credential definition '${credentialDefinitionId}'`, { - credentialDefinitionId, - }) - - return { - credentialDefinitionId, - credentialDefinitionMetadata: {}, - resolutionMetadata: { - error: 'notFound', - message: `unable to resolve credential definition`, - }, - } - } catch (error) { - agentContext.config.logger.error(`Error retrieving credential definition '${credentialDefinitionId}'`, { - error, - credentialDefinitionId, - }) - - return { - credentialDefinitionId, - credentialDefinitionMetadata: {}, - resolutionMetadata: { - error: 'notFound', - message: `unable to resolve credential definition: ${error.message}`, - }, - } - } - } - - public async registerCredentialDefinition( - agentContext: AgentContext, - options: RegisterCredentialDefinitionOptions - ): Promise { - try { - // This will throw an error if trying to register a credential defintion with a legacy indy identifier. We only support did:indy - // identifiers for registering, that will allow us to extract the namespace and means all stored records will use did:indy identifiers. - const { namespaceIdentifier, namespace } = parseIndyDid(options.credentialDefinition.issuerId) - - const indySdkPoolService = agentContext.dependencyManager.resolve(IndySdkPoolService) - const indySdk = agentContext.dependencyManager.resolve(IndySdkSymbol) - - const pool = indySdkPoolService.getPoolForNamespace(namespace) - agentContext.config.logger.debug( - `Registering credential definition on ledger '${pool.didIndyNamespace}' with did '${options.credentialDefinition.issuerId}'`, - options.credentialDefinition - ) - - // TODO: check structure of the schemaId - // TODO: this will bypass caching if done on a higher level. - const { schema, schemaMetadata, resolutionMetadata } = await this.getSchema( - agentContext, - options.credentialDefinition.schemaId - ) - - if (!schema || !schemaMetadata.indyLedgerSeqNo || typeof schemaMetadata.indyLedgerSeqNo !== 'number') { - return { - registrationMetadata: {}, - credentialDefinitionMetadata: { - didIndyNamespace: pool.didIndyNamespace, - }, - credentialDefinitionState: { - credentialDefinition: options.credentialDefinition, - state: 'failed', - reason: `error resolving schema with id ${options.credentialDefinition.schemaId}: ${resolutionMetadata.error} ${resolutionMetadata.message}`, - }, - } - } - - const legacyCredentialDefinitionId = getUnqualifiedCredentialDefinitionId( - namespaceIdentifier, - schemaMetadata.indyLedgerSeqNo, - options.credentialDefinition.tag - ) - const didIndyCredentialDefinitionId = getDidIndyCredentialDefinitionId( - namespace, - namespaceIdentifier, - schemaMetadata.indyLedgerSeqNo, - options.credentialDefinition.tag - ) - - const request = await indySdk.buildCredDefRequest(namespaceIdentifier, { - id: legacyCredentialDefinitionId, - // Indy ledger requires the credential schemaId to be a string of the schema seqNo. - schemaId: schemaMetadata.indyLedgerSeqNo.toString(), - tag: options.credentialDefinition.tag, - type: options.credentialDefinition.type, - value: options.credentialDefinition.value, - ver: '1.0', - }) - - const submitterKey = await verificationKeyForIndyDid(agentContext, options.credentialDefinition.issuerId) - const response = await indySdkPoolService.submitWriteRequest(agentContext, pool, request, submitterKey) - - agentContext.config.logger.debug( - `Registered credential definition '${didIndyCredentialDefinitionId}' on ledger '${pool.didIndyNamespace}'`, - { - response, - credentialDefinition: options.credentialDefinition, - } - ) - - return { - credentialDefinitionMetadata: {}, - credentialDefinitionState: { - credentialDefinition: options.credentialDefinition, - credentialDefinitionId: didIndyCredentialDefinitionId, - state: 'finished', - }, - registrationMetadata: {}, - } - } catch (error) { - agentContext.config.logger.error( - `Error registering credential definition for schema '${options.credentialDefinition.schemaId}'`, - { - error, - did: options.credentialDefinition.issuerId, - credentialDefinition: options.credentialDefinition, - } - ) - - throw isIndyError(error) ? new IndySdkError(error) : error - } - } - - public async getRevocationRegistryDefinition( - agentContext: AgentContext, - revocationRegistryDefinitionId: string - ): Promise { - try { - const indySdkPoolService = agentContext.dependencyManager.resolve(IndySdkPoolService) - const indySdk = agentContext.dependencyManager.resolve(IndySdkSymbol) - - const { did, namespaceIdentifier, credentialDefinitionTag, revocationRegistryTag, schemaSeqNo } = - parseIndyRevocationRegistryId(revocationRegistryDefinitionId) - const { pool } = await indySdkPoolService.getPoolForDid(agentContext, did) - - agentContext.config.logger.debug( - `Using ledger '${pool.didIndyNamespace}' to retrieve revocation registry definition '${revocationRegistryDefinitionId}'` - ) - - const legacyRevocationRegistryId = getUnqualifiedRevocationRegistryDefinitionId( - namespaceIdentifier, - schemaSeqNo, - credentialDefinitionTag, - revocationRegistryTag - ) - const request = await indySdk.buildGetRevocRegDefRequest(null, legacyRevocationRegistryId) - - agentContext.config.logger.trace( - `Submitting get revocation registry definition request for revocation registry definition '${revocationRegistryDefinitionId}' to ledger` - ) - const response = await indySdkPoolService.submitReadRequest(pool, request) - agentContext.config.logger.trace( - `Got un-parsed revocation registry definition '${revocationRegistryDefinitionId}' from ledger '${pool.didIndyNamespace}'`, - { - response, - } - ) - - const [, revocationRegistryDefinition] = await indySdk.parseGetRevocRegDefResponse(response) - - agentContext.config.logger.debug( - `Got revocation registry definition '${revocationRegistryDefinitionId}' from ledger`, - { - revocationRegistryDefinition, - } - ) - - const credentialDefinitionId = revocationRegistryDefinitionId.startsWith('did:indy:') - ? getDidIndyCredentialDefinitionId( - pool.didIndyNamespace, - namespaceIdentifier, - schemaSeqNo, - credentialDefinitionTag - ) - : getUnqualifiedCredentialDefinitionId(namespaceIdentifier, schemaSeqNo, credentialDefinitionTag) - - return { - resolutionMetadata: {}, - revocationRegistryDefinition: { - issuerId: did, - credDefId: credentialDefinitionId, - value: { - maxCredNum: revocationRegistryDefinition.value.maxCredNum, - publicKeys: revocationRegistryDefinition.value.publicKeys, - tailsHash: revocationRegistryDefinition.value.tailsHash, - tailsLocation: revocationRegistryDefinition.value.tailsLocation, - }, - tag: revocationRegistryDefinition.tag, - revocDefType: 'CL_ACCUM', - }, - revocationRegistryDefinitionId, - revocationRegistryDefinitionMetadata: { - issuanceType: revocationRegistryDefinition.value.issuanceType, - didIndyNamespace: pool.didIndyNamespace, - }, - } - } catch (error) { - agentContext.config.logger.error( - `Error retrieving revocation registry definition '${revocationRegistryDefinitionId}' from ledger`, - { - error, - revocationRegistryDefinitionId: revocationRegistryDefinitionId, - } - ) - - return { - resolutionMetadata: { - error: 'notFound', - message: `unable to resolve revocation registry definition: ${error.message}`, - }, - revocationRegistryDefinitionId, - revocationRegistryDefinitionMetadata: {}, - } - } - } - - public async registerRevocationRegistryDefinition(): Promise { - throw new AriesFrameworkError('Not implemented!') - } - - public async getRevocationStatusList( - agentContext: AgentContext, - revocationRegistryId: string, - timestamp: number - ): Promise { - try { - const indySdkPoolService = agentContext.dependencyManager.resolve(IndySdkPoolService) - const indySdk = agentContext.dependencyManager.resolve(IndySdkSymbol) - - const { did, namespaceIdentifier, schemaSeqNo, credentialDefinitionTag, revocationRegistryTag } = - parseIndyRevocationRegistryId(revocationRegistryId) - const { pool } = await indySdkPoolService.getPoolForDid(agentContext, did) - - agentContext.config.logger.debug( - `Using ledger '${pool.didIndyNamespace}' to retrieve revocation registry deltas with revocation registry definition id '${revocationRegistryId}' until ${timestamp}` - ) - - const legacyRevocationRegistryId = getUnqualifiedRevocationRegistryDefinitionId( - namespaceIdentifier, - schemaSeqNo, - credentialDefinitionTag, - revocationRegistryTag - ) - - // TODO: implement caching for returned deltas - const request = await indySdk.buildGetRevocRegDeltaRequest(null, legacyRevocationRegistryId, 0, timestamp) - - agentContext.config.logger.trace( - `Submitting get revocation registry delta request for revocation registry '${revocationRegistryId}' to ledger` - ) - - const response = await indySdkPoolService.submitReadRequest(pool, request) - agentContext.config.logger.trace( - `Got revocation registry delta unparsed-response '${revocationRegistryId}' from ledger`, - { - response, - } - ) - - const [, revocationRegistryDelta, deltaTimestamp] = await indySdk.parseGetRevocRegDeltaResponse(response) - - agentContext.config.logger.debug( - `Got revocation registry deltas '${revocationRegistryId}' until timestamp ${timestamp} from ledger`, - { - revocationRegistryDelta, - deltaTimestamp, - } - ) - - const { resolutionMetadata, revocationRegistryDefinition, revocationRegistryDefinitionMetadata } = - await this.getRevocationRegistryDefinition(agentContext, revocationRegistryId) - - if ( - !revocationRegistryDefinition || - !revocationRegistryDefinitionMetadata.issuanceType || - typeof revocationRegistryDefinitionMetadata.issuanceType !== 'string' - ) { - return { - resolutionMetadata: { - error: `error resolving revocation registry definition with id ${revocationRegistryId}: ${resolutionMetadata.error} ${resolutionMetadata.message}`, - }, - revocationStatusListMetadata: { - didIndyNamespace: pool.didIndyNamespace, - }, - } - } - - const isIssuanceByDefault = revocationRegistryDefinitionMetadata.issuanceType === 'ISSUANCE_BY_DEFAULT' - - return { - resolutionMetadata: {}, - revocationStatusList: anonCredsRevocationStatusListFromIndySdk( - revocationRegistryId, - revocationRegistryDefinition, - revocationRegistryDelta, - deltaTimestamp, - isIssuanceByDefault - ), - revocationStatusListMetadata: { - didIndyNamespace: pool.didIndyNamespace, - }, - } - } catch (error) { - agentContext.config.logger.error( - `Error retrieving revocation registry delta '${revocationRegistryId}' from ledger, potentially revocation interval ends before revocation registry creation?"`, - { - error, - revocationRegistryId: revocationRegistryId, - } - ) - - return { - resolutionMetadata: { - error: 'notFound', - message: `Error retrieving revocation registry delta '${revocationRegistryId}' from ledger, potentially revocation interval ends before revocation registry creation: ${error.message}`, - }, - revocationStatusListMetadata: {}, - } - } - } - - public async registerRevocationStatusList(): Promise { - throw new AriesFrameworkError('Not implemented!') - } - - private async fetchIndySchemaWithSeqNo(agentContext: AgentContext, pool: IndySdkPool, seqNo: number) { - const indySdkPoolService = agentContext.dependencyManager.resolve(IndySdkPoolService) - const indySdk = agentContext.dependencyManager.resolve(IndySdkSymbol) - - agentContext.config.logger.debug(`Getting transaction with seqNo '${seqNo}' from ledger '${pool.didIndyNamespace}'`) - - const request = await indySdk.buildGetTxnRequest(null, 'DOMAIN', seqNo) - - agentContext.config.logger.trace(`Submitting get transaction request to ledger '${pool.didIndyNamespace}'`) - const response = await indySdkPoolService.submitReadRequest(pool, request) - - const schema = response.result.data as SchemaType - - if (schema.txn.type !== '101') { - agentContext.config.logger.error(`Could not get schema from ledger for seq no ${seqNo}'`) - return {} - } - - return { - schema: { - // txnId is the schema id - schemaId: schema.txnMetadata.txnId, - attr_name: schema.txn.data.data.attr_names, - name: schema.txn.data.data.name, - version: schema.txn.data.data.version, - issuerId: schema.txn.metadata.from, - seqNo, - }, - indyNamespace: pool.didIndyNamespace, - } - } -} - -interface SchemaType { - txnMetadata: { - txnId: string - } - txn: { - metadata: { - from: string - } - data: { - data: { - attr_names: string[] - version: string - name: string - } - } - - type: string - } -} diff --git a/packages/indy-sdk/src/anoncreds/services/IndySdkHolderService.ts b/packages/indy-sdk/src/anoncreds/services/IndySdkHolderService.ts deleted file mode 100644 index c4daf4266b..0000000000 --- a/packages/indy-sdk/src/anoncreds/services/IndySdkHolderService.ts +++ /dev/null @@ -1,464 +0,0 @@ -import type { - AnonCredsHolderService, - AnonCredsProof, - CreateCredentialRequestOptions, - CreateCredentialRequestReturn, - CreateProofOptions, - AnonCredsCredentialInfo, - GetCredentialOptions, - StoreCredentialOptions, - GetCredentialsForProofRequestOptions, - GetCredentialsForProofRequestReturn, - AnonCredsSelectedCredentials, - CreateLinkSecretOptions, - CreateLinkSecretReturn, - GetCredentialsOptions, -} from '@credo-ts/anoncreds' -import type { AgentContext } from '@credo-ts/core' -import type { - CredentialDefs, - IndyRequestedCredentials, - RevStates, - Schemas, - IndyCredential as IndySdkCredential, - IndyProofRequest, -} from 'indy-sdk' - -import { - parseIndyCredentialDefinitionId, - AnonCredsLinkSecretRepository, - generateLegacyProverDidLikeString, - storeLinkSecret, -} from '@credo-ts/anoncreds' -import { AriesFrameworkError, injectable, inject, utils } from '@credo-ts/core' - -import { IndySdkModuleConfig } from '../../IndySdkModuleConfig' -import { IndySdkError, isIndyError } from '../../error' -import { IndySdk, IndySdkSymbol } from '../../types' -import { assertIndySdkWallet } from '../../utils/assertIndySdkWallet' -import { - assertAllUnqualified, - assertUnqualifiedCredentialOffer, - assertUnqualifiedProofRequest, -} from '../utils/assertUnqualified' -import { - anonCredsCredentialRequestMetadataFromIndySdk, - indySdkCredentialDefinitionFromAnonCreds, - indySdkCredentialRequestMetadataFromAnonCreds, - indySdkRevocationRegistryDefinitionFromAnonCreds, - indySdkSchemaFromAnonCreds, -} from '../utils/transform' - -import { IndySdkRevocationService } from './IndySdkRevocationService' - -@injectable() -export class IndySdkHolderService implements AnonCredsHolderService { - private indySdk: IndySdk - private indyRevocationService: IndySdkRevocationService - - public constructor(indyRevocationService: IndySdkRevocationService, @inject(IndySdkSymbol) indySdk: IndySdk) { - this.indySdk = indySdk - this.indyRevocationService = indyRevocationService - } - - public async createLinkSecret( - agentContext: AgentContext, - options: CreateLinkSecretOptions - ): Promise { - assertIndySdkWallet(agentContext.wallet) - - const linkSecretId = options.linkSecretId ?? utils.uuid() - - try { - await this.indySdk.proverCreateMasterSecret(agentContext.wallet.handle, linkSecretId) - - // We don't have the value for the link secret when using the indy-sdk so we can't return it. - return { - linkSecretId, - } - } catch (error) { - agentContext.config.logger.error(`Error creating link secret`, { - error, - linkSecretId, - }) - - throw isIndyError(error) ? new IndySdkError(error) : error - } - } - - public async createProof(agentContext: AgentContext, options: CreateProofOptions): Promise { - const { credentialDefinitions, proofRequest, selectedCredentials, schemas } = options - - assertIndySdkWallet(agentContext.wallet) - - // Make sure all identifiers are unqualified - assertAllUnqualified({ - schemaIds: Object.keys(options.schemas), - credentialDefinitionIds: Object.keys(options.credentialDefinitions), - revocationRegistryIds: Object.keys(options.revocationRegistries), - }) - - const linkSecretRepository = agentContext.dependencyManager.resolve(AnonCredsLinkSecretRepository) - - try { - agentContext.config.logger.debug('Creating Indy Proof') - const indyRevocationStates: RevStates = await this.indyRevocationService.createRevocationState( - agentContext, - proofRequest, - selectedCredentials, - options.revocationRegistries - ) - - // The AnonCredsSchema doesn't contain the seqNo anymore. However, the indy credential definition id - // does contain the seqNo, so we can extract it from the credential definition id. - const seqNoMap: { [schemaId: string]: number } = {} - - // Convert AnonCreds credential definitions to Indy credential definitions - const indyCredentialDefinitions: CredentialDefs = {} - for (const credentialDefinitionId in credentialDefinitions) { - const credentialDefinition = credentialDefinitions[credentialDefinitionId] - indyCredentialDefinitions[credentialDefinitionId] = indySdkCredentialDefinitionFromAnonCreds( - credentialDefinitionId, - credentialDefinition - ) - - // Get the seqNo for the schemas so we can use it when transforming the schemas - const { schemaSeqNo } = parseIndyCredentialDefinitionId(credentialDefinitionId) - seqNoMap[credentialDefinition.schemaId] = Number(schemaSeqNo) - } - - // Convert AnonCreds schemas to Indy schemas - const indySchemas: Schemas = {} - for (const schemaId in schemas) { - const schema = schemas[schemaId] - indySchemas[schemaId] = indySdkSchemaFromAnonCreds(schemaId, schema, seqNoMap[schemaId]) - } - - const linkSecretRecord = await linkSecretRepository.findDefault(agentContext) - if (!linkSecretRecord) { - // No default link secret - throw new AriesFrameworkError( - 'No default link secret found. Indy SDK requires a default link secret to be created before creating a proof.' - ) - } - - const indyProof = await this.indySdk.proverCreateProof( - agentContext.wallet.handle, - proofRequest as IndyProofRequest, - this.parseSelectedCredentials(selectedCredentials), - linkSecretRecord.linkSecretId, - indySchemas, - indyCredentialDefinitions, - indyRevocationStates - ) - - agentContext.config.logger.trace('Created Indy Proof', { - indyProof, - }) - - // FIXME IndyProof if badly typed in indy-sdk. It contains a `requested_predicates` property, which should be `predicates`. - return indyProof as unknown as AnonCredsProof - } catch (error) { - agentContext.config.logger.error(`Error creating Indy Proof`, { - error, - proofRequest, - selectedCredentials, - }) - - throw isIndyError(error) ? new IndySdkError(error) : error - } - } - - public async storeCredential(agentContext: AgentContext, options: StoreCredentialOptions): Promise { - assertIndySdkWallet(agentContext.wallet) - assertAllUnqualified({ - schemaIds: [options.credentialDefinition.schemaId, options.credential.schema_id], - credentialDefinitionIds: [options.credentialDefinitionId, options.credential.cred_def_id], - revocationRegistryIds: [options.revocationRegistry?.id, options.credential.rev_reg_id], - }) - - const indyRevocationRegistryDefinition = options.revocationRegistry - ? indySdkRevocationRegistryDefinitionFromAnonCreds( - options.revocationRegistry.id, - options.revocationRegistry.definition - ) - : null - - try { - return await this.indySdk.proverStoreCredential( - agentContext.wallet.handle, - options.credentialId ?? null, - indySdkCredentialRequestMetadataFromAnonCreds(options.credentialRequestMetadata), - options.credential, - indySdkCredentialDefinitionFromAnonCreds(options.credentialDefinitionId, options.credentialDefinition), - indyRevocationRegistryDefinition - ) - } catch (error) { - agentContext.config.logger.error(`Error storing Indy Credential '${options.credentialId}'`, { - error, - }) - - throw isIndyError(error) ? new IndySdkError(error) : error - } - } - - public async getCredential( - agentContext: AgentContext, - options: GetCredentialOptions - ): Promise { - assertIndySdkWallet(agentContext.wallet) - - try { - const result = await this.indySdk.proverGetCredential(agentContext.wallet.handle, options.credentialId) - - return { - credentialDefinitionId: result.cred_def_id, - attributes: result.attrs, - credentialId: result.referent, - schemaId: result.schema_id, - credentialRevocationId: result.cred_rev_id, - revocationRegistryId: result.rev_reg_id, - methodName: 'indy', - } - } catch (error) { - agentContext.config.logger.error(`Error getting Indy Credential '${options.credentialId}'`, { - error, - }) - - throw isIndyError(error) ? new IndySdkError(error) : error - } - } - - public async getCredentials(agentContext: AgentContext, options: GetCredentialsOptions) { - assertIndySdkWallet(agentContext.wallet) - - // Indy SDK only supports indy credentials - if (options.methodName && options.methodName !== 'indy') { - return [] - } - - assertAllUnqualified({ - credentialDefinitionIds: [options.credentialDefinitionId], - schemaIds: [options.schemaId], - issuerIds: [options.issuerId, options.schemaIssuerId], - }) - - const credentials = await this.indySdk.proverGetCredentials(agentContext.wallet.handle, { - cred_def_id: options.credentialDefinitionId, - schema_id: options.schemaId, - schema_issuer_did: options.schemaIssuerId, - schema_name: options.schemaName, - schema_version: options.schemaVersion, - issuer_did: options.issuerId, - }) - - return credentials.map((credential) => ({ - credentialDefinitionId: credential.cred_def_id, - attributes: credential.attrs, - credentialId: credential.referent, - schemaId: credential.schema_id, - credentialRevocationId: credential.cred_rev_id, - revocationRegistryId: credential.rev_reg_id, - methodName: 'indy', - })) - } - - public async createCredentialRequest( - agentContext: AgentContext, - options: CreateCredentialRequestOptions - ): Promise { - assertIndySdkWallet(agentContext.wallet) - - assertUnqualifiedCredentialOffer(options.credentialOffer) - assertAllUnqualified({ - schemaIds: [options.credentialDefinition.schemaId], - issuerIds: [options.credentialDefinition.issuerId], - }) - - if (!options.useLegacyProverDid) { - throw new AriesFrameworkError('Indy SDK only supports legacy prover did for credential requests') - } - - const linkSecretRepository = agentContext.dependencyManager.resolve(AnonCredsLinkSecretRepository) - - // We just generate a prover did like string, as it's not used for anything and we don't need - // to prove ownership of the did. It's deprecated in AnonCreds v1, but kept for backwards compatibility - const proverDid = generateLegacyProverDidLikeString() - - // If a link secret is specified, use it. Otherwise, attempt to use default link secret - let linkSecretRecord = options.linkSecretId - ? await linkSecretRepository.getByLinkSecretId(agentContext, options.linkSecretId) - : await linkSecretRepository.findDefault(agentContext) - - // No default link secret. Automatically create one if set on module config - if (!linkSecretRecord) { - const moduleConfig = agentContext.dependencyManager.resolve(IndySdkModuleConfig) - if (!moduleConfig.autoCreateLinkSecret) { - throw new AriesFrameworkError( - 'No link secret provided to createCredentialRequest and no default link secret has been found' - ) - } - const { linkSecretId } = await this.createLinkSecret(agentContext, {}) - linkSecretRecord = await storeLinkSecret(agentContext, { linkSecretId, setAsDefault: true }) - } - - try { - const result = await this.indySdk.proverCreateCredentialReq( - agentContext.wallet.handle, - proverDid, - options.credentialOffer, - // NOTE: Is it safe to use the cred_def_id from the offer? I think so. You can't create a request - // for a cred def that is not in the offer - indySdkCredentialDefinitionFromAnonCreds(options.credentialOffer.cred_def_id, options.credentialDefinition), - linkSecretRecord.linkSecretId - ) - - return { - credentialRequest: result[0], - // The type is typed as a Record in the indy-sdk, but the anoncreds package contains the correct type - credentialRequestMetadata: anonCredsCredentialRequestMetadataFromIndySdk(result[1]), - } - } catch (error) { - agentContext.config.logger.error(`Error creating Indy Credential Request`, { - error, - credentialOffer: options.credentialOffer, - }) - - throw isIndyError(error) ? new IndySdkError(error) : error - } - } - - public async deleteCredential(agentContext: AgentContext, credentialId: string): Promise { - assertIndySdkWallet(agentContext.wallet) - - try { - return await this.indySdk.proverDeleteCredential(agentContext.wallet.handle, credentialId) - } catch (error) { - agentContext.config.logger.error(`Error deleting Indy Credential from Wallet`, { - error, - }) - - throw isIndyError(error) ? new IndySdkError(error) : error - } - } - - public async getCredentialsForProofRequest( - agentContext: AgentContext, - options: GetCredentialsForProofRequestOptions - ): Promise { - assertIndySdkWallet(agentContext.wallet) - assertUnqualifiedProofRequest(options.proofRequest) - - try { - // Open indy credential search - const searchHandle = await this.indySdk.proverSearchCredentialsForProofReq( - agentContext.wallet.handle, - options.proofRequest as IndyProofRequest, - options.extraQuery ?? null - ) - - const start = options.start ?? 0 - - try { - // Make sure database cursors start at 'start' (bit ugly, but no way around in indy) - if (start > 0) { - await this.fetchCredentialsForReferent(agentContext, searchHandle, options.attributeReferent, start) - } - - // Fetch the credentials - const credentials = await this.fetchCredentialsForReferent( - agentContext, - searchHandle, - options.attributeReferent, - options.limit - ) - - // TODO: sort the credentials (irrevocable first) - return credentials.map((credential) => ({ - credentialInfo: { - credentialDefinitionId: credential.cred_info.cred_def_id, - credentialId: credential.cred_info.referent, - attributes: credential.cred_info.attrs, - schemaId: credential.cred_info.schema_id, - revocationRegistryId: credential.cred_info.rev_reg_id, - credentialRevocationId: credential.cred_info.cred_rev_id, - methodName: 'indy', - }, - interval: credential.interval, - })) - } finally { - // Always close search - await this.indySdk.proverCloseCredentialsSearchForProofReq(searchHandle) - } - } catch (error) { - if (isIndyError(error)) { - throw new IndySdkError(error) - } - - throw error - } - } - - private async fetchCredentialsForReferent( - agentContext: AgentContext, - searchHandle: number, - referent: string, - limit?: number - ) { - try { - let credentials: IndySdkCredential[] = [] - - // Allow max of 256 per fetch operation - const chunk = limit ? Math.min(256, limit) : 256 - - // Loop while limit not reached (or no limit specified) - while (!limit || credentials.length < limit) { - // Retrieve credentials - const credentialsJson = await this.indySdk.proverFetchCredentialsForProofReq(searchHandle, referent, chunk) - credentials = [...credentials, ...credentialsJson] - - // If the number of credentials returned is less than chunk - // It means we reached the end of the iterator (no more credentials) - if (credentialsJson.length < chunk) { - return credentials - } - } - - return credentials - } catch (error) { - agentContext.config.logger.error(`Error Fetching Indy Credentials For Referent`, { - error, - }) - - throw isIndyError(error) ? new IndySdkError(error) : error - } - } - - /** - * Converts a public api form of {@link AnonCredsSelectedCredentials} interface into a format {@link Indy.IndyRequestedCredentials} that Indy SDK expects. - **/ - private parseSelectedCredentials(selectedCredentials: AnonCredsSelectedCredentials): IndyRequestedCredentials { - const indyRequestedCredentials: IndyRequestedCredentials = { - requested_attributes: {}, - requested_predicates: {}, - self_attested_attributes: {}, - } - - for (const groupName in selectedCredentials.attributes) { - indyRequestedCredentials.requested_attributes[groupName] = { - cred_id: selectedCredentials.attributes[groupName].credentialId, - revealed: selectedCredentials.attributes[groupName].revealed, - timestamp: selectedCredentials.attributes[groupName].timestamp, - } - } - - for (const groupName in selectedCredentials.predicates) { - indyRequestedCredentials.requested_predicates[groupName] = { - cred_id: selectedCredentials.predicates[groupName].credentialId, - timestamp: selectedCredentials.predicates[groupName].timestamp, - } - } - - return indyRequestedCredentials - } -} diff --git a/packages/indy-sdk/src/anoncreds/services/IndySdkIssuerService.ts b/packages/indy-sdk/src/anoncreds/services/IndySdkIssuerService.ts deleted file mode 100644 index 075f89598a..0000000000 --- a/packages/indy-sdk/src/anoncreds/services/IndySdkIssuerService.ts +++ /dev/null @@ -1,173 +0,0 @@ -import type { CreateCredentialDefinitionMetadata } from './IndySdkIssuerServiceMetadata' -import type { - AnonCredsIssuerService, - CreateCredentialDefinitionOptions, - CreateCredentialOfferOptions, - CreateCredentialOptions, - CreateCredentialReturn, - CreateSchemaOptions, - AnonCredsCredentialOffer, - AnonCredsSchema, - CreateCredentialDefinitionReturn, - CreateRevocationRegistryDefinitionReturn, - AnonCredsRevocationStatusList, -} from '@credo-ts/anoncreds' -import type { AgentContext } from '@credo-ts/core' - -import { parseIndyDid, getUnqualifiedSchemaId, generateLegacyProverDidLikeString } from '@credo-ts/anoncreds' -import { injectable, AriesFrameworkError, inject } from '@credo-ts/core' - -import { IndySdkError, isIndyError } from '../../error' -import { IndySdk, IndySdkSymbol } from '../../types' -import { assertIndySdkWallet } from '../../utils/assertIndySdkWallet' -import { - assertUnqualifiedCredentialDefinitionId, - assertUnqualifiedCredentialOffer, - assertUnqualifiedCredentialRequest, - assertUnqualifiedRevocationRegistryId, -} from '../utils/assertUnqualified' -import { indySdkSchemaFromAnonCreds } from '../utils/transform' - -@injectable() -export class IndySdkIssuerService implements AnonCredsIssuerService { - private indySdk: IndySdk - - public constructor(@inject(IndySdkSymbol) indySdk: IndySdk) { - this.indySdk = indySdk - } - - public async createRevocationStatusList(): Promise { - throw new AriesFrameworkError('Method not implemented.') - } - - public async updateRevocationStatusList(): Promise { - throw new AriesFrameworkError('Method not implemented.') - } - - public async createRevocationRegistryDefinition(): Promise { - throw new AriesFrameworkError('Method not implemented.') - } - - public async createSchema(agentContext: AgentContext, options: CreateSchemaOptions): Promise { - // We only support passing qualified did:indy issuer ids in the indy issuer service when creating objects - const { namespaceIdentifier } = parseIndyDid(options.issuerId) - - const { name, version, attrNames, issuerId } = options - assertIndySdkWallet(agentContext.wallet) - - try { - const [, schema] = await this.indySdk.issuerCreateSchema(namespaceIdentifier, name, version, attrNames) - - return { - issuerId, - attrNames: schema.attrNames, - name: schema.name, - version: schema.version, - } - } catch (error) { - throw isIndyError(error) ? new IndySdkError(error) : error - } - } - - public async createCredentialDefinition( - agentContext: AgentContext, - options: CreateCredentialDefinitionOptions, - metadata?: CreateCredentialDefinitionMetadata - ): Promise { - const { tag, supportRevocation, schema, issuerId, schemaId } = options - - // We only support passing qualified did:indy issuer ids in the indy issuer service when creating objects - const { namespaceIdentifier } = parseIndyDid(options.issuerId) - - // parse schema in a way that supports both unqualified and qualified identifiers - const legacySchemaId = getUnqualifiedSchemaId(namespaceIdentifier, schema.name, schema.version) - - if (!metadata) - throw new AriesFrameworkError('The metadata parameter is required when using Indy, but received undefined.') - - try { - assertIndySdkWallet(agentContext.wallet) - const [, credentialDefinition] = await this.indySdk.issuerCreateAndStoreCredentialDef( - agentContext.wallet.handle, - namespaceIdentifier, - indySdkSchemaFromAnonCreds(legacySchemaId, schema, metadata.indyLedgerSchemaSeqNo), - tag, - 'CL', - { - support_revocation: supportRevocation, - } - ) - - return { - credentialDefinition: { - issuerId, - tag: credentialDefinition.tag, - schemaId, - type: 'CL', - value: credentialDefinition.value, - }, - } - } catch (error) { - throw isIndyError(error) ? new IndySdkError(error) : error - } - } - - public async createCredentialOffer( - agentContext: AgentContext, - options: CreateCredentialOfferOptions - ): Promise { - assertIndySdkWallet(agentContext.wallet) - assertUnqualifiedCredentialDefinitionId(options.credentialDefinitionId) - - try { - return await this.indySdk.issuerCreateCredentialOffer(agentContext.wallet.handle, options.credentialDefinitionId) - } catch (error) { - throw isIndyError(error) ? new IndySdkError(error) : error - } - } - - public async createCredential( - agentContext: AgentContext, - options: CreateCredentialOptions - ): Promise { - const { - revocationStatusList, - credentialOffer, - credentialRequest, - credentialValues, - revocationRegistryDefinitionId, - } = options - - assertIndySdkWallet(agentContext.wallet) - assertUnqualifiedCredentialOffer(options.credentialOffer) - assertUnqualifiedCredentialRequest(options.credentialRequest) - if (options.revocationRegistryDefinitionId) { - assertUnqualifiedRevocationRegistryId(options.revocationRegistryDefinitionId) - } - - try { - if (revocationRegistryDefinitionId || revocationStatusList) { - throw new AriesFrameworkError('Revocation not supported yet') - } - - // prover_did is deprecated and thus if not provided we generate something on our side, as it's still required by the indy sdk - const proverDid = credentialRequest.prover_did ?? generateLegacyProverDidLikeString() - - const [credential, credentialRevocationId] = await this.indySdk.issuerCreateCredential( - agentContext.wallet.handle, - credentialOffer, - { ...credentialRequest, prover_did: proverDid }, - credentialValues, - revocationRegistryDefinitionId ?? null, - 0 - ) - - return { - credential, - credentialRevocationId, - } - } catch (error) { - throw isIndyError(error) ? new IndySdkError(error) : error - } - } -} diff --git a/packages/indy-sdk/src/anoncreds/services/IndySdkIssuerServiceMetadata.ts b/packages/indy-sdk/src/anoncreds/services/IndySdkIssuerServiceMetadata.ts deleted file mode 100644 index bb02f17967..0000000000 --- a/packages/indy-sdk/src/anoncreds/services/IndySdkIssuerServiceMetadata.ts +++ /dev/null @@ -1,3 +0,0 @@ -export type CreateCredentialDefinitionMetadata = { - indyLedgerSchemaSeqNo: number -} diff --git a/packages/indy-sdk/src/anoncreds/services/IndySdkRevocationService.ts b/packages/indy-sdk/src/anoncreds/services/IndySdkRevocationService.ts deleted file mode 100644 index 78c851d41f..0000000000 --- a/packages/indy-sdk/src/anoncreds/services/IndySdkRevocationService.ts +++ /dev/null @@ -1,155 +0,0 @@ -import type { - AnonCredsRevocationRegistryDefinition, - AnonCredsRevocationStatusList, - AnonCredsProofRequest, - AnonCredsSelectedCredentials, - AnonCredsCredentialInfo, - AnonCredsNonRevokedInterval, -} from '@credo-ts/anoncreds' -import type { AgentContext } from '@credo-ts/core' -import type { RevStates } from 'indy-sdk' - -import { assertBestPracticeRevocationInterval } from '@credo-ts/anoncreds' -import { AriesFrameworkError, inject, injectable } from '@credo-ts/core' - -import { IndySdkError, isIndyError } from '../../error' -import { IndySdk, IndySdkSymbol } from '../../types' -import { createTailsReader } from '../utils/tails' -import { - indySdkRevocationDeltaFromAnonCreds, - indySdkRevocationRegistryDefinitionFromAnonCreds, -} from '../utils/transform' - -enum RequestReferentType { - Attribute = 'attribute', - Predicate = 'predicate', - SelfAttestedAttribute = 'self-attested-attribute', -} - -/** - * Internal class that handles revocation related logic for the Indy SDK - * - * @internal - */ -@injectable() -export class IndySdkRevocationService { - private indySdk: IndySdk - - public constructor(@inject(IndySdkSymbol) indySdk: IndySdk) { - this.indySdk = indySdk - } - - /** - * Creates the revocation state for the requested credentials in a format that the Indy SDK expects. - */ - public async createRevocationState( - agentContext: AgentContext, - proofRequest: AnonCredsProofRequest, - selectedCredentials: AnonCredsSelectedCredentials, - revocationRegistries: { - [revocationRegistryDefinitionId: string]: { - // Tails is already downloaded - tailsFilePath: string - definition: AnonCredsRevocationRegistryDefinition - revocationStatusLists: { - [timestamp: string]: AnonCredsRevocationStatusList - } - } - } - ): Promise { - try { - agentContext.config.logger.debug(`Creating Revocation State(s) for proof request`, { - proofRequest, - selectedCredentials, - }) - const indyRevocationStates: RevStates = {} - const referentCredentials: Array<{ - type: RequestReferentType - referent: string - credentialInfo: AnonCredsCredentialInfo - referentRevocationInterval: AnonCredsNonRevokedInterval | undefined - timestamp: number | undefined - }> = [] - - //Retrieve information for referents and push to single array - for (const [referent, selectedCredential] of Object.entries(selectedCredentials.attributes ?? {})) { - referentCredentials.push({ - referent, - credentialInfo: selectedCredential.credentialInfo, - type: RequestReferentType.Attribute, - referentRevocationInterval: proofRequest.requested_attributes[referent].non_revoked, - timestamp: selectedCredential.timestamp, - }) - } - for (const [referent, selectedCredential] of Object.entries(selectedCredentials.predicates ?? {})) { - referentCredentials.push({ - referent, - credentialInfo: selectedCredential.credentialInfo, - type: RequestReferentType.Predicate, - referentRevocationInterval: proofRequest.requested_predicates[referent].non_revoked, - timestamp: selectedCredential.timestamp, - }) - } - - for (const { referent, credentialInfo, type, referentRevocationInterval, timestamp } of referentCredentials) { - // Prefer referent-specific revocation interval over global revocation interval - const requestRevocationInterval = referentRevocationInterval ?? proofRequest.non_revoked - const credentialRevocationId = credentialInfo.credentialRevocationId - const revocationRegistryId = credentialInfo.revocationRegistryId - - // If revocation interval is present and the credential is revocable then create revocation state - if (requestRevocationInterval && timestamp && credentialRevocationId && revocationRegistryId) { - agentContext.config.logger.trace( - `Presentation is requesting proof of non revocation for ${type} referent '${referent}', creating revocation state for credential`, - { - requestRevocationInterval, - credentialRevocationId, - revocationRegistryId, - } - ) - - assertBestPracticeRevocationInterval(requestRevocationInterval) - - const { definition, revocationStatusLists, tailsFilePath } = revocationRegistries[revocationRegistryId] - - // Extract revocation status list for the given timestamp - const revocationStatusList = revocationStatusLists[timestamp] - if (!revocationStatusList) { - throw new AriesFrameworkError( - `Revocation status list for revocation registry ${revocationRegistryId} and timestamp ${timestamp} not found in revocation status lists. All revocation status lists must be present.` - ) - } - - const tails = await createTailsReader(agentContext, tailsFilePath) - - const revocationState = await this.indySdk.createRevocationState( - tails, - indySdkRevocationRegistryDefinitionFromAnonCreds(revocationRegistryId, definition), - indySdkRevocationDeltaFromAnonCreds(revocationStatusList), - revocationStatusList.timestamp, - credentialRevocationId - ) - - if (!indyRevocationStates[revocationRegistryId]) { - indyRevocationStates[revocationRegistryId] = {} - } - indyRevocationStates[revocationRegistryId][timestamp] = revocationState - } - } - - agentContext.config.logger.debug(`Created Revocation States for Proof Request`, { - indyRevocationStates, - }) - - return indyRevocationStates - } catch (error) { - agentContext.config.logger.error(`Error creating Indy Revocation State for Proof Request`, { - error, - proofRequest, - selectedCredentials, - }) - - throw isIndyError(error) ? new IndySdkError(error) : error - } - } -} diff --git a/packages/indy-sdk/src/anoncreds/services/IndySdkVerifierService.ts b/packages/indy-sdk/src/anoncreds/services/IndySdkVerifierService.ts deleted file mode 100644 index d30fab4393..0000000000 --- a/packages/indy-sdk/src/anoncreds/services/IndySdkVerifierService.ts +++ /dev/null @@ -1,96 +0,0 @@ -import type { AnonCredsProof, AnonCredsVerifierService, VerifyProofOptions } from '@credo-ts/anoncreds' -import type { AgentContext } from '@credo-ts/core' -import type { CredentialDefs, Schemas, RevocRegDefs, RevRegs, IndyProofRequest, IndyProof } from 'indy-sdk' - -import { parseIndyCredentialDefinitionId } from '@credo-ts/anoncreds' -import { inject, injectable } from '@credo-ts/core' - -import { IndySdkError, isIndyError } from '../../error' -import { IndySdk, IndySdkSymbol } from '../../types' -import { assertAllUnqualified } from '../utils/assertUnqualified' -import { - indySdkCredentialDefinitionFromAnonCreds, - indySdkRevocationRegistryDefinitionFromAnonCreds, - indySdkRevocationRegistryFromAnonCreds, - indySdkSchemaFromAnonCreds, -} from '../utils/transform' - -@injectable() -export class IndySdkVerifierService implements AnonCredsVerifierService { - private indySdk: IndySdk - - public constructor(@inject(IndySdkSymbol) indySdk: IndySdk) { - this.indySdk = indySdk - } - - public async verifyProof(agentContext: AgentContext, options: VerifyProofOptions): Promise { - assertAllUnqualified({ - credentialDefinitionIds: Object.keys(options.credentialDefinitions), - schemaIds: Object.keys(options.schemas), - revocationRegistryIds: Object.keys(options.revocationRegistries), - }) - - try { - // The AnonCredsSchema doesn't contain the seqNo anymore. However, the indy credential definition id - // does contain the seqNo, so we can extract it from the credential definition id. - const seqNoMap: { [schemaId: string]: number } = {} - - // Convert AnonCreds credential definitions to Indy credential definitions - const indyCredentialDefinitions: CredentialDefs = {} - for (const credentialDefinitionId in options.credentialDefinitions) { - const credentialDefinition = options.credentialDefinitions[credentialDefinitionId] - - indyCredentialDefinitions[credentialDefinitionId] = indySdkCredentialDefinitionFromAnonCreds( - credentialDefinitionId, - credentialDefinition - ) - - // Get the seqNo for the schemas so we can use it when transforming the schemas - const { schemaSeqNo } = parseIndyCredentialDefinitionId(credentialDefinitionId) - seqNoMap[credentialDefinition.schemaId] = Number(schemaSeqNo) - } - - // Convert AnonCreds schemas to Indy schemas - const indySchemas: Schemas = {} - for (const schemaId in options.schemas) { - const schema = options.schemas[schemaId] - indySchemas[schemaId] = indySdkSchemaFromAnonCreds(schemaId, schema, seqNoMap[schemaId]) - } - - // Convert AnonCreds revocation definitions to Indy revocation definitions - const indyRevocationDefinitions: RevocRegDefs = {} - const indyRevocationRegistries: RevRegs = {} - - for (const revocationRegistryDefinitionId in options.revocationRegistries) { - const { definition, revocationStatusLists } = options.revocationRegistries[revocationRegistryDefinitionId] - indyRevocationDefinitions[revocationRegistryDefinitionId] = indySdkRevocationRegistryDefinitionFromAnonCreds( - revocationRegistryDefinitionId, - definition - ) - - // Initialize empty object for this revocation registry - indyRevocationRegistries[revocationRegistryDefinitionId] = {} - - // Also transform the revocation lists for the specified timestamps into the revocation registry - // format Indy expects - for (const timestamp in revocationStatusLists) { - const revocationStatusList = revocationStatusLists[timestamp] - indyRevocationRegistries[revocationRegistryDefinitionId][timestamp] = - indySdkRevocationRegistryFromAnonCreds(revocationStatusList) - } - } - - return await this.indySdk.verifierVerifyProof( - options.proofRequest as IndyProofRequest, - // FIXME IndyProof if badly typed in indy-sdk. It contains a `requested_predicates` property, which should be `predicates`. - options.proof as unknown as IndyProof, - indySchemas, - indyCredentialDefinitions, - indyRevocationDefinitions, - indyRevocationRegistries - ) - } catch (error) { - throw isIndyError(error) ? new IndySdkError(error) : error - } - } -} diff --git a/packages/indy-sdk/src/anoncreds/utils/__tests__/assertUnqualified.test.ts b/packages/indy-sdk/src/anoncreds/utils/__tests__/assertUnqualified.test.ts deleted file mode 100644 index ba15e97c24..0000000000 --- a/packages/indy-sdk/src/anoncreds/utils/__tests__/assertUnqualified.test.ts +++ /dev/null @@ -1,152 +0,0 @@ -import type { AnonCredsCredentialOffer, AnonCredsCredentialRequest } from '@credo-ts/anoncreds' - -import { - assertUnqualifiedCredentialDefinitionId, - assertUnqualifiedCredentialOffer, - assertUnqualifiedCredentialRequest, - assertUnqualifiedIssuerId, - assertUnqualifiedProofRequest, - assertUnqualifiedRevocationRegistryId, - assertUnqualifiedSchemaId, -} from '../assertUnqualified' - -describe('assertUnqualified', () => { - describe('assertUnqualifiedCredentialDefinitionId', () => { - test('throws when a non-unqualified credential definition id is passed', () => { - expect(() => - assertUnqualifiedCredentialDefinitionId( - 'did:indy:local:N7baRMcyvPwWc8v85CtZ6e/anoncreds/v0/CLAIM_DEF/100669/SCH Employee ID' - ) - ).toThrow() - }) - - test('does not throw when an unqualified credential definition id is passed', () => { - expect(() => - assertUnqualifiedCredentialDefinitionId('N7baRMcyvPwWc8v85CtZ6e:3:CL:100669:SCH Employee ID') - ).not.toThrow() - }) - }) - - describe('assertUnqualifiedSchemaId', () => { - test('throws when a non-unqualified schema id is passed', () => { - expect(() => - assertUnqualifiedSchemaId('did:indy:local:BQ42WeE24jFHeyGg8x9XAz/anoncreds/v0/SCHEMA/Medical Bill/1.0') - ).toThrowError('Schema id') - }) - - test('does not throw when an unqualified schema id is passed', () => { - expect(() => assertUnqualifiedSchemaId('BQ42WeE24jFHeyGg8x9XAz:2:Medical Bill:1.0')).not.toThrow() - }) - }) - - describe('assertUnqualifiedRevocationRegistryId', () => { - test('throws when a non-unqualified revocation registry id is passed', () => { - expect(() => - assertUnqualifiedRevocationRegistryId( - 'did:indy:local:N7baRMcyvPwWc8v85CtZ6e/anoncreds/v0/REV_REG_DEF/100669/SCH Employee ID/1-1024' - ) - ).toThrowError('Revocation registry id') - }) - - test('does not throw when an unqualified revocation registry id is passed', () => { - expect(() => - assertUnqualifiedRevocationRegistryId( - 'N7baRMcyvPwWc8v85CtZ6e:4:N7baRMcyvPwWc8v85CtZ6e:3:CL:100669:SCH Employee ID:CL_ACCUM:1-1024' - ) - ).not.toThrow() - }) - }) - - describe('assertUnqualifiedIssuerId', () => { - test('throws when a non-unqualified issuer id is passed', () => { - expect(() => assertUnqualifiedIssuerId('did:indy:sovrin:N7baRMcyvPwWc8v85CtZ6e')).toThrowError('Issuer id') - }) - - test('does not throw when an unqualified issuer id is passed', () => { - expect(() => assertUnqualifiedIssuerId('N7baRMcyvPwWc8v85CtZ6e')).not.toThrow() - }) - }) - - describe('assertUnqualifiedCredentialOffer', () => { - test('throws when non-unqualified identifiers are passed', () => { - expect(() => - assertUnqualifiedCredentialOffer({ - cred_def_id: 'did:indy:local:N7baRMcyvPwWc8v85CtZ6e/anoncreds/v0/CLAIM_DEF/100669/SCH Employee ID', - schema_id: 'BQ42WeE24jFHeyGg8x9XAz:2:Medical Bill:1.0', - } as AnonCredsCredentialOffer) - ).toThrowError('Credential definition id') - - expect(() => - assertUnqualifiedCredentialOffer({ - cred_def_id: 'N7baRMcyvPwWc8v85CtZ6e:3:CL:100669:SCH Employee ID', - schema_id: 'did:indy:local:BQ42WeE24jFHeyGg8x9XAz/anoncreds/v0/SCHEMA/Medical Bill/1.0', - } as AnonCredsCredentialOffer) - ).toThrowError('Schema id') - }) - - test('does not throw when only unqualified identifiers are passed', () => { - expect(() => - assertUnqualifiedCredentialOffer({ - cred_def_id: 'N7baRMcyvPwWc8v85CtZ6e:3:CL:100669:SCH Employee ID', - schema_id: 'BQ42WeE24jFHeyGg8x9XAz:2:Medical Bill:1.0', - } as AnonCredsCredentialOffer) - ).not.toThrow() - }) - }) - - describe('assertUnqualifiedCredentialRequest', () => { - test('throws when non-unqualified identifiers are passed', () => { - expect(() => - assertUnqualifiedCredentialRequest({ - cred_def_id: 'did:indy:local:N7baRMcyvPwWc8v85CtZ6e/anoncreds/v0/CLAIM_DEF/100669/SCH Employee ID', - } as AnonCredsCredentialRequest) - ).toThrowError('Credential definition id') - }) - - test('does not throw when only unqualified identifiers are passed', () => { - expect(() => - assertUnqualifiedCredentialRequest({ - cred_def_id: 'N7baRMcyvPwWc8v85CtZ6e:3:CL:100669:SCH Employee ID', - } as AnonCredsCredentialRequest) - ).not.toThrow() - }) - }) - - describe('assertUnqualifiedProofRequest', () => { - test('throws when non-unqualified identifiers are passed', () => { - expect(() => - assertUnqualifiedProofRequest({ - requested_attributes: { - a: { - restrictions: [ - { - cred_def_id: 'did:indy:local:N7baRMcyvPwWc8v85CtZ6e/anoncreds/v0/CLAIM_DEF/100669/SCH Employee ID', - }, - ], - }, - }, - requested_predicates: {}, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - } as any) - ).toThrowError('Credential definition id') - }) - - test('does not throw when only unqualified identifiers are passed', () => { - expect(() => - assertUnqualifiedProofRequest({ - requested_attributes: { - a: { - restrictions: [ - { - schema_id: 'BQ42WeE24jFHeyGg8x9XAz:2:Medical Bill:1.0', - }, - ], - }, - }, - requested_predicates: {}, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - } as any) - ).not.toThrow() - }) - }) -}) diff --git a/packages/indy-sdk/src/anoncreds/utils/__tests__/identifiers.test.ts b/packages/indy-sdk/src/anoncreds/utils/__tests__/identifiers.test.ts deleted file mode 100644 index 546579330b..0000000000 --- a/packages/indy-sdk/src/anoncreds/utils/__tests__/identifiers.test.ts +++ /dev/null @@ -1,79 +0,0 @@ -import { - getDidIndyCredentialDefinitionId, - getDidIndyRevocationRegistryDefinitionId, - getDidIndySchemaId, - indySdkAnonCredsRegistryIdentifierRegex, -} from '../identifiers' - -describe('identifiers', () => { - describe('indySdkAnonCredsRegistryIdentifierRegex', () => { - test('matches against a legacy schema id, credential definition id and revocation registry id', () => { - const did = '7Tqg6BwSSWapxgUDm9KKgg' - const schemaId = 'BQ42WeE24jFHeyGg8x9XAz:2:Medical Bill:1.0' - const credentialDefinitionId = 'N7baRMcyvPwWc8v85CtZ6e:3:CL:100669:SCH Employee ID' - const revocationRegistryId = - 'N7baRMcyvPwWc8v85CtZ6e:4:N7baRMcyvPwWc8v85CtZ6e:3:CL:100669:SCH Employee ID:CL_ACCUM:1-1024' - - const anotherId = 'some:id' - - // unqualified issuerId not in regex on purpose. See note in implementation. - expect(indySdkAnonCredsRegistryIdentifierRegex.test(did)).toEqual(false) - - expect(indySdkAnonCredsRegistryIdentifierRegex.test(schemaId)).toEqual(true) - expect(indySdkAnonCredsRegistryIdentifierRegex.test(credentialDefinitionId)).toEqual(true) - expect(indySdkAnonCredsRegistryIdentifierRegex.test(revocationRegistryId)).toEqual(true) - expect(indySdkAnonCredsRegistryIdentifierRegex.test(anotherId)).toEqual(false) - }) - - test('matches against a did indy did, schema id, credential definition id and revocation registry id', () => { - const did = 'did:indy:local:7Tqg6BwSSWapxgUDm9KKgg' - const schemaId = 'did:indy:local:BQ42WeE24jFHeyGg8x9XAz/anoncreds/v0/SCHEMA/Medical Bill/1.0' - const credentialDefinitionId = - 'did:indy:local:N7baRMcyvPwWc8v85CtZ6e/anoncreds/v0/CLAIM_DEF/100669/SCH Employee ID' - const revocationRegistryId = - 'did:indy:local:N7baRMcyvPwWc8v85CtZ6e/anoncreds/v0/REV_REG_DEF/100669/SCH Employee ID/1-1024' - - const anotherId = 'did:indy:local:N7baRMcyvPwWc8v85CtZ6e/anoncreds/v0/SOME_DEF' - - expect(indySdkAnonCredsRegistryIdentifierRegex.test(did)).toEqual(true) - expect(indySdkAnonCredsRegistryIdentifierRegex.test(schemaId)).toEqual(true) - expect(indySdkAnonCredsRegistryIdentifierRegex.test(credentialDefinitionId)).toEqual(true) - expect(indySdkAnonCredsRegistryIdentifierRegex.test(revocationRegistryId)).toEqual(true) - expect(indySdkAnonCredsRegistryIdentifierRegex.test(anotherId)).toEqual(false) - }) - }) - - test('getDidIndySchemaId returns a valid schema id given a did, name, and version', () => { - const namespace = 'sovrin:test' - const did = '12345' - const name = 'backbench' - const version = '420' - - expect(getDidIndySchemaId(namespace, did, name, version)).toEqual( - 'did:indy:sovrin:test:12345/anoncreds/v0/SCHEMA/backbench/420' - ) - }) - - test('getDidIndyCredentialDefinitionId returns a valid credential definition id given a did, seqNo, and tag', () => { - const namespace = 'sovrin:test' - const did = '12345' - const seqNo = 420 - const tag = 'someTag' - - expect(getDidIndyCredentialDefinitionId(namespace, did, seqNo, tag)).toEqual( - 'did:indy:sovrin:test:12345/anoncreds/v0/CLAIM_DEF/420/someTag' - ) - }) - - test('getDidIndyRevocationRegistryId returns a valid credential definition id given a did, seqNo, and tag', () => { - const namespace = 'sovrin:test' - const did = '12345' - const seqNo = 420 - const credentialDefinitionTag = 'someTag' - const tag = 'anotherTag' - - expect(getDidIndyRevocationRegistryDefinitionId(namespace, did, seqNo, credentialDefinitionTag, tag)).toEqual( - 'did:indy:sovrin:test:12345/anoncreds/v0/REV_REG_DEF/420/someTag/anotherTag' - ) - }) -}) diff --git a/packages/indy-sdk/src/anoncreds/utils/__tests__/transform.test.ts b/packages/indy-sdk/src/anoncreds/utils/__tests__/transform.test.ts deleted file mode 100644 index f94060d8fd..0000000000 --- a/packages/indy-sdk/src/anoncreds/utils/__tests__/transform.test.ts +++ /dev/null @@ -1,114 +0,0 @@ -import type { AnonCredsCredentialDefinition, AnonCredsSchema } from '../../../../../anoncreds/src' -import type { CredDef, Schema } from 'indy-sdk' - -import { - anonCredsCredentialDefinitionFromIndySdk, - anonCredsSchemaFromIndySdk, - indySdkCredentialDefinitionFromAnonCreds, - indySdkSchemaFromAnonCreds, -} from '../transform' - -describe('transform', () => { - it('anonCredsSchemaFromIndySdk should return a valid anoncreds schema', () => { - const schema: Schema = { - attrNames: ['hello'], - id: 'TL1EaPFCZ8Si5aUrqScBDt:2:Example Schema:1.0.0', - name: 'Example Schema', - seqNo: 150, - ver: '1.0', - version: '1.0.0', - } - - expect(anonCredsSchemaFromIndySdk(schema)).toEqual({ - attrNames: ['hello'], - issuerId: 'TL1EaPFCZ8Si5aUrqScBDt', - name: 'Example Schema', - version: '1.0.0', - }) - }) - - it('indySdkSchemaFromAnonCreds should return a valid indy sdk schema', () => { - const schemaId = 'TL1EaPFCZ8Si5aUrqScBDt:2:Example Schema:1.0.0' - const schema: AnonCredsSchema = { - attrNames: ['hello'], - issuerId: 'TL1EaPFCZ8Si5aUrqScBDt', - name: 'Example Schema', - version: '1.0.0', - } - - expect(indySdkSchemaFromAnonCreds(schemaId, schema, 150)).toEqual({ - attrNames: ['hello'], - id: 'TL1EaPFCZ8Si5aUrqScBDt:2:Example Schema:1.0.0', - name: 'Example Schema', - seqNo: 150, - ver: '1.0', - version: '1.0.0', - }) - }) - - it('anonCredsCredentialDefinitionFromIndySdk should return a valid anoncreds credential definition', () => { - const credDef: CredDef = { - id: 'TL1EaPFCZ8Si5aUrqScBDt:3:CL:420:someTag', - schemaId: '8910:2:Example Schema:1.0.0', - tag: 'someTag', - type: 'CL', - value: { - primary: { - something: 'string', - }, - }, - ver: '1.0', - } - - expect(anonCredsCredentialDefinitionFromIndySdk(credDef)).toEqual({ - issuerId: 'TL1EaPFCZ8Si5aUrqScBDt', - schemaId: '8910:2:Example Schema:1.0.0', - tag: 'someTag', - type: 'CL', - value: { - primary: { - something: 'string', - }, - }, - }) - }) - - it('indySdkCredentialDefinitionFromAnonCreds should return a valid indy sdk credential definition', () => { - const credentialDefinitionId = 'TL1EaPFCZ8Si5aUrqScBDt:3:CL:420:someTag' - const credentialDefinition: AnonCredsCredentialDefinition = { - issuerId: 'TL1EaPFCZ8Si5aUrqScBDt', - schemaId: '8910:2:Example Schema:1.0.0', - tag: 'someTag', - type: 'CL', - value: { - primary: { - something: 'string', - }, - }, - } - - expect(indySdkCredentialDefinitionFromAnonCreds(credentialDefinitionId, credentialDefinition)).toEqual({ - id: 'TL1EaPFCZ8Si5aUrqScBDt:3:CL:420:someTag', - schemaId: '8910:2:Example Schema:1.0.0', - tag: 'someTag', - type: 'CL', - value: { - primary: { - something: 'string', - }, - }, - ver: '1.0', - }) - }) - - // TODO: add tests for these models once finalized in the anoncreds spec - test.todo( - 'anonCredsRevocationRegistryDefinitionFromIndySdk should return a valid anoncreds revocation registry definition' - ) - test.todo( - 'indySdkRevocationRegistryDefinitionFromAnonCreds should return a valid indy sdk revocation registry definition' - ) - test.todo('anonCredsRevocationStatusListFromIndySdk should return a valid anoncreds revocation list') - test.todo('indySdkRevocationRegistryFromAnonCreds should return a valid indy sdk revocation registry') - test.todo('indySdkRevocationDeltaFromAnonCreds should return a valid indy sdk revocation delta') -}) diff --git a/packages/indy-sdk/src/anoncreds/utils/assertUnqualified.ts b/packages/indy-sdk/src/anoncreds/utils/assertUnqualified.ts deleted file mode 100644 index 42463ca455..0000000000 --- a/packages/indy-sdk/src/anoncreds/utils/assertUnqualified.ts +++ /dev/null @@ -1,129 +0,0 @@ -import type { AnonCredsCredentialOffer, AnonCredsCredentialRequest, AnonCredsProofRequest } from '@credo-ts/anoncreds' - -import { - unqualifiedRevocationRegistryIdRegex, - unqualifiedCredentialDefinitionIdRegex, - unqualifiedIndyDidRegex, - unqualifiedSchemaIdRegex, -} from '@credo-ts/anoncreds' -import { AriesFrameworkError } from '@credo-ts/core' - -/** - * Assert that a credential definition id is unqualified. - */ -export function assertUnqualifiedCredentialDefinitionId(credentialDefinitionId: string) { - if (!unqualifiedCredentialDefinitionIdRegex.test(credentialDefinitionId)) { - throw new AriesFrameworkError( - `Credential definition id '${credentialDefinitionId}' is not an unqualified credential definition id. Indy SDK only supports unqualified identifiers.` - ) - } -} - -/** - * Assert that a schema id is unqualified. - */ -export function assertUnqualifiedSchemaId(schemaId: string) { - if (!unqualifiedSchemaIdRegex.test(schemaId)) { - throw new AriesFrameworkError( - `Schema id '${schemaId}' is not an unqualified schema id. Indy SDK only supports unqualified identifiers.` - ) - } -} - -/** - * Assert that a revocation registry id is unqualified. - */ -export function assertUnqualifiedRevocationRegistryId(revocationRegistryId: string) { - if (!unqualifiedRevocationRegistryIdRegex.test(revocationRegistryId)) { - throw new AriesFrameworkError( - `Revocation registry id '${revocationRegistryId}' is not an unqualified revocation registry id. Indy SDK only supports unqualified identifiers.` - ) - } -} - -/** - * Assert that an issuer id is unqualified. - */ -export function assertUnqualifiedIssuerId(issuerId: string) { - if (!unqualifiedIndyDidRegex.test(issuerId)) { - throw new AriesFrameworkError( - `Issuer id '${issuerId}' is not an unqualified issuer id. Indy SDK only supports unqualified identifiers.` - ) - } -} - -/** - * Assert that a credential offer only contains unqualified identifiers. - */ -export function assertUnqualifiedCredentialOffer(credentialOffer: AnonCredsCredentialOffer) { - assertUnqualifiedCredentialDefinitionId(credentialOffer.cred_def_id) - assertUnqualifiedSchemaId(credentialOffer.schema_id) -} - -/** - * Assert that a credential request only contains unqualified identifiers. - */ -export function assertUnqualifiedCredentialRequest(credentialRequest: AnonCredsCredentialRequest) { - assertUnqualifiedCredentialDefinitionId(credentialRequest.cred_def_id) -} - -/** - * Assert that a proof request only contains unqualified identifiers. - */ -export function assertUnqualifiedProofRequest(proofRequest: AnonCredsProofRequest) { - const allRequested = [ - ...Object.values(proofRequest.requested_attributes), - ...Object.values(proofRequest.requested_predicates), - ] - - for (const requested of allRequested) { - for (const restriction of requested.restrictions ?? []) { - assertAllUnqualified({ - credentialDefinitionIds: [restriction.cred_def_id], - schemaIds: [restriction.schema_id], - revocationRegistryIds: [restriction.rev_reg_id], - issuerIds: [restriction.issuer_did, restriction.schema_issuer_did], - }) - } - } -} - -export function assertAllUnqualified({ - schemaIds = [], - credentialDefinitionIds = [], - revocationRegistryIds = [], - issuerIds = [], -}: { - schemaIds?: Array - credentialDefinitionIds?: Array - revocationRegistryIds?: Array - issuerIds?: Array -}) { - for (const schemaId of schemaIds) { - // We don't validate undefined values - if (!schemaId) continue - - assertUnqualifiedSchemaId(schemaId) - } - - for (const credentialDefinitionId of credentialDefinitionIds) { - // We don't validate undefined values - if (!credentialDefinitionId) continue - - assertUnqualifiedCredentialDefinitionId(credentialDefinitionId) - } - - for (const revocationRegistryId of revocationRegistryIds) { - // We don't validate undefined values - if (!revocationRegistryId) continue - - assertUnqualifiedRevocationRegistryId(revocationRegistryId) - } - - for (const issuerId of issuerIds) { - // We don't validate undefined values - if (!issuerId) continue - - assertUnqualifiedIssuerId(issuerId) - } -} diff --git a/packages/indy-sdk/src/anoncreds/utils/identifiers.ts b/packages/indy-sdk/src/anoncreds/utils/identifiers.ts deleted file mode 100644 index 0946ac67f0..0000000000 --- a/packages/indy-sdk/src/anoncreds/utils/identifiers.ts +++ /dev/null @@ -1,63 +0,0 @@ -/** - * NOTE: this file is available in both the indy-sdk and indy-vdr packages. If making changes to - * this file, make sure to update both files if applicable. - */ - -import { - unqualifiedSchemaIdRegex, - unqualifiedCredentialDefinitionIdRegex, - unqualifiedRevocationRegistryIdRegex, - didIndyCredentialDefinitionIdRegex, - didIndyRevocationRegistryIdRegex, - didIndySchemaIdRegex, - didIndyRegex, -} from '@credo-ts/anoncreds' - -// combines both legacy and did:indy anoncreds identifiers and also the issuer id -const indySdkAnonCredsRegexes = [ - // NOTE: we only include the qualified issuer id here, as we don't support registering objects based on legacy issuer ids. - // you can still resolve using legacy issuer ids, but you need to use the full did:indy identifier when registering. - // As we find a matching anoncreds registry based on the issuerId only when creating an object, this will make sure - // it will throw an no registry found for identifier error. - // issuer id - didIndyRegex, - - // schema - didIndySchemaIdRegex, - unqualifiedSchemaIdRegex, - - // credential definition - didIndyCredentialDefinitionIdRegex, - unqualifiedCredentialDefinitionIdRegex, - - // revocation registry - unqualifiedRevocationRegistryIdRegex, - didIndyRevocationRegistryIdRegex, -] - -export const indySdkAnonCredsRegistryIdentifierRegex = new RegExp( - indySdkAnonCredsRegexes.map((r) => r.source).join('|') -) - -export function getDidIndySchemaId(namespace: string, unqualifiedDid: string, name: string, version: string) { - return `did:indy:${namespace}:${unqualifiedDid}/anoncreds/v0/SCHEMA/${name}/${version}` -} - -export function getDidIndyCredentialDefinitionId( - namespace: string, - unqualifiedDid: string, - schemaSeqNo: string | number, - tag: string -) { - return `did:indy:${namespace}:${unqualifiedDid}/anoncreds/v0/CLAIM_DEF/${schemaSeqNo}/${tag}` -} - -export function getDidIndyRevocationRegistryDefinitionId( - namespace: string, - unqualifiedDid: string, - schemaSeqNo: string | number, - credentialDefinitionTag: string, - revocationRegistryTag: string -) { - return `did:indy:${namespace}:${unqualifiedDid}/anoncreds/v0/REV_REG_DEF/${schemaSeqNo}/${credentialDefinitionTag}/${revocationRegistryTag}` -} diff --git a/packages/indy-sdk/src/anoncreds/utils/tails.ts b/packages/indy-sdk/src/anoncreds/utils/tails.ts deleted file mode 100644 index db1e4f8505..0000000000 --- a/packages/indy-sdk/src/anoncreds/utils/tails.ts +++ /dev/null @@ -1,45 +0,0 @@ -import type { IndySdk } from '../../types' -import type { AgentContext, FileSystem } from '@credo-ts/core' - -import { AriesFrameworkError, getDirFromFilePath, InjectionSymbols } from '@credo-ts/core' - -import { IndySdkError, isIndyError } from '../../error' -import { IndySdkSymbol } from '../../types' - -/** - * Get a handler for the blob storage tails file reader. - * - * @param agentContext The agent context - * @param tailsFilePath The path of the tails file - * @returns The blob storage reader handle - */ -export async function createTailsReader(agentContext: AgentContext, tailsFilePath: string) { - const fileSystem = agentContext.dependencyManager.resolve(InjectionSymbols.FileSystem) - const indySdk = agentContext.dependencyManager.resolve(IndySdkSymbol) - - try { - agentContext.config.logger.debug(`Opening tails reader at path ${tailsFilePath}`) - const tailsFileExists = await fileSystem.exists(tailsFilePath) - - // Extract directory from path (should also work with windows paths) - const dirname = getDirFromFilePath(tailsFilePath) - - if (!tailsFileExists) { - throw new AriesFrameworkError(`Tails file does not exist at path ${tailsFilePath}`) - } - - const tailsReaderConfig = { - base_dir: dirname, - } - - const tailsReader = await indySdk.openBlobStorageReader('default', tailsReaderConfig) - agentContext.config.logger.debug(`Opened tails reader at path ${tailsFilePath}`) - return tailsReader - } catch (error) { - if (isIndyError(error)) { - throw new IndySdkError(error) - } - - throw error - } -} diff --git a/packages/indy-sdk/src/anoncreds/utils/transform.ts b/packages/indy-sdk/src/anoncreds/utils/transform.ts deleted file mode 100644 index 531730d14f..0000000000 --- a/packages/indy-sdk/src/anoncreds/utils/transform.ts +++ /dev/null @@ -1,161 +0,0 @@ -import type { - AnonCredsCredentialDefinition, - AnonCredsRevocationStatusList, - AnonCredsRevocationRegistryDefinition, - AnonCredsSchema, - AnonCredsCredentialRequestMetadata, - AnonCredsLinkSecretBlindingData, -} from '@credo-ts/anoncreds' -import type { CredDef, CredReqMetadata, RevocReg, RevocRegDef, RevocRegDelta, Schema } from 'indy-sdk' - -import { parseIndyCredentialDefinitionId, parseIndySchemaId } from '@credo-ts/anoncreds' - -export function anonCredsSchemaFromIndySdk(schema: Schema): AnonCredsSchema { - const { did } = parseIndySchemaId(schema.id) - return { - issuerId: did, - name: schema.name, - version: schema.version, - attrNames: schema.attrNames, - } -} - -export function indySdkSchemaFromAnonCreds(schemaId: string, schema: AnonCredsSchema, indyLedgerSeqNo: number): Schema { - return { - id: schemaId, - attrNames: schema.attrNames, - name: schema.name, - version: schema.version, - ver: '1.0', - seqNo: indyLedgerSeqNo, - } -} - -export function anonCredsCredentialDefinitionFromIndySdk(credentialDefinition: CredDef): AnonCredsCredentialDefinition { - const { did } = parseIndyCredentialDefinitionId(credentialDefinition.id) - - return { - issuerId: did, - schemaId: credentialDefinition.schemaId, - tag: credentialDefinition.tag, - type: 'CL', - value: credentialDefinition.value, - } -} - -export function indySdkCredentialDefinitionFromAnonCreds( - credentialDefinitionId: string, - credentialDefinition: AnonCredsCredentialDefinition -): CredDef { - return { - id: credentialDefinitionId, - schemaId: credentialDefinition.schemaId, - tag: credentialDefinition.tag, - type: credentialDefinition.type, - value: credentialDefinition.value, - ver: '1.0', - } -} - -export function indySdkRevocationRegistryDefinitionFromAnonCreds( - revocationRegistryDefinitionId: string, - revocationRegistryDefinition: AnonCredsRevocationRegistryDefinition -): RevocRegDef { - return { - id: revocationRegistryDefinitionId, - credDefId: revocationRegistryDefinition.credDefId, - revocDefType: revocationRegistryDefinition.revocDefType, - tag: revocationRegistryDefinition.tag, - value: { - issuanceType: 'ISSUANCE_BY_DEFAULT', // NOTE: we always use ISSUANCE_BY_DEFAULT when passing to the indy-sdk. It doesn't matter, as we have the revocation List with the full state - maxCredNum: revocationRegistryDefinition.value.maxCredNum, - publicKeys: revocationRegistryDefinition.value.publicKeys, - tailsHash: revocationRegistryDefinition.value.tailsHash, - tailsLocation: revocationRegistryDefinition.value.tailsLocation, - }, - ver: '1.0', - } -} - -export function anonCredsRevocationStatusListFromIndySdk( - revocationRegistryDefinitionId: string, - revocationRegistryDefinition: AnonCredsRevocationRegistryDefinition, - delta: RevocRegDelta, - timestamp: number, - isIssuanceByDefault: boolean -): AnonCredsRevocationStatusList { - // 0 means unrevoked, 1 means revoked - const defaultState = isIssuanceByDefault ? 0 : 1 - - // Fill with default value - const revocationList = new Array(revocationRegistryDefinition.value.maxCredNum).fill(defaultState) - - // Set all `issuer` indexes to 0 (not revoked) - for (const issued of delta.value.issued ?? []) { - revocationList[issued] = 0 - } - - // Set all `revoked` indexes to 1 (revoked) - for (const revoked of delta.value.revoked ?? []) { - revocationList[revoked] = 1 - } - - return { - issuerId: revocationRegistryDefinition.issuerId, - currentAccumulator: delta.value.accum, - revRegDefId: revocationRegistryDefinitionId, - revocationList, - timestamp, - } -} - -export function indySdkRevocationRegistryFromAnonCreds(revocationStatusList: AnonCredsRevocationStatusList): RevocReg { - return { - ver: '1.0', - value: { - accum: revocationStatusList.currentAccumulator, - }, - } -} - -export function indySdkRevocationDeltaFromAnonCreds( - revocationStatusList: AnonCredsRevocationStatusList -): RevocRegDelta { - // Get all indices from the revocationStatusList that are revoked (so have value '1') - const revokedIndices = revocationStatusList.revocationList.reduce( - (revoked, current, index) => (current === 1 ? [...revoked, index] : revoked), - [] - ) - - return { - value: { - accum: revocationStatusList.currentAccumulator, - issued: [], - revoked: revokedIndices, - // NOTE: this must be a valid accumulator but it's not actually used. So we set it to the - // currentAccumulator as that should always be a valid accumulator. - prevAccum: revocationStatusList.currentAccumulator, - }, - ver: '1.0', - } -} - -export function anonCredsCredentialRequestMetadataFromIndySdk( - credentialRequestMetadata: CredReqMetadata -): AnonCredsCredentialRequestMetadata { - return { - link_secret_blinding_data: credentialRequestMetadata.master_secret_blinding_data as AnonCredsLinkSecretBlindingData, - link_secret_name: credentialRequestMetadata.master_secret_name as string, - nonce: credentialRequestMetadata.nonce as string, - } -} - -export function indySdkCredentialRequestMetadataFromAnonCreds( - credentialRequestMetadata: AnonCredsCredentialRequestMetadata -): CredReqMetadata { - return { - master_secret_blinding_data: credentialRequestMetadata.link_secret_blinding_data, - master_secret_name: credentialRequestMetadata.link_secret_name, - nonce: credentialRequestMetadata.nonce, - } -} diff --git a/packages/indy-sdk/src/dids/IndySdkIndyDidRegistrar.ts b/packages/indy-sdk/src/dids/IndySdkIndyDidRegistrar.ts deleted file mode 100644 index dc4d66552a..0000000000 --- a/packages/indy-sdk/src/dids/IndySdkIndyDidRegistrar.ts +++ /dev/null @@ -1,328 +0,0 @@ -import type { IndyEndpointAttrib } from './didSovUtil' -import type { IndySdkPool } from '../ledger' -import type { IndySdk } from '../types' -import type { - AgentContext, - Buffer, - DidCreateOptions, - DidCreateResult, - DidDeactivateResult, - DidRegistrar, - DidUpdateResult, -} from '@credo-ts/core' -import type { NymRole } from 'indy-sdk' - -import { parseIndyDid } from '@credo-ts/anoncreds' -import { DidDocumentRole, DidRecord, DidRepository, KeyType, Key } from '@credo-ts/core' - -import { IndySdkError } from '../error' -import { isIndyError } from '../error/indyError' -import { IndySdkPoolService } from '../ledger' -import { IndySdkSymbol } from '../types' -import { assertIndySdkWallet } from '../utils/assertIndySdkWallet' -import { isLegacySelfCertifiedDid, legacyIndyDidFromPublicKeyBase58 } from '../utils/did' - -import { createKeyAgreementKey, indyDidDocumentFromDid, verificationKeyForIndyDid } from './didIndyUtil' -import { addServicesFromEndpointsAttrib } from './didSovUtil' - -export class IndySdkIndyDidRegistrar implements DidRegistrar { - public readonly supportedMethods = ['indy'] - - public async create(agentContext: AgentContext, options: IndySdkIndyDidCreateOptions): Promise { - const indySdkPoolService = agentContext.dependencyManager.resolve(IndySdkPoolService) - const didRepository = agentContext.dependencyManager.resolve(DidRepository) - - const { alias, role, submitterDid, endpoints } = options.options - let did = options.did - let namespaceIdentifier: string - let verificationKey: Key - const privateKey = options.secret?.privateKey - - if (did && privateKey) { - return { - didDocumentMetadata: {}, - didRegistrationMetadata: {}, - didState: { - state: 'failed', - reason: `Only one of 'privateKey' or 'did' must be provided`, - }, - } - } - - try { - assertIndySdkWallet(agentContext.wallet) - - // Parse submitterDid and extract namespace based on the submitter did - const { namespace: submitterNamespace, namespaceIdentifier: submitterNamespaceIdentifier } = - parseIndyDid(submitterDid) - const submitterSigningKey = await verificationKeyForIndyDid(agentContext, submitterDid) - - // Only supports version 1 did identifier (which is same as did:sov) - if (did) { - if (!options.options.verkey) { - return { - didDocumentMetadata: {}, - didRegistrationMetadata: {}, - didState: { - state: 'failed', - reason: 'If a did is defined, a matching verkey must be provided', - }, - } - } - - const { namespace, namespaceIdentifier: _namespaceIdentifier } = parseIndyDid(did) - namespaceIdentifier = _namespaceIdentifier - - verificationKey = Key.fromPublicKeyBase58(options.options.verkey, KeyType.Ed25519) - - if (!isLegacySelfCertifiedDid(namespaceIdentifier, options.options.verkey)) { - return { - didDocumentMetadata: {}, - didRegistrationMetadata: {}, - didState: { - state: 'failed', - reason: `Did must be first 16 bytes of the the verkey base58 encoded.`, - }, - } - } - - if (submitterNamespace !== namespace) { - return { - didDocumentMetadata: {}, - didRegistrationMetadata: {}, - didState: { - state: 'failed', - reason: `The submitter did uses namespace ${submitterNamespace} and the did to register uses namespace ${namespace}. Namespaces must match.`, - }, - } - } - } else { - // Create a new key and calculate did according to the rules for indy did method - verificationKey = await agentContext.wallet.createKey({ privateKey, keyType: KeyType.Ed25519 }) - namespaceIdentifier = legacyIndyDidFromPublicKeyBase58(verificationKey.publicKeyBase58) - did = `did:indy:${submitterNamespace}:${namespaceIdentifier}` - } - - const pool = indySdkPoolService.getPoolForNamespace(submitterNamespace) - await this.registerPublicDid( - agentContext, - pool, - submitterNamespaceIdentifier, - submitterSigningKey, - namespaceIdentifier, - verificationKey, - alias, - role - ) - - // Create did document - const didDocumentBuilder = indyDidDocumentFromDid(did, verificationKey.publicKeyBase58) - - // Add services if endpoints object was passed. - if (endpoints) { - const keyAgreementId = `${did}#key-agreement-1` - - await this.setEndpointsForDid(agentContext, pool, namespaceIdentifier, verificationKey, endpoints) - - didDocumentBuilder - .addContext('https://w3id.org/security/suites/x25519-2019/v1') - .addVerificationMethod({ - controller: did, - id: keyAgreementId, - publicKeyBase58: createKeyAgreementKey(verificationKey.publicKeyBase58), - type: 'X25519KeyAgreementKey2019', - }) - .addKeyAgreement(keyAgreementId) - - // Process endpoint attrib following the same rules as for did:sov - addServicesFromEndpointsAttrib(didDocumentBuilder, did, endpoints, keyAgreementId) - } - - // Build did document. - const didDocument = didDocumentBuilder.build() - - // Save the did so we know we created it and can issue with it - const didRecord = new DidRecord({ - did, - role: DidDocumentRole.Created, - tags: { - recipientKeyFingerprints: didDocument.recipientKeys.map((key: Key) => key.fingerprint), - }, - }) - await didRepository.save(agentContext, didRecord) - - return { - didDocumentMetadata: {}, - didRegistrationMetadata: {}, - didState: { - state: 'finished', - did, - didDocument, - secret: { - // FIXME: the uni-registrar creates the seed in the registrar method - // if it doesn't exist so the seed can always be returned. Currently - // we can only return it if the seed was passed in by the user. Once - // we have a secure method for generating seeds we should use the same - // approach - privateKey: options.secret?.privateKey, - }, - }, - } - } catch (error) { - return { - didDocumentMetadata: {}, - didRegistrationMetadata: {}, - didState: { - state: 'failed', - reason: `unknownError: ${error.message}`, - }, - } - } - } - - public async update(): Promise { - return { - didDocumentMetadata: {}, - didRegistrationMetadata: {}, - didState: { - state: 'failed', - reason: `notImplemented: updating did:indy not implemented yet`, - }, - } - } - - public async deactivate(): Promise { - return { - didDocumentMetadata: {}, - didRegistrationMetadata: {}, - didState: { - state: 'failed', - reason: `notImplemented: deactivating did:indy not implemented yet`, - }, - } - } - - private async registerPublicDid( - agentContext: AgentContext, - pool: IndySdkPool, - unqualifiedSubmitterDid: string, - submitterSigningKey: Key, - unqualifiedDid: string, - signingKey: Key, - alias: string, - role?: NymRole - ) { - const indySdk = agentContext.dependencyManager.resolve(IndySdkSymbol) - const indySdkPoolService = agentContext.dependencyManager.resolve(IndySdkPoolService) - - try { - agentContext.config.logger.debug(`Register public did '${unqualifiedDid}' on ledger '${pool.didIndyNamespace}'`) - - const request = await indySdk.buildNymRequest( - unqualifiedSubmitterDid, - unqualifiedDid, - signingKey.publicKeyBase58, - alias, - role || null - ) - - const response = await indySdkPoolService.submitWriteRequest(agentContext, pool, request, submitterSigningKey) - - agentContext.config.logger.debug( - `Registered public did '${unqualifiedDid}' on ledger '${pool.didIndyNamespace}'`, - { - response, - } - ) - } catch (error) { - agentContext.config.logger.error( - `Error registering public did '${unqualifiedDid}' on ledger '${pool.didIndyNamespace}'`, - { - error, - unqualifiedSubmitterDid, - unqualifiedDid, - verkey: signingKey.publicKeyBase58, - alias, - role, - pool: pool.didIndyNamespace, - } - ) - - throw error - } - } - - private async setEndpointsForDid( - agentContext: AgentContext, - pool: IndySdkPool, - unqualifiedDid: string, - signingKey: Key, - endpoints: IndyEndpointAttrib - ): Promise { - const indySdk = agentContext.dependencyManager.resolve(IndySdkSymbol) - const indySdkPoolService = agentContext.dependencyManager.resolve(IndySdkPoolService) - - try { - agentContext.config.logger.debug( - `Set endpoints for did '${unqualifiedDid}' on ledger '${pool.didIndyNamespace}'`, - endpoints - ) - - const request = await indySdk.buildAttribRequest( - unqualifiedDid, - unqualifiedDid, - null, - { endpoint: endpoints }, - null - ) - - const response = await indySdkPoolService.submitWriteRequest(agentContext, pool, request, signingKey) - agentContext.config.logger.debug( - `Successfully set endpoints for did '${unqualifiedDid}' on ledger '${pool.didIndyNamespace}'`, - { - response, - endpoints, - } - ) - } catch (error) { - agentContext.config.logger.error( - `Error setting endpoints for did '${unqualifiedDid}' on ledger '${pool.didIndyNamespace}'`, - { - error, - unqualifiedDid, - endpoints, - } - ) - - throw isIndyError(error) ? new IndySdkError(error) : error - } - } -} - -interface IndySdkIndyDidCreateOptionsBase extends DidCreateOptions { - // The indy sdk can only publish a very limited did document (what is mostly known as a legacy did:sov did) and thus we require everything - // needed to construct the did document to be passed through the options object. - didDocument?: never - options: { - alias: string - role?: NymRole - verkey?: string - endpoints?: IndyEndpointAttrib - submitterDid: string - } - secret?: { - privateKey?: Buffer - } -} - -interface IndySdkIndyDidCreateOptionsWithDid extends IndySdkIndyDidCreateOptionsBase { - method?: never - did: string -} - -interface IndySdkIndyDidCreateOptionsWithoutDid extends IndySdkIndyDidCreateOptionsBase { - method: 'indy' - did?: never -} - -export type IndySdkIndyDidCreateOptions = IndySdkIndyDidCreateOptionsWithDid | IndySdkIndyDidCreateOptionsWithoutDid diff --git a/packages/indy-sdk/src/dids/IndySdkIndyDidResolver.ts b/packages/indy-sdk/src/dids/IndySdkIndyDidResolver.ts deleted file mode 100644 index 540ba3e0fb..0000000000 --- a/packages/indy-sdk/src/dids/IndySdkIndyDidResolver.ts +++ /dev/null @@ -1,126 +0,0 @@ -import type { IndyEndpointAttrib } from './didSovUtil' -import type { IndySdkPool } from '../ledger' -import type { IndySdk } from '../types' -import type { DidResolutionResult, DidResolver, AgentContext } from '@credo-ts/core' - -import { parseIndyDid } from '@credo-ts/anoncreds' - -import { isIndyError, IndySdkError } from '../error' -import { IndySdkPoolService } from '../ledger/IndySdkPoolService' -import { IndySdkSymbol } from '../types' -import { getFullVerkey } from '../utils/did' - -import { createKeyAgreementKey, indyDidDocumentFromDid } from './didIndyUtil' -import { addServicesFromEndpointsAttrib } from './didSovUtil' - -export class IndySdkIndyDidResolver implements DidResolver { - public readonly supportedMethods = ['indy'] - - public readonly allowsCaching = true - - public async resolve(agentContext: AgentContext, did: string): Promise { - const didDocumentMetadata = {} - - try { - const { namespaceIdentifier, namespace } = parseIndyDid(did) - - const poolService = agentContext.dependencyManager.resolve(IndySdkPoolService) - const pool = poolService.getPoolForNamespace(namespace) - - const nym = await this.getPublicDid(agentContext, pool, namespaceIdentifier) - const endpoints = await this.getEndpointsForDid(agentContext, pool, namespaceIdentifier) - - // For modern did:indy DIDs, we assume that GET_NYM is always a full verkey in base58. - // For backwards compatibility, we accept a shortened verkey and convert it using previous convention - const verkey = getFullVerkey(did, nym.verkey) - const builder = indyDidDocumentFromDid(did, verkey) - - // NOTE: we don't support the `diddocContent` field in the GET_NYM response using the indy-sdk. So if the did would have the `diddocContent` field - // we will ignore it without knowing if it is present. We may be able to extract the diddocContent from the GET_NYM response in the future, but need - // some dids registered with diddocContent to test with. - if (endpoints) { - const keyAgreementId = `${did}#key-agreement-1` - - builder - .addContext('https://w3id.org/security/suites/x25519-2019/v1') - .addVerificationMethod({ - controller: did, - id: keyAgreementId, - publicKeyBase58: createKeyAgreementKey(verkey), - type: 'X25519KeyAgreementKey2019', - }) - .addKeyAgreement(keyAgreementId) - addServicesFromEndpointsAttrib(builder, did, endpoints, keyAgreementId) - } - - return { - didDocument: builder.build(), - didDocumentMetadata, - didResolutionMetadata: { contentType: 'application/did+ld+json' }, - } - } catch (error) { - return { - didDocument: null, - didDocumentMetadata, - didResolutionMetadata: { - error: 'notFound', - message: `resolver_error: Unable to resolve did '${did}': ${error}`, - }, - } - } - } - - private async getPublicDid(agentContext: AgentContext, pool: IndySdkPool, unqualifiedDid: string) { - const indySdkPoolService = agentContext.dependencyManager.resolve(IndySdkPoolService) - const indySdk = agentContext.dependencyManager.resolve(IndySdkSymbol) - - const request = await indySdk.buildGetNymRequest(null, unqualifiedDid) - const response = await indySdkPoolService.submitReadRequest(pool, request) - - return await indySdk.parseGetNymResponse(response) - } - - private async getEndpointsForDid(agentContext: AgentContext, pool: IndySdkPool, unqualifiedDid: string) { - const indySdk = agentContext.dependencyManager.resolve(IndySdkSymbol) - const indySdkPoolService = agentContext.dependencyManager.resolve(IndySdkPoolService) - - try { - agentContext.config.logger.debug( - `Get endpoints for did '${unqualifiedDid}' from ledger '${pool.didIndyNamespace}'` - ) - - const request = await indySdk.buildGetAttribRequest(null, unqualifiedDid, 'endpoint', null, null) - - agentContext.config.logger.debug( - `Submitting get endpoint ATTRIB request for did '${unqualifiedDid}' to ledger '${pool.didIndyNamespace}'` - ) - const response = await indySdkPoolService.submitReadRequest(pool, request) - - if (!response.result.data) { - return null - } - - const endpoints = JSON.parse(response.result.data as string)?.endpoint as IndyEndpointAttrib - agentContext.config.logger.debug( - `Got endpoints '${JSON.stringify(endpoints)}' for did '${unqualifiedDid}' from ledger '${ - pool.didIndyNamespace - }'`, - { - response, - endpoints, - } - ) - - return endpoints - } catch (error) { - agentContext.config.logger.error( - `Error retrieving endpoints for did '${unqualifiedDid}' from ledger '${pool.didIndyNamespace}'`, - { - error, - } - ) - - throw isIndyError(error) ? new IndySdkError(error) : error - } - } -} diff --git a/packages/indy-sdk/src/dids/IndySdkSovDidResolver.ts b/packages/indy-sdk/src/dids/IndySdkSovDidResolver.ts deleted file mode 100644 index 46c7454ad3..0000000000 --- a/packages/indy-sdk/src/dids/IndySdkSovDidResolver.ts +++ /dev/null @@ -1,101 +0,0 @@ -import type { IndyEndpointAttrib } from './didSovUtil' -import type { IndySdkPool } from '../ledger' -import type { IndySdk } from '../types' -import type { DidResolutionResult, ParsedDid, DidResolver, AgentContext } from '@credo-ts/core' - -import { isIndyError, IndySdkError } from '../error' -import { IndySdkPoolService } from '../ledger/IndySdkPoolService' -import { IndySdkSymbol } from '../types' - -import { addServicesFromEndpointsAttrib, sovDidDocumentFromDid } from './didSovUtil' - -export class IndySdkSovDidResolver implements DidResolver { - public readonly supportedMethods = ['sov'] - - public readonly allowsCaching = true - - public async resolve(agentContext: AgentContext, did: string, parsed: ParsedDid): Promise { - const didDocumentMetadata = {} - - try { - const poolService = agentContext.dependencyManager.resolve(IndySdkPoolService) - const { pool, nymResponse } = await poolService.getPoolForDid(agentContext, parsed.id) - const nym = nymResponse ?? (await this.getPublicDid(agentContext, pool, parsed.id)) - const endpoints = await this.getEndpointsForDid(agentContext, pool, parsed.id) - - const keyAgreementId = `${parsed.did}#key-agreement-1` - const builder = sovDidDocumentFromDid(parsed.did, nym.verkey) - - if (endpoints) { - addServicesFromEndpointsAttrib(builder, parsed.did, endpoints, keyAgreementId) - } - - return { - didDocument: builder.build(), - didDocumentMetadata, - didResolutionMetadata: { contentType: 'application/did+ld+json' }, - } - } catch (error) { - return { - didDocument: null, - didDocumentMetadata, - didResolutionMetadata: { - error: 'notFound', - message: `resolver_error: Unable to resolve did '${did}': ${error}`, - }, - } - } - } - - private async getPublicDid(agentContext: AgentContext, pool: IndySdkPool, did: string) { - const indySdkPoolService = agentContext.dependencyManager.resolve(IndySdkPoolService) - const indySdk = agentContext.dependencyManager.resolve(IndySdkSymbol) - - const request = await indySdk.buildGetNymRequest(null, did) - const response = await indySdkPoolService.submitReadRequest(pool, request) - - return await indySdk.parseGetNymResponse(response) - } - - private async getEndpointsForDid(agentContext: AgentContext, pool: IndySdkPool, unqualifiedDid: string) { - const indySdk = agentContext.dependencyManager.resolve(IndySdkSymbol) - const indySdkPoolService = agentContext.dependencyManager.resolve(IndySdkPoolService) - - try { - agentContext.config.logger.debug( - `Get endpoints for did '${unqualifiedDid}' from ledger '${pool.didIndyNamespace}'` - ) - - const request = await indySdk.buildGetAttribRequest(null, unqualifiedDid, 'endpoint', null, null) - - agentContext.config.logger.debug( - `Submitting get endpoint ATTRIB request for did '${unqualifiedDid}' to ledger '${pool.didIndyNamespace}'` - ) - const response = await indySdkPoolService.submitReadRequest(pool, request) - - if (!response.result.data) return null - - const endpoints = JSON.parse(response.result.data as string)?.endpoint as IndyEndpointAttrib - agentContext.config.logger.debug( - `Got endpoints '${JSON.stringify(endpoints)}' for did '${unqualifiedDid}' from ledger '${ - pool.didIndyNamespace - }'`, - { - response, - endpoints, - } - ) - - return endpoints ?? null - } catch (error) { - agentContext.config.logger.error( - `Error retrieving endpoints for did '${unqualifiedDid}' from ledger '${pool.didIndyNamespace}'`, - { - error, - } - ) - - throw isIndyError(error) ? new IndySdkError(error) : error - } - } -} diff --git a/packages/indy-sdk/src/dids/__tests__/IndySdkIndyDidRegistrar.test.ts b/packages/indy-sdk/src/dids/__tests__/IndySdkIndyDidRegistrar.test.ts deleted file mode 100644 index 3852629be4..0000000000 --- a/packages/indy-sdk/src/dids/__tests__/IndySdkIndyDidRegistrar.test.ts +++ /dev/null @@ -1,501 +0,0 @@ -/* eslint-disable @typescript-eslint/ban-ts-comment */ -import type { IndySdkPool } from '../../ledger/IndySdkPool' -import type { DidRecord, RecordSavedEvent } from '@credo-ts/core' - -import { - SigningProviderRegistry, - DidsApi, - DidDocument, - VerificationMethod, - KeyType, - Key, - TypedArrayEncoder, - DidRepository, - JsonTransformer, - DidDocumentRole, - EventEmitter, - RepositoryEventTypes, -} from '@credo-ts/core' -import { Subject } from 'rxjs' - -import { InMemoryStorageService } from '../../../../../tests/InMemoryStorageService' -import { mockFunction, getAgentConfig, getAgentContext, agentDependencies, indySdk } from '../../../../core/tests' -import { IndySdkPoolService } from '../../ledger/IndySdkPoolService' -import { IndySdkWallet } from '../../wallet' -import { IndySdkIndyDidRegistrar } from '../IndySdkIndyDidRegistrar' - -jest.mock('../../ledger/IndySdkPoolService') -const IndySdkPoolServiceMock = IndySdkPoolService as jest.Mock -const indySdkPoolServiceMock = new IndySdkPoolServiceMock() - -const pool = { - config: { indyNamespace: 'pool1' }, -} as IndySdkPool -mockFunction(indySdkPoolServiceMock.getPoolForNamespace).mockReturnValue(pool) - -const agentConfig = getAgentConfig('IndySdkIndyDidRegistrar') -const wallet = new IndySdkWallet(indySdk, agentConfig.logger, new SigningProviderRegistry([])) - -jest - .spyOn(wallet, 'createKey') - .mockResolvedValue(Key.fromPublicKeyBase58('E6D1m3eERqCueX4ZgMCY14B4NceAr6XP2HyVqt55gDhu', KeyType.Ed25519)) -const storageService = new InMemoryStorageService() -const eventEmitter = new EventEmitter(agentDependencies, new Subject()) -const didRepository = new DidRepository(storageService, eventEmitter) - -const agentContext = getAgentContext({ - wallet, - registerInstances: [ - [DidRepository, didRepository], - [IndySdkPoolService, indySdkPoolServiceMock], - [ - DidsApi, - { - resolve: jest.fn().mockResolvedValue({ - didDocument: new DidDocument({ - id: 'did:indy:pool1:BzCbsNYhMrjHiqZDTUASHg', - authentication: [ - new VerificationMethod({ - id: 'did:indy:pool1:BzCbsNYhMrjHiqZDTUASHg#verkey', - type: 'Ed25519VerificationKey2018', - controller: 'did:indy:pool1:BzCbsNYhMrjHiqZDTUASHg', - publicKeyBase58: 'E6D1m3eERqCueX4ZgMCY14B4NceAr6XP2HyVqt55gDhu', - }), - ], - }), - }), - }, - ], - ], - agentConfig, -}) - -const indySdkIndyDidRegistrar = new IndySdkIndyDidRegistrar() - -describe('IndySdkIndyDidRegistrar', () => { - afterEach(() => { - jest.clearAllMocks() - }) - - test('returns an error state if both did and privateKey are provided', async () => { - const result = await indySdkIndyDidRegistrar.create(agentContext, { - did: 'did:indy:pool1:did-value', - options: { - submitterDid: 'did:indy:pool1:BzCbsNYhMrjHiqZDTUASHg', - alias: 'Hello', - }, - secret: { - privateKey: TypedArrayEncoder.fromString('key'), - }, - }) - - expect(JsonTransformer.toJSON(result)).toMatchObject({ - didDocumentMetadata: {}, - didRegistrationMetadata: {}, - didState: { - state: 'failed', - reason: `Only one of 'privateKey' or 'did' must be provided`, - }, - }) - }) - - test('returns an error state if the submitter did is not a valid did:indy did', async () => { - const result = await indySdkIndyDidRegistrar.create(agentContext, { - method: 'indy', - options: { - submitterDid: 'BzCbsNYhMrjHiqZDTUASHg', - alias: 'Hello', - }, - }) - - expect(JsonTransformer.toJSON(result)).toMatchObject({ - didDocumentMetadata: {}, - didRegistrationMetadata: {}, - didState: { - state: 'failed', - reason: 'unknownError: BzCbsNYhMrjHiqZDTUASHg is not a valid did:indy did', - }, - }) - }) - - test('returns an error state if did is provided, but it is not a valid did:indy did', async () => { - const result = await indySdkIndyDidRegistrar.create(agentContext, { - did: 'BzCbsNYhMrjHiqZDTUASHg', - options: { - submitterDid: 'did:indy:pool1:BzCbsNYhMrjHiqZDTUASHg', - verkey: 'verkey', - alias: 'Hello', - }, - }) - - expect(JsonTransformer.toJSON(result)).toMatchObject({ - didDocumentMetadata: {}, - didRegistrationMetadata: {}, - didState: { - state: 'failed', - reason: 'unknownError: BzCbsNYhMrjHiqZDTUASHg is not a valid did:indy did', - }, - }) - }) - - test('returns an error state if did is provided, but no verkey', async () => { - const result = await indySdkIndyDidRegistrar.create(agentContext, { - did: 'BzCbsNYhMrjHiqZDTUASHg', - options: { - submitterDid: 'did:indy:pool1:BzCbsNYhMrjHiqZDTUASHg', - alias: 'Hello', - }, - }) - - expect(JsonTransformer.toJSON(result)).toMatchObject({ - didDocumentMetadata: {}, - didRegistrationMetadata: {}, - didState: { - state: 'failed', - reason: 'If a did is defined, a matching verkey must be provided', - }, - }) - }) - - test('returns an error state if did and verkey are provided, but the did is not self certifying', async () => { - const result = await indySdkIndyDidRegistrar.create(agentContext, { - did: 'did:indy:pool1:BzCbsNYhMrjHiqZDTUASHg', - options: { - submitterDid: 'did:indy:pool1:BzCbsNYhMrjHiqZDTUASHg', - verkey: 'verkey', - alias: 'Hello', - }, - }) - - expect(JsonTransformer.toJSON(result)).toMatchObject({ - didDocumentMetadata: {}, - didRegistrationMetadata: {}, - didState: { - state: 'failed', - reason: 'Did must be first 16 bytes of the the verkey base58 encoded.', - }, - }) - }) - - test('returns an error state if did is provided, but does not match with the namespace from the submitterDid', async () => { - const result = await indySdkIndyDidRegistrar.create(agentContext, { - did: 'did:indy:pool2:R1xKJw17sUoXhejEpugMYJ', - options: { - submitterDid: 'did:indy:pool1:BzCbsNYhMrjHiqZDTUASHg', - verkey: 'E6D1m3eERqCueX4ZgMCY14B4NceAr6XP2HyVqt55gDhu', - alias: 'Hello', - }, - }) - - expect(JsonTransformer.toJSON(result)).toMatchObject({ - didDocumentMetadata: {}, - didRegistrationMetadata: {}, - didState: { - state: 'failed', - reason: - 'The submitter did uses namespace pool1 and the did to register uses namespace pool2. Namespaces must match.', - }, - }) - }) - - test('creates a did:indy document without services', async () => { - const privateKey = TypedArrayEncoder.fromString('96213c3d7fc8d4d6754c712fd969598e') - - // @ts-ignore method is private - const registerPublicDidSpy = jest.spyOn(indySdkIndyDidRegistrar, 'registerPublicDid') - // @ts-ignore type check fails because method is private - registerPublicDidSpy.mockImplementationOnce(() => Promise.resolve()) - - const result = await indySdkIndyDidRegistrar.create(agentContext, { - method: 'indy', - options: { - alias: 'Hello', - submitterDid: 'did:indy:pool1:BzCbsNYhMrjHiqZDTUASHg', - role: 'STEWARD', - }, - secret: { - privateKey, - }, - }) - expect(registerPublicDidSpy).toHaveBeenCalledWith( - agentContext, - pool, - // Unqualified submitter did - 'BzCbsNYhMrjHiqZDTUASHg', - // submitter signing key, - expect.any(Key), - // Unqualified created indy did - 'R1xKJw17sUoXhejEpugMYJ', - // Verkey - expect.any(Key), - // Alias - 'Hello', - // Role - 'STEWARD' - ) - expect(JsonTransformer.toJSON(result)).toMatchObject({ - didDocumentMetadata: {}, - didRegistrationMetadata: {}, - didState: { - state: 'finished', - did: 'did:indy:pool1:R1xKJw17sUoXhejEpugMYJ', - didDocument: { - '@context': ['https://w3id.org/did/v1', 'https://w3id.org/security/suites/ed25519-2018/v1'], - id: 'did:indy:pool1:R1xKJw17sUoXhejEpugMYJ', - verificationMethod: [ - { - id: 'did:indy:pool1:R1xKJw17sUoXhejEpugMYJ#verkey', - type: 'Ed25519VerificationKey2018', - controller: 'did:indy:pool1:R1xKJw17sUoXhejEpugMYJ', - publicKeyBase58: 'E6D1m3eERqCueX4ZgMCY14B4NceAr6XP2HyVqt55gDhu', - }, - ], - authentication: ['did:indy:pool1:R1xKJw17sUoXhejEpugMYJ#verkey'], - assertionMethod: undefined, - keyAgreement: undefined, - }, - secret: { - privateKey, - }, - }, - }) - }) - - test('creates a did:indy document by passing did', async () => { - // @ts-ignore method is private - const registerPublicDidSpy = jest.spyOn(indySdkIndyDidRegistrar, 'registerPublicDid') - // @ts-ignore type check fails because method is private - registerPublicDidSpy.mockImplementationOnce(() => Promise.resolve()) - - const result = await indySdkIndyDidRegistrar.create(agentContext, { - did: 'did:indy:pool1:R1xKJw17sUoXhejEpugMYJ', - options: { - verkey: 'E6D1m3eERqCueX4ZgMCY14B4NceAr6XP2HyVqt55gDhu', - alias: 'Hello', - submitterDid: 'did:indy:pool1:BzCbsNYhMrjHiqZDTUASHg', - role: 'STEWARD', - }, - secret: {}, - }) - expect(registerPublicDidSpy).toHaveBeenCalledWith( - agentContext, - pool, - // Unqualified submitter did - 'BzCbsNYhMrjHiqZDTUASHg', - // submitter signing key, - expect.any(Key), - // Unqualified created indy did - 'R1xKJw17sUoXhejEpugMYJ', - // Verkey - expect.any(Key), - // Alias - 'Hello', - // Role - 'STEWARD' - ) - expect(JsonTransformer.toJSON(result)).toMatchObject({ - didDocumentMetadata: {}, - didRegistrationMetadata: {}, - didState: { - state: 'finished', - did: 'did:indy:pool1:R1xKJw17sUoXhejEpugMYJ', - didDocument: { - '@context': ['https://w3id.org/did/v1', 'https://w3id.org/security/suites/ed25519-2018/v1'], - id: 'did:indy:pool1:R1xKJw17sUoXhejEpugMYJ', - verificationMethod: [ - { - id: 'did:indy:pool1:R1xKJw17sUoXhejEpugMYJ#verkey', - type: 'Ed25519VerificationKey2018', - controller: 'did:indy:pool1:R1xKJw17sUoXhejEpugMYJ', - publicKeyBase58: 'E6D1m3eERqCueX4ZgMCY14B4NceAr6XP2HyVqt55gDhu', - }, - ], - authentication: ['did:indy:pool1:R1xKJw17sUoXhejEpugMYJ#verkey'], - assertionMethod: undefined, - keyAgreement: undefined, - }, - secret: {}, - }, - }) - }) - - test('creates a did:indy document with services', async () => { - const privateKey = TypedArrayEncoder.fromString('96213c3d7fc8d4d6754c712fd969598e') - - // @ts-ignore method is private - const registerPublicDidSpy = jest.spyOn(indySdkIndyDidRegistrar, 'registerPublicDid') - // @ts-ignore type check fails because method is private - registerPublicDidSpy.mockImplementationOnce(() => Promise.resolve()) - - // @ts-ignore method is private - const setEndpointsForDidSpy = jest.spyOn(indySdkIndyDidRegistrar, 'setEndpointsForDid') - // @ts-ignore type check fails because method is private - setEndpointsForDidSpy.mockImplementationOnce(() => Promise.resolve(undefined)) - - const result = await indySdkIndyDidRegistrar.create(agentContext, { - method: 'indy', - options: { - alias: 'Hello', - submitterDid: 'did:indy:pool1:BzCbsNYhMrjHiqZDTUASHg', - role: 'STEWARD', - endpoints: { - endpoint: 'https://example.com/endpoint', - routingKeys: ['key-1'], - types: ['DIDComm', 'did-communication', 'endpoint'], - }, - }, - secret: { - privateKey, - }, - }) - - expect(registerPublicDidSpy).toHaveBeenCalledWith( - agentContext, - pool, - // Unqualified submitter did - 'BzCbsNYhMrjHiqZDTUASHg', - // submitter signing key, - expect.any(Key), - // Unqualified created indy did - 'R1xKJw17sUoXhejEpugMYJ', - // Verkey - expect.any(Key), - // Alias - 'Hello', - // Role - 'STEWARD' - ) - expect(JsonTransformer.toJSON(result)).toMatchObject({ - didDocumentMetadata: {}, - didRegistrationMetadata: {}, - didState: { - state: 'finished', - did: 'did:indy:pool1:R1xKJw17sUoXhejEpugMYJ', - didDocument: { - '@context': [ - 'https://w3id.org/did/v1', - 'https://w3id.org/security/suites/ed25519-2018/v1', - 'https://w3id.org/security/suites/x25519-2019/v1', - 'https://didcomm.org/messaging/contexts/v2', - ], - id: 'did:indy:pool1:R1xKJw17sUoXhejEpugMYJ', - verificationMethod: [ - { - id: 'did:indy:pool1:R1xKJw17sUoXhejEpugMYJ#verkey', - type: 'Ed25519VerificationKey2018', - controller: 'did:indy:pool1:R1xKJw17sUoXhejEpugMYJ', - publicKeyBase58: 'E6D1m3eERqCueX4ZgMCY14B4NceAr6XP2HyVqt55gDhu', - }, - { - id: 'did:indy:pool1:R1xKJw17sUoXhejEpugMYJ#key-agreement-1', - type: 'X25519KeyAgreementKey2019', - controller: 'did:indy:pool1:R1xKJw17sUoXhejEpugMYJ', - publicKeyBase58: 'Fbv17ZbnUSbafsiUBJbdGeC62M8v8GEscVMMcE59mRPt', - }, - ], - service: [ - { - id: 'did:indy:pool1:R1xKJw17sUoXhejEpugMYJ#endpoint', - serviceEndpoint: 'https://example.com/endpoint', - type: 'endpoint', - }, - { - id: 'did:indy:pool1:R1xKJw17sUoXhejEpugMYJ#did-communication', - serviceEndpoint: 'https://example.com/endpoint', - type: 'did-communication', - priority: 0, - recipientKeys: ['did:indy:pool1:R1xKJw17sUoXhejEpugMYJ#key-agreement-1'], - routingKeys: ['key-1'], - accept: ['didcomm/aip2;env=rfc19'], - }, - { - id: 'did:indy:pool1:R1xKJw17sUoXhejEpugMYJ#didcomm-1', - serviceEndpoint: 'https://example.com/endpoint', - type: 'DIDComm', - routingKeys: ['key-1'], - accept: ['didcomm/v2'], - }, - ], - authentication: ['did:indy:pool1:R1xKJw17sUoXhejEpugMYJ#verkey'], - assertionMethod: undefined, - keyAgreement: ['did:indy:pool1:R1xKJw17sUoXhejEpugMYJ#key-agreement-1'], - }, - secret: { - privateKey, - }, - }, - }) - }) - - test('stores the did document', async () => { - const privateKey = TypedArrayEncoder.fromString('96213c3d7fc8d4d6754c712fd969598e') - - // @ts-ignore method is private - const registerPublicDidSpy = jest.spyOn(indySdkIndyDidRegistrar, 'registerPublicDid') - // @ts-ignore type check fails because method is private - registerPublicDidSpy.mockImplementationOnce(() => Promise.resolve()) - - // @ts-ignore method is private - const setEndpointsForDidSpy = jest.spyOn(indySdkIndyDidRegistrar, 'setEndpointsForDid') - // @ts-ignore type check fails because method is private - setEndpointsForDidSpy.mockImplementationOnce(() => Promise.resolve(undefined)) - - const saveCalled = jest.fn() - eventEmitter.on>(RepositoryEventTypes.RecordSaved, saveCalled) - - await indySdkIndyDidRegistrar.create(agentContext, { - method: 'indy', - options: { - alias: 'Hello', - submitterDid: 'did:indy:pool1:BzCbsNYhMrjHiqZDTUASHg', - role: 'STEWARD', - endpoints: { - endpoint: 'https://example.com/endpoint', - routingKeys: ['key-1'], - types: ['DIDComm', 'did-communication', 'endpoint'], - }, - }, - secret: { - privateKey, - }, - }) - - expect(saveCalled).toHaveBeenCalledTimes(1) - const [saveEvent] = saveCalled.mock.calls[0] - - expect(saveEvent.payload.record).toMatchObject({ - did: 'did:indy:pool1:R1xKJw17sUoXhejEpugMYJ', - role: DidDocumentRole.Created, - _tags: { - recipientKeyFingerprints: ['z6LSrH6AdsQeZuKKmG6Ehx7abEQZsVg2psR2VU536gigUoAe'], - }, - didDocument: undefined, - }) - }) - - test('returns an error state when calling update', async () => { - const result = await indySdkIndyDidRegistrar.update() - - expect(result).toEqual({ - didDocumentMetadata: {}, - didRegistrationMetadata: {}, - didState: { - state: 'failed', - reason: `notImplemented: updating did:indy not implemented yet`, - }, - }) - }) - - test('returns an error state when calling deactivate', async () => { - const result = await indySdkIndyDidRegistrar.deactivate() - - expect(result).toEqual({ - didDocumentMetadata: {}, - didRegistrationMetadata: {}, - didState: { - state: 'failed', - reason: `notImplemented: deactivating did:indy not implemented yet`, - }, - }) - }) -}) diff --git a/packages/indy-sdk/src/dids/__tests__/IndySdkIndyDidResolver.test.ts b/packages/indy-sdk/src/dids/__tests__/IndySdkIndyDidResolver.test.ts deleted file mode 100644 index 3b431bc964..0000000000 --- a/packages/indy-sdk/src/dids/__tests__/IndySdkIndyDidResolver.test.ts +++ /dev/null @@ -1,127 +0,0 @@ -import type { IndySdkPool } from '../../ledger' -import type { IndyEndpointAttrib } from '../didSovUtil' -import type { GetNymResponse } from 'indy-sdk' - -import { SigningProviderRegistry, JsonTransformer } from '@credo-ts/core' -import indySdk from 'indy-sdk' - -import { mockFunction, getAgentConfig, getAgentContext } from '../../../../core/tests/helpers' -import { IndySdkPoolService } from '../../ledger/IndySdkPoolService' -import { IndySdkSymbol } from '../../types' -import { IndySdkWallet } from '../../wallet' -import { IndySdkIndyDidResolver } from '../IndySdkIndyDidResolver' - -import didIndyPool1R1xKJw17sUoXhejEpugMYJFixture from './__fixtures__/didIndyPool1R1xKJw17sUoXhejEpugMYJ.json' -import didIndyPool1WJz9mHyW9BZksioQnRsrAoFixture from './__fixtures__/didIndyPool1WJz9mHyW9BZksioQnRsrAo.json' - -jest.mock('../../ledger/IndySdkPoolService') -const IndySdkPoolServiceMock = IndySdkPoolService as jest.Mock -const indySdkPoolServiceMock = new IndySdkPoolServiceMock() - -mockFunction(indySdkPoolServiceMock.getPoolForNamespace).mockReturnValue({ - config: { indyNamespace: 'pool1' }, -} as IndySdkPool) - -const agentConfig = getAgentConfig('IndySdkIndyDidResolver') - -const wallet = new IndySdkWallet(indySdk, agentConfig.logger, new SigningProviderRegistry([])) - -const agentContext = getAgentContext({ - wallet, - agentConfig, - registerInstances: [ - [IndySdkPoolService, indySdkPoolServiceMock], - [IndySdkSymbol, indySdk], - ], -}) - -const indySdkSovDidResolver = new IndySdkIndyDidResolver() - -describe('IndySdkIndyDidResolver', () => { - it('should correctly resolve a did:indy document', async () => { - const did = 'did:indy:pool1:R1xKJw17sUoXhejEpugMYJ' - - const nymResponse: GetNymResponse = { - did: 'R1xKJw17sUoXhejEpugMYJ', - verkey: 'E6D1m3eERqCueX4ZgMCY14B4NceAr6XP2HyVqt55gDhu', - role: 'ENDORSER', - } - - const endpoints: IndyEndpointAttrib = { - endpoint: 'https://ssi.com', - profile: 'https://profile.com', - hub: 'https://hub.com', - } - - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - jest.spyOn(indySdkSovDidResolver, 'getPublicDid').mockResolvedValue(nymResponse) - - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - jest.spyOn(indySdkSovDidResolver, 'getEndpointsForDid').mockResolvedValue(endpoints) - - const result = await indySdkSovDidResolver.resolve(agentContext, did) - - expect(JsonTransformer.toJSON(result)).toMatchObject({ - didDocument: didIndyPool1R1xKJw17sUoXhejEpugMYJFixture, - didDocumentMetadata: {}, - didResolutionMetadata: { - contentType: 'application/did+ld+json', - }, - }) - }) - - it('should resolve a did:indy document with routingKeys and types entries in the attrib', async () => { - const did = 'did:indy:pool1:WJz9mHyW9BZksioQnRsrAo' - - const nymResponse: GetNymResponse = { - did: 'WJz9mHyW9BZksioQnRsrAo', - verkey: 'GyYtYWU1vjwd5PFJM4VSX5aUiSV3TyZMuLBJBTQvfdF8', - role: 'ENDORSER', - } - - const endpoints: IndyEndpointAttrib = { - endpoint: 'https://agent.com', - types: ['endpoint', 'did-communication', 'DIDComm'], - routingKeys: ['routingKey1', 'routingKey2'], - } - - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - jest.spyOn(indySdkSovDidResolver, 'getPublicDid').mockResolvedValue(nymResponse) - - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - jest.spyOn(indySdkSovDidResolver, 'getEndpointsForDid').mockResolvedValue(endpoints) - - const result = await indySdkSovDidResolver.resolve(agentContext, did) - - expect(JsonTransformer.toJSON(result)).toMatchObject({ - didDocument: didIndyPool1WJz9mHyW9BZksioQnRsrAoFixture, - didDocumentMetadata: {}, - didResolutionMetadata: { - contentType: 'application/did+ld+json', - }, - }) - }) - - it('should return did resolution metadata with error if the indy ledger service throws an error', async () => { - const did = 'did:indy:pool1:R1xKJw17sUoXhejEpugMYJ' - - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - jest.spyOn(indySdkSovDidResolver, 'getPublicDid').mockRejectedValue(new Error('Error retrieving did')) - - const result = await indySdkSovDidResolver.resolve(agentContext, did) - - expect(result).toMatchObject({ - didDocument: null, - didDocumentMetadata: {}, - didResolutionMetadata: { - error: 'notFound', - message: `resolver_error: Unable to resolve did 'did:indy:pool1:R1xKJw17sUoXhejEpugMYJ': Error: Error retrieving did`, - }, - }) - }) -}) diff --git a/packages/indy-sdk/src/dids/__tests__/IndySdkSovDidResolver.test.ts b/packages/indy-sdk/src/dids/__tests__/IndySdkSovDidResolver.test.ts deleted file mode 100644 index b79ca7c507..0000000000 --- a/packages/indy-sdk/src/dids/__tests__/IndySdkSovDidResolver.test.ts +++ /dev/null @@ -1,132 +0,0 @@ -import type { IndySdkPool } from '../../ledger' -import type { IndyEndpointAttrib } from '../didSovUtil' -import type { GetNymResponse } from 'indy-sdk' - -import { SigningProviderRegistry, JsonTransformer } from '@credo-ts/core' -import indySdk from 'indy-sdk' - -import { parseDid } from '../../../../core/src/modules/dids/domain/parse' -import { mockFunction, getAgentConfig, getAgentContext } from '../../../../core/tests/helpers' -import { IndySdkPoolService } from '../../ledger/IndySdkPoolService' -import { IndySdkSymbol } from '../../types' -import { IndySdkWallet } from '../../wallet' -import { IndySdkSovDidResolver } from '../IndySdkSovDidResolver' - -import didSovR1xKJw17sUoXhejEpugMYJFixture from './__fixtures__/didSovR1xKJw17sUoXhejEpugMYJ.json' -import didSovWJz9mHyW9BZksioQnRsrAoFixture from './__fixtures__/didSovWJz9mHyW9BZksioQnRsrAo.json' - -jest.mock('../../ledger/IndySdkPoolService') -const IndySdkPoolServiceMock = IndySdkPoolService as jest.Mock -const indySdkPoolServiceMock = new IndySdkPoolServiceMock() - -mockFunction(indySdkPoolServiceMock.getPoolForNamespace).mockReturnValue({ - config: { indyNamespace: 'pool1' }, -} as IndySdkPool) - -mockFunction(indySdkPoolServiceMock.getPoolForDid).mockResolvedValue({ - pool: { config: { indyNamespace: 'pool1' } } as IndySdkPool, -}) - -const agentConfig = getAgentConfig('IndySdkSovDidResolver') - -const wallet = new IndySdkWallet(indySdk, agentConfig.logger, new SigningProviderRegistry([])) - -const agentContext = getAgentContext({ - wallet, - agentConfig, - registerInstances: [ - [IndySdkPoolService, indySdkPoolServiceMock], - [IndySdkSymbol, indySdk], - ], -}) - -const indySdkSovDidResolver = new IndySdkSovDidResolver() - -describe('IndySdkSovDidResolver', () => { - it('should correctly resolve a did:sov document', async () => { - const did = 'did:sov:R1xKJw17sUoXhejEpugMYJ' - - const nymResponse: GetNymResponse = { - did: 'R1xKJw17sUoXhejEpugMYJ', - verkey: 'E6D1m3eERqCueX4ZgMCY14B4NceAr6XP2HyVqt55gDhu', - role: 'ENDORSER', - } - - const endpoints: IndyEndpointAttrib = { - endpoint: 'https://ssi.com', - profile: 'https://profile.com', - hub: 'https://hub.com', - } - - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - jest.spyOn(indySdkSovDidResolver, 'getPublicDid').mockResolvedValue(nymResponse) - - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - jest.spyOn(indySdkSovDidResolver, 'getEndpointsForDid').mockResolvedValue(endpoints) - - const result = await indySdkSovDidResolver.resolve(agentContext, did, parseDid(did)) - - expect(JsonTransformer.toJSON(result)).toMatchObject({ - didDocument: didSovR1xKJw17sUoXhejEpugMYJFixture, - didDocumentMetadata: {}, - didResolutionMetadata: { - contentType: 'application/did+ld+json', - }, - }) - }) - - it('should resolve a did:sov document with routingKeys and types entries in the attrib', async () => { - const did = 'did:sov:WJz9mHyW9BZksioQnRsrAo' - - const nymResponse: GetNymResponse = { - did: 'WJz9mHyW9BZksioQnRsrAo', - verkey: 'GyYtYWU1vjwd5PFJM4VSX5aUiSV3TyZMuLBJBTQvfdF8', - role: 'ENDORSER', - } - - const endpoints: IndyEndpointAttrib = { - endpoint: 'https://agent.com', - types: ['endpoint', 'did-communication', 'DIDComm'], - routingKeys: ['routingKey1', 'routingKey2'], - } - - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - jest.spyOn(indySdkSovDidResolver, 'getPublicDid').mockResolvedValue(nymResponse) - - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - jest.spyOn(indySdkSovDidResolver, 'getEndpointsForDid').mockResolvedValue(endpoints) - - const result = await indySdkSovDidResolver.resolve(agentContext, did, parseDid(did)) - - expect(JsonTransformer.toJSON(result)).toMatchObject({ - didDocument: didSovWJz9mHyW9BZksioQnRsrAoFixture, - didDocumentMetadata: {}, - didResolutionMetadata: { - contentType: 'application/did+ld+json', - }, - }) - }) - - it('should return did resolution metadata with error if the indy ledger service throws an error', async () => { - const did = 'did:sov:R1xKJw17sUoXhejEpugMYJ' - - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - jest.spyOn(indySdkSovDidResolver, 'getPublicDid').mockRejectedValue(new Error('Error retrieving did')) - - const result = await indySdkSovDidResolver.resolve(agentContext, did, parseDid(did)) - - expect(result).toMatchObject({ - didDocument: null, - didDocumentMetadata: {}, - didResolutionMetadata: { - error: 'notFound', - message: `resolver_error: Unable to resolve did 'did:sov:R1xKJw17sUoXhejEpugMYJ': Error: Error retrieving did`, - }, - }) - }) -}) diff --git a/packages/indy-sdk/src/dids/__tests__/__fixtures__/didIndyPool1R1xKJw17sUoXhejEpugMYJ.json b/packages/indy-sdk/src/dids/__tests__/__fixtures__/didIndyPool1R1xKJw17sUoXhejEpugMYJ.json deleted file mode 100644 index c0bd51aa30..0000000000 --- a/packages/indy-sdk/src/dids/__tests__/__fixtures__/didIndyPool1R1xKJw17sUoXhejEpugMYJ.json +++ /dev/null @@ -1,50 +0,0 @@ -{ - "@context": [ - "https://w3id.org/did/v1", - "https://w3id.org/security/suites/ed25519-2018/v1", - "https://w3id.org/security/suites/x25519-2019/v1" - ], - "id": "did:indy:pool1:R1xKJw17sUoXhejEpugMYJ", - "verificationMethod": [ - { - "type": "Ed25519VerificationKey2018", - "controller": "did:indy:pool1:R1xKJw17sUoXhejEpugMYJ", - "id": "did:indy:pool1:R1xKJw17sUoXhejEpugMYJ#verkey", - "publicKeyBase58": "E6D1m3eERqCueX4ZgMCY14B4NceAr6XP2HyVqt55gDhu" - }, - { - "type": "X25519KeyAgreementKey2019", - "controller": "did:indy:pool1:R1xKJw17sUoXhejEpugMYJ", - "id": "did:indy:pool1:R1xKJw17sUoXhejEpugMYJ#key-agreement-1", - "publicKeyBase58": "Fbv17ZbnUSbafsiUBJbdGeC62M8v8GEscVMMcE59mRPt" - } - ], - "authentication": ["did:indy:pool1:R1xKJw17sUoXhejEpugMYJ#verkey"], - "keyAgreement": ["did:indy:pool1:R1xKJw17sUoXhejEpugMYJ#key-agreement-1"], - "service": [ - { - "id": "did:indy:pool1:R1xKJw17sUoXhejEpugMYJ#endpoint", - "type": "endpoint", - "serviceEndpoint": "https://ssi.com" - }, - { - "accept": ["didcomm/aip2;env=rfc19"], - "id": "did:indy:pool1:R1xKJw17sUoXhejEpugMYJ#did-communication", - "priority": 0, - "recipientKeys": ["did:indy:pool1:R1xKJw17sUoXhejEpugMYJ#key-agreement-1"], - "routingKeys": [], - "serviceEndpoint": "https://ssi.com", - "type": "did-communication" - }, - { - "id": "did:indy:pool1:R1xKJw17sUoXhejEpugMYJ#profile", - "serviceEndpoint": "https://profile.com", - "type": "profile" - }, - { - "id": "did:indy:pool1:R1xKJw17sUoXhejEpugMYJ#hub", - "serviceEndpoint": "https://hub.com", - "type": "hub" - } - ] -} diff --git a/packages/indy-sdk/src/dids/__tests__/__fixtures__/didIndyPool1WJz9mHyW9BZksioQnRsrAo.json b/packages/indy-sdk/src/dids/__tests__/__fixtures__/didIndyPool1WJz9mHyW9BZksioQnRsrAo.json deleted file mode 100644 index a943f3bf9e..0000000000 --- a/packages/indy-sdk/src/dids/__tests__/__fixtures__/didIndyPool1WJz9mHyW9BZksioQnRsrAo.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "@context": [ - "https://w3id.org/did/v1", - "https://w3id.org/security/suites/ed25519-2018/v1", - "https://w3id.org/security/suites/x25519-2019/v1", - "https://didcomm.org/messaging/contexts/v2" - ], - "id": "did:indy:pool1:WJz9mHyW9BZksioQnRsrAo", - "verificationMethod": [ - { - "type": "Ed25519VerificationKey2018", - "controller": "did:indy:pool1:WJz9mHyW9BZksioQnRsrAo", - "id": "did:indy:pool1:WJz9mHyW9BZksioQnRsrAo#verkey", - "publicKeyBase58": "GyYtYWU1vjwd5PFJM4VSX5aUiSV3TyZMuLBJBTQvfdF8" - }, - { - "type": "X25519KeyAgreementKey2019", - "controller": "did:indy:pool1:WJz9mHyW9BZksioQnRsrAo", - "id": "did:indy:pool1:WJz9mHyW9BZksioQnRsrAo#key-agreement-1", - "publicKeyBase58": "S3AQEEKkGYrrszT9D55ozVVX2XixYp8uynqVm4okbud" - } - ], - "authentication": ["did:indy:pool1:WJz9mHyW9BZksioQnRsrAo#verkey"], - "keyAgreement": ["did:indy:pool1:WJz9mHyW9BZksioQnRsrAo#key-agreement-1"], - "service": [ - { - "id": "did:indy:pool1:WJz9mHyW9BZksioQnRsrAo#endpoint", - "type": "endpoint", - "serviceEndpoint": "https://agent.com" - }, - { - "id": "did:indy:pool1:WJz9mHyW9BZksioQnRsrAo#did-communication", - "type": "did-communication", - "priority": 0, - "recipientKeys": ["did:indy:pool1:WJz9mHyW9BZksioQnRsrAo#key-agreement-1"], - "routingKeys": ["routingKey1", "routingKey2"], - "accept": ["didcomm/aip2;env=rfc19"], - "serviceEndpoint": "https://agent.com" - }, - { - "id": "did:indy:pool1:WJz9mHyW9BZksioQnRsrAo#didcomm-1", - "type": "DIDComm", - "serviceEndpoint": "https://agent.com", - "accept": ["didcomm/v2"], - "routingKeys": ["routingKey1", "routingKey2"] - } - ] -} diff --git a/packages/indy-sdk/src/dids/__tests__/__fixtures__/didSovR1xKJw17sUoXhejEpugMYJ.json b/packages/indy-sdk/src/dids/__tests__/__fixtures__/didSovR1xKJw17sUoXhejEpugMYJ.json deleted file mode 100644 index 6a6e4ed706..0000000000 --- a/packages/indy-sdk/src/dids/__tests__/__fixtures__/didSovR1xKJw17sUoXhejEpugMYJ.json +++ /dev/null @@ -1,51 +0,0 @@ -{ - "@context": [ - "https://w3id.org/did/v1", - "https://w3id.org/security/suites/ed25519-2018/v1", - "https://w3id.org/security/suites/x25519-2019/v1" - ], - "id": "did:sov:R1xKJw17sUoXhejEpugMYJ", - "verificationMethod": [ - { - "type": "Ed25519VerificationKey2018", - "controller": "did:sov:R1xKJw17sUoXhejEpugMYJ", - "id": "did:sov:R1xKJw17sUoXhejEpugMYJ#key-1", - "publicKeyBase58": "E6D1m3eERqCueX4ZgMCY14B4NceAr6XP2HyVqt55gDhu" - }, - { - "type": "X25519KeyAgreementKey2019", - "controller": "did:sov:R1xKJw17sUoXhejEpugMYJ", - "id": "did:sov:R1xKJw17sUoXhejEpugMYJ#key-agreement-1", - "publicKeyBase58": "Fbv17ZbnUSbafsiUBJbdGeC62M8v8GEscVMMcE59mRPt" - } - ], - "authentication": ["did:sov:R1xKJw17sUoXhejEpugMYJ#key-1"], - "assertionMethod": ["did:sov:R1xKJw17sUoXhejEpugMYJ#key-1"], - "keyAgreement": ["did:sov:R1xKJw17sUoXhejEpugMYJ#key-agreement-1"], - "service": [ - { - "id": "did:sov:R1xKJw17sUoXhejEpugMYJ#endpoint", - "type": "endpoint", - "serviceEndpoint": "https://ssi.com" - }, - { - "accept": ["didcomm/aip2;env=rfc19"], - "id": "did:sov:R1xKJw17sUoXhejEpugMYJ#did-communication", - "priority": 0, - "recipientKeys": ["did:sov:R1xKJw17sUoXhejEpugMYJ#key-agreement-1"], - "routingKeys": [], - "serviceEndpoint": "https://ssi.com", - "type": "did-communication" - }, - { - "id": "did:sov:R1xKJw17sUoXhejEpugMYJ#profile", - "serviceEndpoint": "https://profile.com", - "type": "profile" - }, - { - "id": "did:sov:R1xKJw17sUoXhejEpugMYJ#hub", - "serviceEndpoint": "https://hub.com", - "type": "hub" - } - ] -} diff --git a/packages/indy-sdk/src/dids/__tests__/__fixtures__/didSovWJz9mHyW9BZksioQnRsrAo.json b/packages/indy-sdk/src/dids/__tests__/__fixtures__/didSovWJz9mHyW9BZksioQnRsrAo.json deleted file mode 100644 index 7b74e0587f..0000000000 --- a/packages/indy-sdk/src/dids/__tests__/__fixtures__/didSovWJz9mHyW9BZksioQnRsrAo.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "@context": [ - "https://w3id.org/did/v1", - "https://w3id.org/security/suites/ed25519-2018/v1", - "https://w3id.org/security/suites/x25519-2019/v1", - "https://didcomm.org/messaging/contexts/v2" - ], - "id": "did:sov:WJz9mHyW9BZksioQnRsrAo", - "verificationMethod": [ - { - "type": "Ed25519VerificationKey2018", - "controller": "did:sov:WJz9mHyW9BZksioQnRsrAo", - "id": "did:sov:WJz9mHyW9BZksioQnRsrAo#key-1", - "publicKeyBase58": "GyYtYWU1vjwd5PFJM4VSX5aUiSV3TyZMuLBJBTQvfdF8" - }, - { - "type": "X25519KeyAgreementKey2019", - "controller": "did:sov:WJz9mHyW9BZksioQnRsrAo", - "id": "did:sov:WJz9mHyW9BZksioQnRsrAo#key-agreement-1", - "publicKeyBase58": "S3AQEEKkGYrrszT9D55ozVVX2XixYp8uynqVm4okbud" - } - ], - "authentication": ["did:sov:WJz9mHyW9BZksioQnRsrAo#key-1"], - "assertionMethod": ["did:sov:WJz9mHyW9BZksioQnRsrAo#key-1"], - "keyAgreement": ["did:sov:WJz9mHyW9BZksioQnRsrAo#key-agreement-1"], - "service": [ - { - "id": "did:sov:WJz9mHyW9BZksioQnRsrAo#endpoint", - "type": "endpoint", - "serviceEndpoint": "https://agent.com" - }, - { - "id": "did:sov:WJz9mHyW9BZksioQnRsrAo#did-communication", - "type": "did-communication", - "priority": 0, - "recipientKeys": ["did:sov:WJz9mHyW9BZksioQnRsrAo#key-agreement-1"], - "routingKeys": ["routingKey1", "routingKey2"], - "accept": ["didcomm/aip2;env=rfc19"], - "serviceEndpoint": "https://agent.com" - }, - { - "id": "did:sov:WJz9mHyW9BZksioQnRsrAo#didcomm-1", - "type": "DIDComm", - "serviceEndpoint": "https://agent.com", - "accept": ["didcomm/v2"], - "routingKeys": ["routingKey1", "routingKey2"] - } - ] -} diff --git a/packages/indy-sdk/src/dids/didIndyUtil.ts b/packages/indy-sdk/src/dids/didIndyUtil.ts deleted file mode 100644 index 6131be042d..0000000000 --- a/packages/indy-sdk/src/dids/didIndyUtil.ts +++ /dev/null @@ -1,55 +0,0 @@ -import type { AgentContext } from '@credo-ts/core' - -import { - getKeyFromVerificationMethod, - AriesFrameworkError, - convertPublicKeyToX25519, - DidDocumentBuilder, - DidsApi, - TypedArrayEncoder, -} from '@credo-ts/core' - -// Create a base DIDDoc template according to https://hyperledger.github.io/indy-did-method/#base-diddoc-template -export function indyDidDocumentFromDid(did: string, publicKeyBase58: string) { - const verificationMethodId = `${did}#verkey` - - const builder = new DidDocumentBuilder(did) - .addContext('https://w3id.org/security/suites/ed25519-2018/v1') - .addVerificationMethod({ - controller: did, - id: verificationMethodId, - publicKeyBase58, - type: 'Ed25519VerificationKey2018', - }) - .addAuthentication(verificationMethodId) - - return builder -} - -export function createKeyAgreementKey(verkey: string) { - return TypedArrayEncoder.toBase58(convertPublicKeyToX25519(TypedArrayEncoder.fromBase58(verkey))) -} - -/** - * Fetches the verification key for a given did:indy did and returns the key as a {@link Key} object. - * - * @throws {@link AriesFrameworkError} if the did could not be resolved or the key could not be extracted - */ -export async function verificationKeyForIndyDid(agentContext: AgentContext, did: string) { - // FIXME: we should store the didDocument in the DidRecord so we don't have to fetch our own did - // from the ledger to know which key is associated with the did - const didsApi = agentContext.dependencyManager.resolve(DidsApi) - const didResult = await didsApi.resolve(did) - - if (!didResult.didDocument) { - throw new AriesFrameworkError( - `Could not resolve did ${did}. ${didResult.didResolutionMetadata.error} ${didResult.didResolutionMetadata.message}` - ) - } - - // did:indy dids MUST have a verificationMethod with #verkey - const verificationMethod = didResult.didDocument.dereferenceKey(`${did}#verkey`) - const key = getKeyFromVerificationMethod(verificationMethod) - - return key -} diff --git a/packages/indy-sdk/src/dids/didSovUtil.ts b/packages/indy-sdk/src/dids/didSovUtil.ts deleted file mode 100644 index e98e02a3f6..0000000000 --- a/packages/indy-sdk/src/dids/didSovUtil.ts +++ /dev/null @@ -1,138 +0,0 @@ -import { - TypedArrayEncoder, - DidDocumentService, - DidDocumentBuilder, - DidCommV1Service, - DidCommV2Service, - convertPublicKeyToX25519, -} from '@credo-ts/core' - -import { getFullVerkey } from '../utils/did' - -export type DidCommServicesEndpointType = 'endpoint' | 'did-communication' | 'DIDComm' - -export interface IndyEndpointAttrib { - endpoint?: string - types?: Array<'endpoint' | 'did-communication' | 'DIDComm'> - routingKeys?: string[] - [key: string]: unknown -} - -/** - * Get a base did:sov did document based on the provided did and verkey - * https://sovrin-foundation.github.io/sovrin/spec/did-method-spec-template.html#crud-operation-definitions - */ -export function sovDidDocumentFromDid(fullDid: string, verkey: string) { - const verificationMethodId = `${fullDid}#key-1` - const keyAgreementId = `${fullDid}#key-agreement-1` - - const publicKeyBase58 = getFullVerkey(fullDid, verkey) - const publicKeyX25519 = TypedArrayEncoder.toBase58( - convertPublicKeyToX25519(TypedArrayEncoder.fromBase58(publicKeyBase58)) - ) - - const builder = new DidDocumentBuilder(fullDid) - .addContext('https://w3id.org/security/suites/ed25519-2018/v1') - .addContext('https://w3id.org/security/suites/x25519-2019/v1') - .addVerificationMethod({ - controller: fullDid, - id: verificationMethodId, - publicKeyBase58: publicKeyBase58, - type: 'Ed25519VerificationKey2018', - }) - .addVerificationMethod({ - controller: fullDid, - id: keyAgreementId, - publicKeyBase58: publicKeyX25519, - type: 'X25519KeyAgreementKey2019', - }) - .addAuthentication(verificationMethodId) - .addAssertionMethod(verificationMethodId) - .addKeyAgreement(keyAgreementId) - - return builder -} - -// Process Indy Attrib Endpoint Types according to: https://sovrin-foundation.github.io/sovrin/spec/did-method-spec-template.html > Read (Resolve) > DID Service Endpoint -function processEndpointTypes(types?: string[]) { - const expectedTypes = ['endpoint', 'did-communication', 'DIDComm'] - const defaultTypes = ['endpoint', 'did-communication'] - - // Return default types if types "is NOT present [or] empty" - if (!types || types.length <= 0) { - return defaultTypes - } - - // Return default types if types "contain any other values" - for (const type of types) { - if (!expectedTypes.includes(type)) { - return defaultTypes - } - } - - // Return provided types - return types -} - -export function addServicesFromEndpointsAttrib( - builder: DidDocumentBuilder, - did: string, - endpoints: IndyEndpointAttrib, - keyAgreementId: string -) { - const { endpoint, routingKeys, types, ...otherEndpoints } = endpoints - - if (endpoint) { - const processedTypes = processEndpointTypes(types) - - // If 'endpoint' included in types, add id to the services array - if (processedTypes.includes('endpoint')) { - builder.addService( - new DidDocumentService({ - id: `${did}#endpoint`, - serviceEndpoint: endpoint, - type: 'endpoint', - }) - ) - } - - // If 'did-communication' included in types, add DIDComm v1 entry - if (processedTypes.includes('did-communication')) { - builder.addService( - new DidCommV1Service({ - id: `${did}#did-communication`, - serviceEndpoint: endpoint, - priority: 0, - routingKeys: routingKeys ?? [], - recipientKeys: [keyAgreementId], - accept: ['didcomm/aip2;env=rfc19'], - }) - ) - - // If 'DIDComm' included in types, add DIDComm v2 entry - if (processedTypes.includes('DIDComm')) { - builder - .addService( - new DidCommV2Service({ - id: `${did}#didcomm-1`, - serviceEndpoint: endpoint, - routingKeys: routingKeys ?? [], - accept: ['didcomm/v2'], - }) - ) - .addContext('https://didcomm.org/messaging/contexts/v2') - } - } - } - - // Add other endpoint types - for (const [type, endpoint] of Object.entries(otherEndpoints)) { - builder.addService( - new DidDocumentService({ - id: `${did}#${type}`, - serviceEndpoint: endpoint as string, - type, - }) - ) - } -} diff --git a/packages/indy-sdk/src/dids/index.ts b/packages/indy-sdk/src/dids/index.ts deleted file mode 100644 index 8017bf8749..0000000000 --- a/packages/indy-sdk/src/dids/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export { IndySdkIndyDidRegistrar, IndySdkIndyDidCreateOptions } from './IndySdkIndyDidRegistrar' -export { IndySdkSovDidResolver } from './IndySdkSovDidResolver' -export { IndySdkIndyDidResolver } from './IndySdkIndyDidResolver' diff --git a/packages/indy-sdk/src/error/IndySdkError.ts b/packages/indy-sdk/src/error/IndySdkError.ts deleted file mode 100644 index 9720b5347a..0000000000 --- a/packages/indy-sdk/src/error/IndySdkError.ts +++ /dev/null @@ -1,11 +0,0 @@ -import type { IndyError } from './indyError' - -import { AriesFrameworkError } from '@credo-ts/core' - -export class IndySdkError extends AriesFrameworkError { - public constructor(indyError: IndyError, message?: string) { - const base = `${indyError.name}(${indyError.indyName}): ${indyError.message}` - - super(message ? `${message}: ${base}` : base, { cause: indyError }) - } -} diff --git a/packages/indy-sdk/src/error/index.ts b/packages/indy-sdk/src/error/index.ts deleted file mode 100644 index 5829a46d0a..0000000000 --- a/packages/indy-sdk/src/error/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './IndySdkError' -export * from './indyError' diff --git a/packages/indy-sdk/src/error/indyError.ts b/packages/indy-sdk/src/error/indyError.ts deleted file mode 100644 index b253cf4e05..0000000000 --- a/packages/indy-sdk/src/error/indyError.ts +++ /dev/null @@ -1,100 +0,0 @@ -import { AriesFrameworkError } from '@credo-ts/core' - -export const indyErrors = { - 100: 'CommonInvalidParam1', - 101: 'CommonInvalidParam2', - 102: 'CommonInvalidParam3', - 103: 'CommonInvalidParam4', - 104: 'CommonInvalidParam5', - 105: 'CommonInvalidParam6', - 106: 'CommonInvalidParam7', - 107: 'CommonInvalidParam8', - 108: 'CommonInvalidParam9', - 109: 'CommonInvalidParam10', - 110: 'CommonInvalidParam11', - 111: 'CommonInvalidParam12', - 112: 'CommonInvalidState', - 113: 'CommonInvalidStructure', - 114: 'CommonIOError', - 115: 'CommonInvalidParam13', - 116: 'CommonInvalidParam14', - 200: 'WalletInvalidHandle', - 201: 'WalletUnknownTypeError', - 202: 'WalletTypeAlreadyRegisteredError', - 203: 'WalletAlreadyExistsError', - 204: 'WalletNotFoundError', - 205: 'WalletIncompatiblePoolError', - 206: 'WalletAlreadyOpenedError', - 207: 'WalletAccessFailed', - 208: 'WalletInputError', - 209: 'WalletDecodingError', - 210: 'WalletStorageError', - 211: 'WalletEncryptionError', - 212: 'WalletItemNotFound', - 213: 'WalletItemAlreadyExists', - 214: 'WalletQueryError', - 300: 'PoolLedgerNotCreatedError', - 301: 'PoolLedgerInvalidPoolHandle', - 302: 'PoolLedgerTerminated', - 303: 'LedgerNoConsensusError', - 304: 'LedgerInvalidTransaction', - 305: 'LedgerSecurityError', - 306: 'PoolLedgerConfigAlreadyExistsError', - 307: 'PoolLedgerTimeout', - 308: 'PoolIncompatibleProtocolVersion', - 309: 'LedgerNotFound', - 400: 'AnoncredsRevocationRegistryFullError', - 401: 'AnoncredsInvalidUserRevocId', - 404: 'AnoncredsMasterSecretDuplicateNameError', - 405: 'AnoncredsProofRejected', - 406: 'AnoncredsCredentialRevoked', - 407: 'AnoncredsCredDefAlreadyExistsError', - 500: 'UnknownCryptoTypeError', - 600: 'DidAlreadyExistsError', - 700: 'PaymentUnknownMethodError', - 701: 'PaymentIncompatibleMethodsError', - 702: 'PaymentInsufficientFundsError', - 703: 'PaymentSourceDoesNotExistError', - 704: 'PaymentOperationNotSupportedError', - 705: 'PaymentExtraFundsError', - 706: 'TransactionNotAllowedError', -} as const - -type IndyErrorValues = (typeof indyErrors)[keyof typeof indyErrors] - -export interface IndyError { - name: 'IndyError' - message: string - indyName?: string -} - -// eslint-disable-next-line @typescript-eslint/no-explicit-any -export function isIndyError(error: any, errorName?: IndyErrorValues): error is IndyError { - if (typeof error !== 'object' || error === null) return false - - const indyError = error.name === 'IndyError' - - // if no specific indy error name is passed - // or the error is no indy error - // we can already return - if (!indyError || !errorName) return indyError - - // NodeJS Wrapper is missing some type names. When a type is missing it will - // only have the error code as string in the message field - // Until that is fixed we take that into account to make Credo work with rn-indy-sdk - // See: https://github.com/AbsaOSS/rn-indy-sdk/pull/24 - // See: https://github.com/hyperledger/indy-sdk/pull/2283 - if (!error.indyName) { - const errorCode = Number(error.message) - if (!isNaN(errorCode) && Object.prototype.hasOwnProperty.call(indyErrors, errorCode)) { - // We already check if the property is set. We can safely ignore this typescript error - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - return errorName === indyErrors[errorCode] - } - - throw new AriesFrameworkError(`Could not determine errorName of indyError ${error.message}`) - } - - return error.indyName === errorName -} diff --git a/packages/indy-sdk/src/index.ts b/packages/indy-sdk/src/index.ts deleted file mode 100644 index 5857f00da2..0000000000 --- a/packages/indy-sdk/src/index.ts +++ /dev/null @@ -1,23 +0,0 @@ -// Dids -export * from './dids' - -// Ledger -export { IndySdkPoolConfig } from './ledger' - -// Wallet -export { IndySdkWallet } from './wallet' - -// Storage -export { IndySdkStorageService } from './storage' - -// AnonCreds -export { - IndySdkAnonCredsRegistry, - IndySdkHolderService, - IndySdkIssuerService, - IndySdkVerifierService, -} from './anoncreds' - -// Module -export { IndySdkModule } from './IndySdkModule' -export { IndySdkModuleConfig } from './IndySdkModuleConfig' diff --git a/packages/indy-sdk/src/ledger/IndySdkPool.ts b/packages/indy-sdk/src/ledger/IndySdkPool.ts deleted file mode 100644 index abd8a138aa..0000000000 --- a/packages/indy-sdk/src/ledger/IndySdkPool.ts +++ /dev/null @@ -1,218 +0,0 @@ -import type { IndySdk } from '../types' -import type { FileSystem, Logger } from '@credo-ts/core' -import type { LedgerReadReplyResponse, LedgerRequest, LedgerWriteReplyResponse } from 'indy-sdk' -import type { Subject } from 'rxjs' - -import { AriesFrameworkError } from '@credo-ts/core' - -import { isIndyError, IndySdkError } from '../error' - -import { IndySdkPoolError } from './error' -import { isLedgerRejectResponse, isLedgerReqnackResponse } from './util' - -export interface TransactionAuthorAgreement { - version: `${number}.${number}` | `${number}` - acceptanceMechanism: string -} - -export interface IndySdkPoolConfig { - /** - * Optional id that influences the pool config that is created by the indy-sdk. - * Uses the indyNamespace as the pool identifier if not provided. - */ - id?: string - - genesisPath?: string - genesisTransactions?: string - - isProduction: boolean - indyNamespace: string - transactionAuthorAgreement?: TransactionAuthorAgreement - connectOnStartup?: boolean -} - -export class IndySdkPool { - private indySdk: IndySdk - private logger: Logger - private fileSystem: FileSystem - private poolConfig: IndySdkPoolConfig - private _poolHandle?: number - private poolConnected?: Promise - public authorAgreement?: AuthorAgreement | null - - public constructor( - poolConfig: IndySdkPoolConfig, - indySdk: IndySdk, - logger: Logger, - stop$: Subject, - fileSystem: FileSystem - ) { - this.indySdk = indySdk - this.fileSystem = fileSystem - this.poolConfig = poolConfig - this.logger = logger - - // Listen to stop$ (shutdown) and close pool - stop$.subscribe(async () => { - if (this._poolHandle) { - await this.close() - } - }) - } - - public get didIndyNamespace(): string { - return this.config.indyNamespace - } - - public get id() { - return this.poolConfig.id - } - - public get config() { - return this.poolConfig - } - - public async close() { - const poolHandle = this._poolHandle - - if (!poolHandle) { - return - } - - this._poolHandle = undefined - this.poolConnected = undefined - - await this.indySdk.closePoolLedger(poolHandle) - } - - public async delete() { - // Close the pool if currently open - if (this._poolHandle) { - await this.close() - } - - await this.indySdk.deletePoolLedgerConfig(this.poolConfig.indyNamespace) - } - - public async connect() { - if (!this.poolConnected) { - // Save the promise of connectToLedger to determine if we are done connecting - this.poolConnected = this.connectToLedger() - this.poolConnected.catch((error) => { - // Set poolConnected to undefined so we can retry connection upon failure - this.poolConnected = undefined - this.logger.error('Connection to pool: ' + this.poolConfig.genesisPath + ' failed.', { error }) - }) - return this.poolConnected - } else { - throw new AriesFrameworkError('Cannot attempt connection to ledger, already connecting.') - } - } - - private async connectToLedger() { - const poolName = this.poolConfig.id ?? this.poolConfig.indyNamespace - const genesisPath = await this.getGenesisPath() - - if (!genesisPath) { - throw new AriesFrameworkError('Cannot connect to ledger without genesis file') - } - - this.logger.debug(`Connecting to ledger pool '${poolName}'`, { genesisPath }) - await this.indySdk.setProtocolVersion(2) - - try { - this._poolHandle = await this.indySdk.openPoolLedger(poolName) - return - } catch (error) { - if (!isIndyError(error, 'PoolLedgerNotCreatedError')) { - throw isIndyError(error) ? new IndySdkError(error) : error - } - } - - this.logger.debug(`Pool '${poolName}' does not exist yet, creating.`, { - indyError: 'PoolLedgerNotCreatedError', - }) - try { - await this.indySdk.createPoolLedgerConfig(poolName, { genesis_txn: genesisPath }) - this._poolHandle = await this.indySdk.openPoolLedger(poolName) - return - } catch (error) { - throw isIndyError(error) ? new IndySdkError(error) : error - } - } - - private async submitRequest(request: LedgerRequest) { - return this.indySdk.submitRequest(await this.getPoolHandle(), request) - } - - public async submitReadRequest(request: LedgerRequest) { - const response = await this.submitRequest(request) - - if (isLedgerRejectResponse(response) || isLedgerReqnackResponse(response)) { - throw new IndySdkPoolError( - `Ledger '${this.didIndyNamespace}' rejected read transaction request: ${response.reason}` - ) - } - - return response as LedgerReadReplyResponse - } - - public async submitWriteRequest(request: LedgerRequest) { - const response = await this.submitRequest(request) - - if (isLedgerRejectResponse(response) || isLedgerReqnackResponse(response)) { - throw new IndySdkPoolError( - `Ledger '${this.didIndyNamespace}' rejected write transaction request: ${response.reason}` - ) - } - - return response as LedgerWriteReplyResponse - } - - private async getPoolHandle() { - if (this.poolConnected) { - // If we have tried to already connect to pool wait for it - try { - await this.poolConnected - } catch (error) { - this.logger.error('Connection to pool: ' + this.poolConfig.genesisPath + ' failed.', { error }) - } - } - - if (!this._poolHandle) await this.connect() - if (!this._poolHandle) throw new IndySdkPoolError('Pool handle not set after connection') - - return this._poolHandle - } - - private async getGenesisPath() { - // If the path is already provided return it - if (this.poolConfig.genesisPath) return this.poolConfig.genesisPath - - // Determine the genesisPath - const genesisPath = this.fileSystem.tempPath + `/genesis-${this.poolConfig.id ?? this.poolConfig.indyNamespace}.txn` - // Store genesis data if provided - if (this.poolConfig.genesisTransactions) { - await this.fileSystem.write(genesisPath, this.poolConfig.genesisTransactions) - this.poolConfig.genesisPath = genesisPath - return genesisPath - } - - // No genesisPath - return null - } -} - -export interface AuthorAgreement { - digest: string - version: string - text: string - ratification_ts: number - acceptanceMechanisms: AcceptanceMechanisms -} - -export interface AcceptanceMechanisms { - aml: Record - amlContext: string - version: string -} diff --git a/packages/indy-sdk/src/ledger/IndySdkPoolService.ts b/packages/indy-sdk/src/ledger/IndySdkPoolService.ts deleted file mode 100644 index dc2ee2b292..0000000000 --- a/packages/indy-sdk/src/ledger/IndySdkPoolService.ts +++ /dev/null @@ -1,357 +0,0 @@ -import type { AcceptanceMechanisms, AuthorAgreement } from './IndySdkPool' -import type { IndySdk } from '../types' -import type { AgentContext, Key } from '@credo-ts/core' -import type { GetNymResponse, LedgerReadReplyResponse, LedgerRequest, LedgerWriteReplyResponse } from 'indy-sdk' - -import { didIndyRegex } from '@credo-ts/anoncreds' -import { - TypedArrayEncoder, - CacheModuleConfig, - InjectionSymbols, - Logger, - injectable, - inject, - FileSystem, -} from '@credo-ts/core' -import { Subject } from 'rxjs' - -import { IndySdkModuleConfig } from '../IndySdkModuleConfig' -import { IndySdkError, isIndyError } from '../error' -import { assertIndySdkWallet } from '../utils/assertIndySdkWallet' -import { isLegacySelfCertifiedDid } from '../utils/did' -import { allSettled, onlyFulfilled, onlyRejected } from '../utils/promises' - -import { IndySdkPool } from './IndySdkPool' -import { IndySdkPoolError, IndySdkPoolNotConfiguredError, IndySdkPoolNotFoundError } from './error' -import { serializeRequestForSignature } from './serializeRequestForSignature' - -export interface CachedDidResponse { - nymResponse: GetNymResponse - indyNamespace: string -} - -@injectable() -export class IndySdkPoolService { - public pools: IndySdkPool[] = [] - private logger: Logger - private indySdk: IndySdk - private stop$: Subject - private fileSystem: FileSystem - private indySdkModuleConfig: IndySdkModuleConfig - - public constructor( - @inject(InjectionSymbols.Logger) logger: Logger, - @inject(InjectionSymbols.Stop$) stop$: Subject, - @inject(InjectionSymbols.FileSystem) fileSystem: FileSystem, - indySdkModuleConfig: IndySdkModuleConfig - ) { - this.logger = logger - this.indySdk = indySdkModuleConfig.indySdk - this.fileSystem = fileSystem - this.stop$ = stop$ - this.indySdkModuleConfig = indySdkModuleConfig - - this.pools = this.indySdkModuleConfig.networks.map( - (network) => new IndySdkPool(network, this.indySdk, this.logger, this.stop$, this.fileSystem) - ) - } - - /** - * Get the most appropriate pool for the given did. - * If the did is a qualified indy did, the pool will be determined based on the namespace. - * If it is a legacy unqualified indy did, the pool will be determined based on the algorithm as described in this document: - * https://docs.google.com/document/d/109C_eMsuZnTnYe2OAd02jAts1vC4axwEKIq7_4dnNVA/edit - * - * This method will optionally return a nym response when the did has been resolved to determine the ledger - * either now or in the past. The nymResponse can be used to prevent multiple ledger queries fetching the same - * did - */ - public async getPoolForDid( - agentContext: AgentContext, - did: string - ): Promise<{ pool: IndySdkPool; nymResponse?: GetNymResponse }> { - // Check if the did starts with did:indy - const match = did.match(didIndyRegex) - - if (match) { - const [, namespace] = match - - const pool = this.getPoolForNamespace(namespace) - - if (pool) return { pool } - - throw new IndySdkPoolError(`Pool for indy namespace '${namespace}' not found`) - } else { - return await this.getPoolForLegacyDid(agentContext, did) - } - } - - private async getPoolForLegacyDid( - agentContext: AgentContext, - did: string - ): Promise<{ pool: IndySdkPool; nymResponse: GetNymResponse }> { - const pools = this.pools - - if (pools.length === 0) { - throw new IndySdkPoolNotConfiguredError( - 'No indy ledgers configured. Provide at least one pool configuration in IndySdkModuleConfigOptions.networks' - ) - } - - const cache = agentContext.dependencyManager.resolve(CacheModuleConfig).cache - const cacheKey = `IndySdkPoolService:${did}` - - const cachedNymResponse = await cache.get(agentContext, cacheKey) - const pool = this.pools.find((pool) => pool.didIndyNamespace === cachedNymResponse?.indyNamespace) - - // If we have the nym response with associated pool in the cache, we'll use that - if (cachedNymResponse && pool) { - this.logger.trace(`Found ledger '${pool.didIndyNamespace}' for did '${did}' in cache`) - return { nymResponse: cachedNymResponse.nymResponse, pool } - } - - const { successful, rejected } = await this.getSettledDidResponsesFromPools(did, pools) - - if (successful.length === 0) { - const allNotFound = rejected.every((e) => e.reason instanceof IndySdkPoolNotFoundError) - const rejectedOtherThanNotFound = rejected.filter((e) => !(e.reason instanceof IndySdkPoolNotFoundError)) - - // All ledgers returned response that the did was not found - if (allNotFound) { - throw new IndySdkPoolNotFoundError(`Did '${did}' not found on any of the ledgers (total ${this.pools.length}).`) - } - - // one or more of the ledgers returned an unknown error - throw new IndySdkPoolError( - `Unknown error retrieving did '${did}' from '${rejectedOtherThanNotFound.length}' of '${pools.length}' ledgers. ${rejectedOtherThanNotFound[0].reason}`, - { cause: rejectedOtherThanNotFound[0].reason } - ) - } - - // If there are self certified DIDs we always prefer it over non self certified DIDs - // We take the first self certifying DID as we take the order in the - // IndySdkModuleConfigOptions.networks config as the order of preference of ledgers - let value = successful.find((response) => - isLegacySelfCertifiedDid(response.value.did.did, response.value.did.verkey) - )?.value - - if (!value) { - // Split between production and nonProduction ledgers. If there is at least one - // successful response from a production ledger, only keep production ledgers - // otherwise we only keep the non production ledgers. - const production = successful.filter((s) => s.value.pool.config.isProduction) - const nonProduction = successful.filter((s) => !s.value.pool.config.isProduction) - const productionOrNonProduction = production.length >= 1 ? production : nonProduction - - // We take the first value as we take the order in the IndySdkModuleConfigOptions.networks - // config as the order of preference of ledgers - value = productionOrNonProduction[0].value - } - - await cache.set(agentContext, cacheKey, { - nymResponse: value.did, - indyNamespace: value.pool.didIndyNamespace, - } satisfies CachedDidResponse) - - return { pool: value.pool, nymResponse: value.did } - } - - private async getSettledDidResponsesFromPools(did: string, pools: IndySdkPool[]) { - this.logger.trace(`Retrieving did '${did}' from ${pools.length} ledgers`) - const didResponses = await allSettled(pools.map((pool) => this.getDidFromPool(did, pool))) - - const successful = onlyFulfilled(didResponses) - this.logger.trace(`Retrieved ${successful.length} responses from ledgers for did '${did}'`) - - const rejected = onlyRejected(didResponses) - - return { - rejected, - successful, - } - } - - /** - * Get the most appropriate pool for the given indyNamespace - */ - public getPoolForNamespace(indyNamespace?: string) { - if (this.pools.length === 0) { - throw new IndySdkPoolNotConfiguredError( - 'No indy ledgers configured. Provide at least one pool configuration in IndySdkModuleConfigOptions.networks' - ) - } - - if (!indyNamespace) { - this.logger.warn('Not passing the indyNamespace is deprecated and will be removed in the future version.') - return this.pools[0] - } - - const pool = this.pools.find((pool) => pool.didIndyNamespace === indyNamespace) - - if (!pool) { - throw new IndySdkPoolNotFoundError(`No ledgers found for indy namespace '${indyNamespace}'.`) - } - - return pool - } - - public async submitWriteRequest( - agentContext: AgentContext, - pool: IndySdkPool, - request: LedgerRequest, - signingKey: Key - ): Promise { - try { - const requestWithTaa = await this.appendTaa(pool, request) - const signedRequestWithTaa = await this.signRequest(agentContext, signingKey, requestWithTaa) - - const response = await pool.submitWriteRequest(signedRequestWithTaa) - - return response - } catch (error) { - throw isIndyError(error) ? new IndySdkError(error) : error - } - } - - public async submitReadRequest(pool: IndySdkPool, request: LedgerRequest): Promise { - try { - const response = await pool.submitReadRequest(request) - - return response - } catch (error) { - throw isIndyError(error) ? new IndySdkError(error) : error - } - } - - private async signRequest(agentContext: AgentContext, key: Key, request: LedgerRequest): Promise { - assertIndySdkWallet(agentContext.wallet) - - try { - const signedPayload = await this.indySdk.cryptoSign( - agentContext.wallet.handle, - key.publicKeyBase58, - TypedArrayEncoder.fromString(serializeRequestForSignature(request)) - ) - - const signedRequest = { ...request, signature: TypedArrayEncoder.toBase58(signedPayload) } - return signedRequest - } catch (error) { - throw isIndyError(error) ? new IndySdkError(error) : error - } - } - - private async appendTaa(pool: IndySdkPool, request: LedgerRequest) { - try { - const authorAgreement = await this.getTransactionAuthorAgreement(pool) - const taa = pool.config.transactionAuthorAgreement - - // If ledger does not have TAA, we can just send request - if (authorAgreement == null) { - return request - } - // Ledger has taa but user has not specified which one to use - if (!taa) { - throw new IndySdkPoolError( - `Please, specify a transaction author agreement with version and acceptance mechanism. ${JSON.stringify( - authorAgreement - )}` - ) - } - - // Throw an error if the pool doesn't have the specified version and acceptance mechanism - if ( - authorAgreement.version !== taa.version || - !(taa.acceptanceMechanism in authorAgreement.acceptanceMechanisms.aml) - ) { - // Throw an error with a helpful message - const errMessage = `Unable to satisfy matching TAA with mechanism ${JSON.stringify( - taa.acceptanceMechanism - )} and version ${JSON.stringify(taa.version)} in pool.\n Found ${JSON.stringify( - Object.keys(authorAgreement.acceptanceMechanisms.aml) - )} and version ${authorAgreement.version} in pool.` - throw new IndySdkPoolError(errMessage) - } - - const requestWithTaa = await this.indySdk.appendTxnAuthorAgreementAcceptanceToRequest( - request, - authorAgreement.text, - taa.version, - authorAgreement.digest, - taa.acceptanceMechanism, - // Current time since epoch - // We can't use ratification_ts, as it must be greater than 1499906902 - Math.floor(new Date().getTime() / 1000) - ) - - return requestWithTaa - } catch (error) { - throw isIndyError(error) ? new IndySdkError(error) : error - } - } - - private async getTransactionAuthorAgreement(pool: IndySdkPool): Promise { - try { - // TODO Replace this condition with memoization - if (pool.authorAgreement !== undefined) { - return pool.authorAgreement - } - - const taaRequest = await this.indySdk.buildGetTxnAuthorAgreementRequest(null) - const taaResponse = await this.submitReadRequest(pool, taaRequest) - const acceptanceMechanismRequest = await this.indySdk.buildGetAcceptanceMechanismsRequest(null) - const acceptanceMechanismResponse = await this.submitReadRequest(pool, acceptanceMechanismRequest) - - // TAA can be null - if (taaResponse.result.data == null) { - pool.authorAgreement = null - return null - } - - // If TAA is not null, we can be sure AcceptanceMechanisms is also not null - const authorAgreement = taaResponse.result.data as AuthorAgreement - const acceptanceMechanisms = acceptanceMechanismResponse.result.data as AcceptanceMechanisms - pool.authorAgreement = { - ...authorAgreement, - acceptanceMechanisms, - } - return pool.authorAgreement - } catch (error) { - throw isIndyError(error) ? new IndySdkError(error) : error - } - } - - private async getDidFromPool(did: string, pool: IndySdkPool): Promise { - try { - this.logger.trace(`Get public did '${did}' from ledger '${pool.didIndyNamespace}'`) - const request = await this.indySdk.buildGetNymRequest(null, did) - - this.logger.trace(`Submitting get did request for did '${did}' to ledger '${pool.didIndyNamespace}'`) - const response = await pool.submitReadRequest(request) - - const result = await this.indySdk.parseGetNymResponse(response) - this.logger.trace(`Retrieved did '${did}' from ledger '${pool.didIndyNamespace}'`, result) - - return { - did: result, - pool, - response, - } - } catch (error) { - this.logger.trace(`Error retrieving did '${did}' from ledger '${pool.didIndyNamespace}'`, { - error, - did, - }) - if (isIndyError(error, 'LedgerNotFound')) { - throw new IndySdkPoolNotFoundError(`Did '${did}' not found on ledger ${pool.didIndyNamespace}`) - } else { - throw isIndyError(error) ? new IndySdkError(error) : error - } - } - } -} - -export interface PublicDidRequest { - did: GetNymResponse - pool: IndySdkPool - response: LedgerReadReplyResponse -} diff --git a/packages/indy-sdk/src/ledger/__tests__/IndySdkPoolService.test.ts b/packages/indy-sdk/src/ledger/__tests__/IndySdkPoolService.test.ts deleted file mode 100644 index f7b489c21d..0000000000 --- a/packages/indy-sdk/src/ledger/__tests__/IndySdkPoolService.test.ts +++ /dev/null @@ -1,422 +0,0 @@ -import type { IndySdkPoolConfig } from '../IndySdkPool' -import type { CachedDidResponse } from '../IndySdkPoolService' - -import { - CacheModuleConfig, - InMemoryLruCache, - SigningProviderRegistry, - AriesFrameworkError, - Key, - KeyType, -} from '@credo-ts/core' -import indySdk from 'indy-sdk' -import { Subject } from 'rxjs' - -import { getAgentConfig, getAgentContext } from '../../../../core/tests/helpers' -import { NodeFileSystem } from '../../../../node/src/NodeFileSystem' -import { IndySdkModuleConfig } from '../../IndySdkModuleConfig' -import { IndySdkWallet } from '../../wallet/IndySdkWallet' -import { IndySdkPoolService } from '../IndySdkPoolService' -import { IndySdkPoolError, IndySdkPoolNotConfiguredError, IndySdkPoolNotFoundError } from '../error' - -import { getDidResponsesForDid } from './didResponses' - -const pools: IndySdkPoolConfig[] = [ - { - indyNamespace: 'sovrin', - isProduction: true, - genesisTransactions: 'xxx', - transactionAuthorAgreement: { version: '1', acceptanceMechanism: 'accept' }, - }, - { - indyNamespace: 'sovrin:builder', - isProduction: false, - genesisTransactions: 'xxx', - transactionAuthorAgreement: { version: '1', acceptanceMechanism: 'accept' }, - }, - { - indyNamespace: 'sovrin:staging', - isProduction: false, - genesisTransactions: 'xxx', - transactionAuthorAgreement: { version: '1', acceptanceMechanism: 'accept' }, - }, - { - indyNamespace: 'indicio', - isProduction: true, - genesisTransactions: 'xxx', - transactionAuthorAgreement: { version: '1', acceptanceMechanism: 'accept' }, - }, - { - indyNamespace: 'bcovrin:test', - isProduction: false, - genesisTransactions: 'xxx', - transactionAuthorAgreement: { version: '1', acceptanceMechanism: 'accept' }, - }, -] - -const config = getAgentConfig('IndySdkPoolServiceTest') -const cache = new InMemoryLruCache({ limit: 1 }) - -const indySdkModule = new IndySdkModuleConfig({ indySdk, networks: pools }) -const wallet = new IndySdkWallet(indySdk, config.logger, new SigningProviderRegistry([])) - -const agentContext = getAgentContext({ - wallet, - registerInstances: [[CacheModuleConfig, new CacheModuleConfig({ cache })]], -}) - -const poolService = new IndySdkPoolService(config.logger, new Subject(), new NodeFileSystem(), indySdkModule) - -describe('IndySdkPoolService', () => { - beforeAll(async () => { - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - await wallet.createAndOpen(config.walletConfig!) - }) - - afterAll(async () => { - await wallet.delete() - }) - - afterEach(() => { - cache.clear() - }) - - describe('getPoolForDid', () => { - it('should throw a IndySdkPoolNotConfiguredError error if no pools are configured on the pool service', async () => { - const oldPools = poolService.pools - poolService.pools = [] - - expect(poolService.getPoolForDid(agentContext, 'some-did')).rejects.toThrow(IndySdkPoolNotConfiguredError) - - poolService.pools = oldPools - }) - - it('should throw a IndySdkPoolError if all ledger requests throw an error other than NotFoundError', async () => { - const did = 'Y5bj4SjCiTM9PgeheKAiXx' - - poolService.pools.forEach((pool) => { - const spy = jest.spyOn(pool, 'submitReadRequest') - spy.mockImplementationOnce(() => Promise.reject(new AriesFrameworkError('Something went wrong'))) - }) - - expect(poolService.getPoolForDid(agentContext, did)).rejects.toThrowError(IndySdkPoolError) - }) - - it('should throw a IndySdkPoolNotFoundError if all pools did not find the did on the ledger', async () => { - const did = 'Y5bj4SjCiTM9PgeheKAiXx' - // Not found on any of the ledgers - const responses = getDidResponsesForDid(did, pools, {}) - - poolService.pools.forEach((pool, index) => { - const spy = jest.spyOn(pool, 'submitReadRequest') - spy.mockImplementationOnce(responses[index]) - }) - - expect(poolService.getPoolForDid(agentContext, did)).rejects.toThrowError(IndySdkPoolNotFoundError) - }) - - it('should return the pool based on namespace if did is a valid did:indy did', async () => { - const { pool } = await poolService.getPoolForDid(agentContext, 'did:indy:sovrin:Y5bj4SjCiTM9PgeheKAiXx') - - expect(pool.didIndyNamespace).toBe('sovrin') - }) - - it('should return the pool if the did was only found on one ledger', async () => { - const did = 'TL1EaPFCZ8Si5aUrqScBDt' - // Only found on one ledger - const responses = getDidResponsesForDid(did, pools, { - sovrin: '~43X4NhAFqREffK7eWdKgFH', - }) - - poolService.pools.forEach((pool, index) => { - const spy = jest.spyOn(pool, 'submitReadRequest') - spy.mockImplementationOnce(responses[index]) - }) - - const { pool } = await poolService.getPoolForDid(agentContext, did) - - expect(pool.config.indyNamespace).toBe('sovrin') - }) - - it('should return the first pool with a self certifying DID if at least one did is self certifying ', async () => { - const did = 'did:sov:q7ATwTYbQDgiigVijUAej' - // Found on one production and one non production ledger - const responses = getDidResponsesForDid(did, pools, { - indicio: '~43X4NhAFqREffK7eWdKgFH', - 'bcovrin:test': '43X4NhAFqREffK7eWdKgFH43X4NhAFqREffK7eWdKgFH', - 'sovrin:builder': '~43X4NhAFqREffK7eWdKgFH', - }) - - poolService.pools.forEach((pool, index) => { - const spy = jest.spyOn(pool, 'submitReadRequest') - spy.mockImplementationOnce(responses[index]) - }) - - const { pool } = await poolService.getPoolForDid(agentContext, did) - - expect(pool.config.indyNamespace).toBe('sovrin:builder') - }) - - it('should return the production pool if the did was found on one production and one non production ledger and both DIDs are not self certifying', async () => { - const did = 'V6ty6ttM3EjuCtosH6sGtW' - // Found on one production and one non production ledger - const responses = getDidResponsesForDid(did, pools, { - indicio: '43X4NhAFqREffK7eWdKgFH43X4NhAFqREffK7eWdKgFH', - 'sovrin:builder': '43X4NhAFqREffK7eWdKgFH43X4NhAFqREffK7eWdKgFH', - }) - - poolService.pools.forEach((pool, index) => { - const spy = jest.spyOn(pool, 'submitReadRequest') - spy.mockImplementationOnce(responses[index]) - }) - - const { pool } = await poolService.getPoolForDid(agentContext, did) - - expect(pool.config.indyNamespace).toBe('indicio') - }) - - it('should return the pool with the self certified did if the did was found on two production ledgers where one did is self certified', async () => { - const did = 'VsKV7grR1BUE29mG2Fm2kX' - // Found on two production ledgers. Sovrin is self certified - const responses = getDidResponsesForDid(did, pools, { - sovrin: '~43X4NhAFqREffK7eWdKgFH', - indicio: 'kqa2HyagzfMAq42H5f9u3UMwnSBPQx2QfrSyXbUPxMn', - }) - - poolService.pools.forEach((pool, index) => { - const spy = jest.spyOn(pool, 'submitReadRequest') - spy.mockImplementationOnce(responses[index]) - }) - - const { pool } = await poolService.getPoolForDid(agentContext, did) - - expect(pool.config.indyNamespace).toBe('sovrin') - }) - - it('should return the first pool with a self certified did if the did was found on three non production ledgers where two DIDs are self certified', async () => { - const did = 'HEi9QViXNThGQaDsQ3ptcw' - // Found on two non production ledgers. Sovrin is self certified - const responses = getDidResponsesForDid(did, pools, { - 'sovrin:builder': '~M9kv2Ez61cur7X39DXWh8W', - 'sovrin:staging': '~M9kv2Ez61cur7X39DXWh8W', - 'bcovrin:test': '3SeuRm3uYuQDYmHeuMLu1xNHozNTtzS3kbZRFMMCWrX4', - }) - - poolService.pools.forEach((pool, index) => { - const spy = jest.spyOn(pool, 'submitReadRequest') - spy.mockImplementationOnce(responses[index]) - }) - - const { pool } = await poolService.getPoolForDid(agentContext, did) - - expect(pool.config.indyNamespace).toBe('sovrin:builder') - }) - - it('should return the pool from the cache if the did was found in the cache', async () => { - const did = 'HEi9QViXNThGQaDsQ3ptcw' - - const expectedPool = pools[3] - - const didResponse: CachedDidResponse = { - nymResponse: { - did, - role: 'ENDORSER', - verkey: '~M9kv2Ez61cur7X39DXWh8W', - }, - indyNamespace: expectedPool.indyNamespace, - } - - await cache.set(agentContext, `IndySdkPoolService:${did}`, didResponse) - const { pool } = await poolService.getPoolForDid(agentContext, did) - - expect(pool.config.indyNamespace).toBe(pool.didIndyNamespace) - }) - - it('should set the indyNamespace in the cache if the did was not found in the cache, but resolved later on', async () => { - const did = 'HEi9QViXNThGQaDsQ3ptcw' - // Found on one ledger - const responses = getDidResponsesForDid(did, pools, { - 'sovrin:builder': '~M9kv2Ez61cur7X39DXWh8W', - }) - - poolService.pools.forEach((pool, index) => { - const spy = jest.spyOn(pool, 'submitReadRequest') - spy.mockImplementationOnce(responses[index]) - }) - - const { pool } = await poolService.getPoolForDid(agentContext, did) - - expect(pool.config.indyNamespace).toBe('sovrin:builder') - expect(pool.config.indyNamespace).toBe('sovrin:builder') - - expect(await cache.get(agentContext, `IndySdkPoolService:${did}`)).toEqual({ - nymResponse: { - did, - verkey: '~M9kv2Ez61cur7X39DXWh8W', - role: '0', - }, - indyNamespace: 'sovrin:builder', - }) - }) - }) - - describe('getPoolForNamespace', () => { - it('should throw a IndySdkPoolNotConfiguredError error if no pools are configured on the pool service', async () => { - const oldPools = poolService.pools - poolService.pools = [] - - expect(() => poolService.getPoolForNamespace()).toThrow(IndySdkPoolNotConfiguredError) - - poolService.pools = oldPools - }) - - it('should return the first pool if indyNamespace is not provided', async () => { - const expectedPool = pools[0] - - expect(poolService.getPoolForNamespace().didIndyNamespace).toEqual(expectedPool.indyNamespace) - }) - - it('should throw a IndySdkPoolNotFoundError error if any of the pools did not have the provided indyNamespace', async () => { - const indyNameSpace = 'test' - const responses = pools.map((pool) => pool.indyNamespace) - - poolService.pools.forEach((pool, index) => { - const spy = jest.spyOn(pool, 'didIndyNamespace', 'get') - spy.mockReturnValueOnce(responses[index]) - }) - - expect(() => poolService.getPoolForNamespace(indyNameSpace)).toThrow(IndySdkPoolNotFoundError) - }) - - it('should return the first pool that indyNamespace matches', async () => { - const expectedPool = pools[3] - const indyNameSpace = 'indicio' - const responses = pools.map((pool) => pool.indyNamespace) - - poolService.pools.forEach((pool, index) => { - const spy = jest.spyOn(pool, 'didIndyNamespace', 'get') - spy.mockReturnValueOnce(responses[index]) - }) - - const pool = poolService.getPoolForNamespace(indyNameSpace) - - expect(pool.didIndyNamespace).toEqual(expectedPool.indyNamespace) - }) - }) - - describe('submitWriteRequest', () => { - it('should throw an error if the config version does not match', async () => { - const pool = poolService.getPoolForNamespace() - - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - jest.spyOn(poolService, 'getTransactionAuthorAgreement').mockResolvedValue({ - digest: 'abcde', - version: '2.0', - text: 'jhsdhbv', - ratification_ts: 12345678, - acceptanceMechanisms: { - aml: { accept: 'accept' }, - amlContext: 'accept', - version: '3', - }, - } as never) - await expect( - poolService.submitWriteRequest( - agentContext, - pool, - { - reqId: 1668174449192969000, - identifier: 'BBPoJqRKatdcfLEAFL7exC', - operation: { - type: '1', - dest: 'N8NQHLtCKfPmWMgCSdfa7h', - verkey: 'GAb4NUvpBcHVCvtP45vTVa5Bp74vFg3iXzdp1Gbd68Wf', - alias: 'Heinz57', - }, - protocolVersion: 2, - }, - Key.fromPublicKeyBase58('GAb4NUvpBcHVCvtP45vTVa5Bp74vFg3iXzdp1Gbd68Wf', KeyType.Ed25519) - ) - ).rejects.toThrowError( - 'Unable to satisfy matching TAA with mechanism "accept" and version "1" in pool.\n Found ["accept"] and version 2.0 in pool.' - ) - }) - - it('should throw an error if the config acceptance mechanism does not match', async () => { - const pool = poolService.getPoolForNamespace() - - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - jest.spyOn(poolService, 'getTransactionAuthorAgreement').mockResolvedValue({ - digest: 'abcde', - version: '1.0', - text: 'jhsdhbv', - ratification_ts: 12345678, - acceptanceMechanisms: { - aml: { decline: 'accept' }, - amlContext: 'accept', - version: '1', - }, - } as never) - await expect( - poolService.submitWriteRequest( - agentContext, - pool, - { - reqId: 1668174449192969000, - identifier: 'BBPoJqRKatdcfLEAFL7exC', - operation: { - type: '1', - dest: 'N8NQHLtCKfPmWMgCSdfa7h', - verkey: 'GAb4NUvpBcHVCvtP45vTVa5Bp74vFg3iXzdp1Gbd68Wf', - alias: 'Heinz57', - }, - protocolVersion: 2, - }, - Key.fromPublicKeyBase58('GAb4NUvpBcHVCvtP45vTVa5Bp74vFg3iXzdp1Gbd68Wf', KeyType.Ed25519) - ) - ).rejects.toThrowError( - 'Unable to satisfy matching TAA with mechanism "accept" and version "1" in pool.\n Found ["decline"] and version 1.0 in pool.' - ) - }) - - it('should throw an error if no config is present', async () => { - const pool = poolService.getPoolForNamespace() - pool.authorAgreement = undefined - pool.config.transactionAuthorAgreement = undefined - - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - jest.spyOn(poolService, 'getTransactionAuthorAgreement').mockResolvedValue({ - digest: 'abcde', - version: '1.0', - text: 'jhsdhbv', - ratification_ts: 12345678, - acceptanceMechanisms: { - aml: { accept: 'accept' }, - amlContext: 'accept', - version: '3', - }, - } as never) - await expect( - poolService.submitWriteRequest( - agentContext, - pool, - { - reqId: 1668174449192969000, - identifier: 'BBPoJqRKatdcfLEAFL7exC', - operation: { - type: '1', - dest: 'N8NQHLtCKfPmWMgCSdfa7h', - verkey: 'GAb4NUvpBcHVCvtP45vTVa5Bp74vFg3iXzdp1Gbd68Wf', - alias: 'Heinz57', - }, - protocolVersion: 2, - }, - Key.fromPublicKeyBase58('GAb4NUvpBcHVCvtP45vTVa5Bp74vFg3iXzdp1Gbd68Wf', KeyType.Ed25519) - ) - ).rejects.toThrowError(/Please, specify a transaction author agreement with version and acceptance mechanism/) - }) - }) -}) diff --git a/packages/indy-sdk/src/ledger/__tests__/didResponses.ts b/packages/indy-sdk/src/ledger/__tests__/didResponses.ts deleted file mode 100644 index 4d3dac6596..0000000000 --- a/packages/indy-sdk/src/ledger/__tests__/didResponses.ts +++ /dev/null @@ -1,58 +0,0 @@ -import type { IndySdkPoolConfig } from '../IndySdkPool' -import type * as Indy from 'indy-sdk' - -// eslint-disable-next-line @typescript-eslint/ban-ts-comment -// @ts-ignore -// eslint-disable-next-line import/no-extraneous-dependencies -import IndyError from 'indy-sdk/src/IndyError' - -export function getDidResponse({ did, verkey }: { did: string; verkey: string }) { - const response: Indy.LedgerReadReplyResponse = { - op: 'REPLY', - result: { - txnTime: 1632680963, - reqId: 1632681194706196000, - state_proof: { - multi_signature: { - participants: ['Node3', 'Node4', 'Node2'], - value: { - state_root_hash: 'AqMNuzJHeHduhggd8URobGyc1W89oGEjmohRXkB66JZo', - ledger_id: 1, - pool_state_root_hash: 'NCGqbfRWDWtLB2bDuL6TC5BhrRdQMc5MyKdXQqXii44', - timestamp: 1632680963, - txn_root_hash: 'AxqfyyDFuY74kiXcfvkYCWCVrHsrQutKaoi3ao4Vp8K7', - }, - signature: - 'QwkoPr9pwXyBdtMMUtJ841QjX3pTEQP6bumBpHCWiBCn4AduEW55SQXHjfQZd7EXEjArMfjNyDjgC3Qsvh51WAFGK74C3Tq7k5zYbm7kbVZdUse2i27XiDkMuB6sriroi7XHfnV3Bo55ig3APAFXD7mQrKTGE2ov17CF6yn1ns81vf', - }, - proof_nodes: - '+QHS+JygNttWkmVHYjZyCCk0TNJr5l7AJOnuLNU99qWyNhfBuWq4efh3uHV7ImlkZW50aWZpZXIiOiJWNFNHUlU4Nlo1OGQ2VFY3UEJVZTZmIiwicm9sZSI6IjAiLCJzZXFObyI6MTEsInR4blRpbWUiOjE2MzI2ODA5NjMsInZlcmtleSI6In40M1g0TmhBRnFSRWZmSzdlV2RLZ0ZIIn35ATGg09I/bgmxWmztC58rrZwebgwutUGli7VUyVOFwmuLFqOAoNrtARUl8FhzgOfGsZGlm8IVqgH1wB5KaoajR9sA53e2oJqauj70Qf++s0g43b1zvnQEyQJh2lfNqxFRtmaADvkwgKACG8f0w2NsuDibWYibc1TYySAgUKSeIevHF6wVZdMBL6BEAIIJs0un9jVqVEABbCWTkc0rybTVrFgaKU6LD6ciGYCAgICgJHIm3oUOYlDrQlw95UDkRdOc2tGIsE9g2r12AjpJiUKAoH0lXE47VtUlFvwnCC5rgY878m6TpeEZTJIKd4SUxXtqoBvSoTludXD0XkhTPm4YxfCcAdCaiDvkzM8w6O4v5/e1oDs6GXxRL8inD2b3RY1v/ufksDHNqfFKaK2MEIjNIZwagA==', - root_hash: 'AqMNuzJHeHduhggd8URobGyc1W89oGEjmohRXkB66JZo', - }, - seqNo: 11, - identifier: 'LibindyDid111111111111', - dest: did, - data: `{"dest":"${did}","identifier":"V4SGRU86Z58d6TV7PBUe6f","role":"0","seqNo":11,"txnTime":1632680963,"verkey":"${verkey}"}`, - type: '105', - }, - } - - return response -} - -export function getDidResponsesForDid( - did: string, - pools: IndySdkPoolConfig[], - responses: { [key: string]: string | undefined } -) { - return pools.map((pool) => { - const verkey = responses[pool.indyNamespace] - - if (verkey) { - return () => Promise.resolve(getDidResponse({ did, verkey })) - } - - // LedgerNotFound - return () => Promise.reject(new IndyError(309)) - }) -} diff --git a/packages/indy-sdk/src/ledger/__tests__/serializeRequestForSignature.test.ts b/packages/indy-sdk/src/ledger/__tests__/serializeRequestForSignature.test.ts deleted file mode 100644 index 7bf0c64a67..0000000000 --- a/packages/indy-sdk/src/ledger/__tests__/serializeRequestForSignature.test.ts +++ /dev/null @@ -1,87 +0,0 @@ -import { serializeRequestForSignature } from '../serializeRequestForSignature' - -describe('serializeRequestForSignature', () => { - it('Should correctly serialize the json for signature input', () => { - const request = { - name: 'John Doe', - age: 43, - operation: { - dest: 54, - }, - phones: ['1234567', '2345678', { rust: 5, age: 1 }, 3], - } - - const expectedResult = 'age:43|name:John Doe|operation:dest:54|phones:1234567,2345678,age:1|rust:5,3' - - expect(serializeRequestForSignature(request)).toEqual(expectedResult) - }) - - it('Should correctly serialize the json for signature with skipped fields', () => { - const request = { - name: 'John Doe', - age: 43, - operation: { - type: '100', - hash: 'cool hash', - dest: 54, - }, - fees: 'fees1', - signature: 'sign1', - signatures: 'sign-m', - phones: ['1234567', '2345678', { rust: 5, age: 1 }, 3], - } - - const expectedResult = - 'age:43|name:John Doe|operation:dest:54|hash:46aa0c92129b33ee72ee1478d2ae62fa6e756869dedc6c858af3214a6fcf1904|type:100|phones:1234567,2345678,age:1|rust:5,3' - - expect(serializeRequestForSignature(request)).toEqual(expectedResult) - }) - - it('Should correctly serialize the json for signature with raw hash for attrib related types', () => { - const request = { - name: 'John Doe', - age: 43, - operation: { - type: '100', - hash: 'cool hash', - dest: 54, - raw: 'string for hash', - }, - phones: ['1234567', '2345678', { rust: 5, age: 1 }, 3], - } - - const expectedResult = - 'age:43|name:John Doe|operation:dest:54|hash:46aa0c92129b33ee72ee1478d2ae62fa6e756869dedc6c858af3214a6fcf1904|raw:1dcd0759ce38f57049344a6b3c5fc18144fca1724713090c2ceeffa788c02711|type:100|phones:1234567,2345678,age:1|rust:5,3' - - expect(serializeRequestForSignature(request)).toEqual(expectedResult) - }) - - it('Should correctly serialize the json for signature with raw hash for non-attrib related types', () => { - const request = { - name: 'John Doe', - age: 43, - operation: { - type: '101', - hash: 'cool hash', - dest: 54, - raw: 'string for hash', - }, - phones: ['1234567', '2345678', { rust: 5, age: 1 }, 3], - } - - const expectedResult = - 'age:43|name:John Doe|operation:dest:54|hash:cool hash|raw:string for hash|type:101|phones:1234567,2345678,age:1|rust:5,3' - - expect(serializeRequestForSignature(request)).toEqual(expectedResult) - }) - - it('Should correctly serialize the json for signature with null signature', () => { - const request = { - signature: null, - } - - const expectedResult = '' - - expect(serializeRequestForSignature(request)).toEqual(expectedResult) - }) -}) diff --git a/packages/indy-sdk/src/ledger/__tests__/util.test.ts b/packages/indy-sdk/src/ledger/__tests__/util.test.ts deleted file mode 100644 index 38976758ae..0000000000 --- a/packages/indy-sdk/src/ledger/__tests__/util.test.ts +++ /dev/null @@ -1,45 +0,0 @@ -import type { LedgerRejectResponse, LedgerReqnackResponse } from 'indy-sdk' - -import * as LedgerUtil from '../util' - -describe('LedgerUtils', () => { - // IsLedgerRejectResponse - it('Should return true if the response op is: REJECT', () => { - const ledgerResponse: LedgerRejectResponse = { - op: 'REJECT', - reqId: 1, - reason: 'Why not', - identifier: '123456', - } - expect(LedgerUtil.isLedgerRejectResponse(ledgerResponse)).toEqual(true) - }) - it('Should return false if the response op is not: REJECT', () => { - const ledgerResponse: LedgerReqnackResponse = { - op: 'REQNACK', - reqId: 1, - reason: 'Why not', - identifier: '123456', - } - expect(LedgerUtil.isLedgerRejectResponse(ledgerResponse)).toEqual(false) - }) - - // isLedgerReqnackResponse - it('Should return true if the response op is: REQNACK', () => { - const ledgerResponse: LedgerReqnackResponse = { - op: 'REQNACK', - reqId: 1, - reason: 'Why not', - identifier: '123456', - } - expect(LedgerUtil.isLedgerReqnackResponse(ledgerResponse)).toEqual(true) - }) - it('Should return false if the response op is NOT: REQNACK', () => { - const ledgerResponse: LedgerRejectResponse = { - op: 'REJECT', - reqId: 1, - reason: 'Why not', - identifier: '123456', - } - expect(LedgerUtil.isLedgerReqnackResponse(ledgerResponse)).toEqual(false) - }) -}) diff --git a/packages/indy-sdk/src/ledger/error/IndySdkPoolError.ts b/packages/indy-sdk/src/ledger/error/IndySdkPoolError.ts deleted file mode 100644 index dd124d0e65..0000000000 --- a/packages/indy-sdk/src/ledger/error/IndySdkPoolError.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { AriesFrameworkError } from '@credo-ts/core' - -export class IndySdkPoolError extends AriesFrameworkError { - public constructor(message: string, { cause }: { cause?: Error } = {}) { - super(message, { cause }) - } -} diff --git a/packages/indy-sdk/src/ledger/error/IndySdkPoolNotConfiguredError.ts b/packages/indy-sdk/src/ledger/error/IndySdkPoolNotConfiguredError.ts deleted file mode 100644 index 91cd3c7199..0000000000 --- a/packages/indy-sdk/src/ledger/error/IndySdkPoolNotConfiguredError.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { IndySdkPoolError } from './IndySdkPoolError' - -export class IndySdkPoolNotConfiguredError extends IndySdkPoolError { - public constructor(message: string, { cause }: { cause?: Error } = {}) { - super(message, { cause }) - } -} diff --git a/packages/indy-sdk/src/ledger/error/IndySdkPoolNotFoundError.ts b/packages/indy-sdk/src/ledger/error/IndySdkPoolNotFoundError.ts deleted file mode 100644 index 4977428cba..0000000000 --- a/packages/indy-sdk/src/ledger/error/IndySdkPoolNotFoundError.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { IndySdkPoolError } from './IndySdkPoolError' - -export class IndySdkPoolNotFoundError extends IndySdkPoolError { - public constructor(message: string, { cause }: { cause?: Error } = {}) { - super(message, { cause }) - } -} diff --git a/packages/indy-sdk/src/ledger/error/index.ts b/packages/indy-sdk/src/ledger/error/index.ts deleted file mode 100644 index e2554abbdf..0000000000 --- a/packages/indy-sdk/src/ledger/error/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from './IndySdkPoolError' -export * from './IndySdkPoolNotConfiguredError' -export * from './IndySdkPoolNotFoundError' diff --git a/packages/indy-sdk/src/ledger/index.ts b/packages/indy-sdk/src/ledger/index.ts deleted file mode 100644 index fe016abcec..0000000000 --- a/packages/indy-sdk/src/ledger/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './IndySdkPool' -export * from './IndySdkPoolService' diff --git a/packages/indy-sdk/src/ledger/serializeRequestForSignature.ts b/packages/indy-sdk/src/ledger/serializeRequestForSignature.ts deleted file mode 100644 index 7338e21892..0000000000 --- a/packages/indy-sdk/src/ledger/serializeRequestForSignature.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { Hasher, TypedArrayEncoder } from '@credo-ts/core' - -const ATTRIB_TYPE = '100' -const GET_ATTR_TYPE = '104' - -/// Generate the normalized form of a ledger transaction request for signing -export function serializeRequestForSignature(v: any): string { - const type = v?.operation?.type - - return _serializeRequestForSignature(v, true, type != undefined ? `${type}` : undefined) -} - -/** - * Serialize an indy ledger request object for signing input. Based on the rust code. Indy SDK requires ledger requests to be signed using - * a did, however in Credo's the wallet only creates keys, and we create custom did records. This allows us to remove the legacy createDid and - * publicDidSeed properties from the wallet, as we create the request payload ourselves. - * - * @see https://github.com/hyperledger/indy-shared-rs/blob/6af1e939586d1f16341dc03b62970cf28b32d118/indy-utils/src/txn_signature.rs#L10 - */ -function _serializeRequestForSignature(v: any, isTopLevel: boolean, _type?: string): string { - const vType = typeof v - - if (vType === 'boolean') return v ? 'True' : 'False' - if (vType === 'number') return v.toString() - if (vType === 'string') return v - - if (vType === 'object') { - if (Array.isArray(v)) { - return v.map((element) => _serializeRequestForSignature(element, false, _type)).join(',') - } - - let result = '' - let inMiddle = false - - for (const vKey of Object.keys(v).sort()) { - // Skip signature field at top level as in python code - if (isTopLevel && (vKey == 'signature' || vKey == 'fees' || vKey == 'signatures')) { - continue - } - - if (inMiddle) { - result += '|' - } - - let value = v[vKey] - if ((_type == ATTRIB_TYPE || _type == GET_ATTR_TYPE) && (vKey == 'raw' || vKey == 'hash' || vKey == 'enc')) { - // do it only for attribute related request - if (typeof value !== 'string') throw new Error('Value must be a string for hash') - const hash = Hasher.hash(TypedArrayEncoder.fromString(value), 'sha2-256') - value = Buffer.from(hash).toString('hex') - } - - result = `${result}${vKey}:${_serializeRequestForSignature(value, false, _type)}` - inMiddle = true - } - - return result - } - - return '' -} diff --git a/packages/indy-sdk/src/ledger/util.ts b/packages/indy-sdk/src/ledger/util.ts deleted file mode 100644 index d7b5fc2076..0000000000 --- a/packages/indy-sdk/src/ledger/util.ts +++ /dev/null @@ -1,9 +0,0 @@ -import type { LedgerResponse, LedgerRejectResponse, LedgerReqnackResponse } from 'indy-sdk' - -export function isLedgerRejectResponse(response: LedgerResponse): response is LedgerRejectResponse { - return response.op === 'REJECT' -} - -export function isLedgerReqnackResponse(response: LedgerResponse): response is LedgerReqnackResponse { - return response.op === 'REQNACK' -} diff --git a/packages/indy-sdk/src/storage/IndySdkStorageService.ts b/packages/indy-sdk/src/storage/IndySdkStorageService.ts deleted file mode 100644 index c2dc7e19cd..0000000000 --- a/packages/indy-sdk/src/storage/IndySdkStorageService.ts +++ /dev/null @@ -1,321 +0,0 @@ -import type { IndySdkWallet } from '../wallet/IndySdkWallet' -import type { BaseRecordConstructor, AgentContext, BaseRecord, TagsBase, Query, StorageService } from '@credo-ts/core' -import type { WalletQuery, WalletRecord, WalletSearchOptions } from 'indy-sdk' - -import { RecordDuplicateError, RecordNotFoundError, injectable, inject, JsonTransformer } from '@credo-ts/core' - -import { isIndyError, IndySdkError } from '../error' -import { IndySdk, IndySdkSymbol } from '../types' -import { assertIndySdkWallet } from '../utils/assertIndySdkWallet' - -@injectable() -export class IndySdkStorageService implements StorageService { - private indySdk: IndySdk - - private static DEFAULT_QUERY_OPTIONS = { - retrieveType: true, - retrieveTags: true, - } - - public constructor(@inject(IndySdkSymbol) indySdk: IndySdk) { - this.indySdk = indySdk - } - - private transformToRecordTagValues(tags: { [key: number]: string | undefined }): TagsBase { - const transformedTags: TagsBase = {} - - for (const [key, value] of Object.entries(tags)) { - // If the value is a boolean string ('1' or '0') - // use the boolean val - if (value === '1' && key?.includes(':')) { - const [tagName, tagValue] = key.split(':') - - const transformedValue = transformedTags[tagName] - - if (Array.isArray(transformedValue)) { - transformedTags[tagName] = [...transformedValue, tagValue] - } else { - transformedTags[tagName] = [tagValue] - } - } - // Transform '1' and '0' to boolean - else if (value === '1' || value === '0') { - transformedTags[key] = value === '1' - } - // If 1 or 0 is prefixed with 'n__' we need to remove it. This is to prevent - // casting the value to a boolean - else if (value === 'n__1' || value === 'n__0') { - transformedTags[key] = value === 'n__1' ? '1' : '0' - } - // Otherwise just use the value - else { - transformedTags[key] = value - } - } - - return transformedTags - } - - private transformFromRecordTagValues(tags: TagsBase): { [key: string]: string | undefined } { - const transformedTags: { [key: string]: string | undefined } = {} - - for (const [key, value] of Object.entries(tags)) { - // If the value is of type null we use the value undefined - // Indy doesn't support null as a value - if (value === null) { - transformedTags[key] = undefined - } - // If the value is a boolean use the indy - // '1' or '0' syntax - else if (typeof value === 'boolean') { - transformedTags[key] = value ? '1' : '0' - } - // If the value is 1 or 0, we need to add something to the value, otherwise - // the next time we deserialize the tag values it will be converted to boolean - else if (value === '1' || value === '0') { - transformedTags[key] = `n__${value}` - } - // If the value is an array we create a tag for each array - // item ("tagName:arrayItem" = "1") - else if (Array.isArray(value)) { - value.forEach((item) => { - const tagName = `${key}:${item}` - transformedTags[tagName] = '1' - }) - } - // Otherwise just use the value - else { - transformedTags[key] = value - } - } - - return transformedTags - } - - /** - * Transforms the search query into a wallet query compatible with indy WQL. - * - * The format used by Credo is almost the same as the indy query, with the exception of - * the encoding of values, however this is handled by the {@link IndyStorageService.transformToRecordTagValues} - * method. - */ - private indyQueryFromSearchQuery(query: Query): Record { - // eslint-disable-next-line prefer-const - let { $and, $or, $not, ...tags } = query - - $and = ($and as Query[] | undefined)?.map((q) => this.indyQueryFromSearchQuery(q)) - $or = ($or as Query[] | undefined)?.map((q) => this.indyQueryFromSearchQuery(q)) - $not = $not ? this.indyQueryFromSearchQuery($not as Query) : undefined - - const indyQuery = { - ...this.transformFromRecordTagValues(tags as unknown as TagsBase), - $and, - $or, - $not, - } - - return indyQuery - } - - private recordToInstance(record: WalletRecord, recordClass: BaseRecordConstructor): T { - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const instance = JsonTransformer.deserialize(record.value!, recordClass) - instance.id = record.id - - const tags = record.tags ? this.transformToRecordTagValues(record.tags) : {} - instance.replaceTags(tags) - - return instance - } - - /** @inheritDoc */ - public async save(agentContext: AgentContext, record: T) { - assertIndySdkWallet(agentContext.wallet) - - record.updatedAt = new Date() - - const value = JsonTransformer.serialize(record) - const tags = this.transformFromRecordTagValues(record.getTags()) as Record - - try { - await this.indySdk.addWalletRecord(agentContext.wallet.handle, record.type, record.id, value, tags) - } catch (error) { - // Record already exists - if (isIndyError(error, 'WalletItemAlreadyExists')) { - throw new RecordDuplicateError(`Record with id ${record.id} already exists`, { recordType: record.type }) - } - - throw isIndyError(error) ? new IndySdkError(error) : error - } - } - - /** @inheritDoc */ - public async update(agentContext: AgentContext, record: T): Promise { - assertIndySdkWallet(agentContext.wallet) - - record.updatedAt = new Date() - - const value = JsonTransformer.serialize(record) - const tags = this.transformFromRecordTagValues(record.getTags()) as Record - - try { - await this.indySdk.updateWalletRecordValue(agentContext.wallet.handle, record.type, record.id, value) - await this.indySdk.updateWalletRecordTags(agentContext.wallet.handle, record.type, record.id, tags) - } catch (error) { - // Record does not exist - if (isIndyError(error, 'WalletItemNotFound')) { - throw new RecordNotFoundError(`record with id ${record.id} not found.`, { - recordType: record.type, - cause: error, - }) - } - - throw isIndyError(error) ? new IndySdkError(error) : error - } - } - - /** @inheritDoc */ - public async delete(agentContext: AgentContext, record: T) { - assertIndySdkWallet(agentContext.wallet) - - try { - await this.indySdk.deleteWalletRecord(agentContext.wallet.handle, record.type, record.id) - } catch (error) { - // Record does not exist - if (isIndyError(error, 'WalletItemNotFound')) { - throw new RecordNotFoundError(`record with id ${record.id} not found.`, { - recordType: record.type, - cause: error, - }) - } - - throw isIndyError(error) ? new IndySdkError(error) : error - } - } - - /** @inheritDoc */ - public async deleteById( - agentContext: AgentContext, - recordClass: BaseRecordConstructor, - id: string - ): Promise { - assertIndySdkWallet(agentContext.wallet) - - try { - await this.indySdk.deleteWalletRecord(agentContext.wallet.handle, recordClass.type, id) - } catch (error) { - if (isIndyError(error, 'WalletItemNotFound')) { - throw new RecordNotFoundError(`record with id ${id} not found.`, { - recordType: recordClass.type, - cause: error, - }) - } - - throw isIndyError(error) ? new IndySdkError(error) : error - } - } - - /** @inheritDoc */ - public async getById(agentContext: AgentContext, recordClass: BaseRecordConstructor, id: string): Promise { - assertIndySdkWallet(agentContext.wallet) - - try { - const record = await this.indySdk.getWalletRecord( - agentContext.wallet.handle, - recordClass.type, - id, - IndySdkStorageService.DEFAULT_QUERY_OPTIONS - ) - return this.recordToInstance(record, recordClass) - } catch (error) { - if (isIndyError(error, 'WalletItemNotFound')) { - throw new RecordNotFoundError(`record with id ${id} not found.`, { - recordType: recordClass.type, - cause: error, - }) - } - - throw isIndyError(error) ? new IndySdkError(error) : error - } - } - - /** @inheritDoc */ - public async getAll(agentContext: AgentContext, recordClass: BaseRecordConstructor): Promise { - assertIndySdkWallet(agentContext.wallet) - - const recordIterator = this.search( - agentContext.wallet, - recordClass.type, - {}, - IndySdkStorageService.DEFAULT_QUERY_OPTIONS - ) - const records = [] - for await (const record of recordIterator) { - records.push(this.recordToInstance(record, recordClass)) - } - return records - } - - /** @inheritDoc */ - public async findByQuery( - agentContext: AgentContext, - recordClass: BaseRecordConstructor, - query: Query - ): Promise { - assertIndySdkWallet(agentContext.wallet) - - const indyQuery = this.indyQueryFromSearchQuery(query) - - const recordIterator = this.search( - agentContext.wallet, - recordClass.type, - indyQuery, - IndySdkStorageService.DEFAULT_QUERY_OPTIONS - ) - const records = [] - for await (const record of recordIterator) { - records.push(this.recordToInstance(record, recordClass)) - } - return records - } - - private async *search( - wallet: IndySdkWallet, - type: string, - query: WalletQuery, - { limit = Infinity, ...options }: WalletSearchOptions & { limit?: number } - ) { - try { - const searchHandle = await this.indySdk.openWalletSearch(wallet.handle, type, query, options) - - let records: WalletRecord[] = [] - - // Allow max of 256 per fetch operation - const chunk = limit ? Math.min(256, limit) : 256 - - // Loop while limit not reached (or no limit specified) - while (!limit || records.length < limit) { - // Retrieve records - const recordsJson = await this.indySdk.fetchWalletSearchNextRecords(wallet.handle, searchHandle, chunk) - - if (recordsJson.records) { - records = [...records, ...recordsJson.records] - - for (const record of recordsJson.records) { - yield record - } - } - - // If the number of records returned is less than chunk - // It means we reached the end of the iterator (no more records) - if (!records.length || !recordsJson.records || recordsJson.records.length < chunk) { - await this.indySdk.closeWalletSearch(searchHandle) - - return - } - } - } catch (error) { - throw new IndySdkError(error, `Searching '${type}' records for query '${JSON.stringify(query)}' failed`) - } - } -} diff --git a/packages/indy-sdk/src/storage/__tests__/IndySdkStorageService.test.ts b/packages/indy-sdk/src/storage/__tests__/IndySdkStorageService.test.ts deleted file mode 100644 index a6bac1e8de..0000000000 --- a/packages/indy-sdk/src/storage/__tests__/IndySdkStorageService.test.ts +++ /dev/null @@ -1,314 +0,0 @@ -import type { IndySdk } from '../../types' -import type { TagsBase } from '@credo-ts/core' - -import { RecordDuplicateError, RecordNotFoundError, SigningProviderRegistry } from '@credo-ts/core' -import * as indySdk from 'indy-sdk' - -import { TestRecord } from '../../../../core/src/storage/__tests__/TestRecord' -import { getAgentConfig, getAgentContext } from '../../../../core/tests/helpers' -import { IndySdkWallet } from '../../wallet/IndySdkWallet' -import { IndySdkStorageService } from '../IndySdkStorageService' - -const agentConfig = getAgentConfig('IndySdkStorageServiceTest') -const wallet = new IndySdkWallet(indySdk, agentConfig.logger, new SigningProviderRegistry([])) - -const agentContext = getAgentContext({ - wallet, - agentConfig, -}) - -const storageService = new IndySdkStorageService(indySdk) -const startDate = Date.now() - -describe('IndySdkStorageService', () => { - beforeEach(async () => { - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - await wallet.createAndOpen(agentConfig.walletConfig!) - }) - - afterEach(async () => { - await wallet.delete() - }) - - const insertRecord = async ({ id, tags }: { id?: string; tags?: TagsBase }) => { - const props = { - id, - foo: 'bar', - tags: tags ?? { myTag: 'foobar' }, - } - const record = new TestRecord(props) - await storageService.save(agentContext, record) - return record - } - - describe('tag transformation', () => { - it('should correctly transform tag values to string before storing', async () => { - const record = await insertRecord({ - id: 'test-id', - tags: { - someBoolean: true, - someOtherBoolean: false, - someStringValue: 'string', - anArrayValue: ['foo', 'bar'], - // booleans are stored as '1' and '0' so we store the string values '1' and '0' as 'n__1' and 'n__0' - someStringNumberValue: '1', - anotherStringNumberValue: '0', - }, - }) - - const retrieveRecord = await indySdk.getWalletRecord(wallet.handle, record.type, record.id, { - retrieveType: true, - retrieveTags: true, - }) - - expect(retrieveRecord.tags).toEqual({ - someBoolean: '1', - someOtherBoolean: '0', - someStringValue: 'string', - 'anArrayValue:foo': '1', - 'anArrayValue:bar': '1', - someStringNumberValue: 'n__1', - anotherStringNumberValue: 'n__0', - }) - }) - - it('should correctly transform tag values from string after retrieving', async () => { - await indySdk.addWalletRecord(wallet.handle, TestRecord.type, 'some-id', '{}', { - someBoolean: '1', - someOtherBoolean: '0', - someStringValue: 'string', - 'anArrayValue:foo': '1', - 'anArrayValue:bar': '1', - // booleans are stored as '1' and '0' so we store the string values '1' and '0' as 'n__1' and 'n__0' - someStringNumberValue: 'n__1', - anotherStringNumberValue: 'n__0', - }) - - const record = await storageService.getById(agentContext, TestRecord, 'some-id') - - expect(record.getTags()).toEqual({ - someBoolean: true, - someOtherBoolean: false, - someStringValue: 'string', - anArrayValue: expect.arrayContaining(['bar', 'foo']), - someStringNumberValue: '1', - anotherStringNumberValue: '0', - }) - }) - }) - - describe('save()', () => { - it('should throw RecordDuplicateError if a record with the id already exists', async () => { - const record = await insertRecord({ id: 'test-id' }) - - return expect(() => storageService.save(agentContext, record)).rejects.toThrowError(RecordDuplicateError) - }) - - it('should save the record', async () => { - const record = await insertRecord({ id: 'test-id' }) - const found = await storageService.getById(agentContext, TestRecord, 'test-id') - - expect(record).toEqual(found) - }) - - it('After a save the record should have update the updatedAt property', async () => { - const time = startDate - const record = await insertRecord({ id: 'test-updatedAt' }) - expect(record.updatedAt?.getTime()).toBeGreaterThan(time) - }) - }) - - describe('getById()', () => { - it('should throw RecordNotFoundError if the record does not exist', async () => { - return expect(() => storageService.getById(agentContext, TestRecord, 'does-not-exist')).rejects.toThrowError( - RecordNotFoundError - ) - }) - - it('should return the record by id', async () => { - const record = await insertRecord({ id: 'test-id' }) - const found = await storageService.getById(agentContext, TestRecord, 'test-id') - - expect(found).toEqual(record) - }) - }) - - describe('update()', () => { - it('should throw RecordNotFoundError if the record does not exist', async () => { - const record = new TestRecord({ - id: 'test-id', - foo: 'test', - tags: { some: 'tag' }, - }) - - return expect(() => storageService.update(agentContext, record)).rejects.toThrowError(RecordNotFoundError) - }) - - it('should update the record', async () => { - const record = await insertRecord({ id: 'test-id' }) - - record.replaceTags({ ...record.getTags(), foo: 'bar' }) - record.foo = 'foobaz' - await storageService.update(agentContext, record) - - const retrievedRecord = await storageService.getById(agentContext, TestRecord, record.id) - expect(retrievedRecord).toEqual(record) - }) - - it('After a record has been updated it should have updated the updatedAT property', async () => { - const time = startDate - const record = await insertRecord({ id: 'test-id' }) - - record.replaceTags({ ...record.getTags(), foo: 'bar' }) - record.foo = 'foobaz' - await storageService.update(agentContext, record) - - const retrievedRecord = await storageService.getById(agentContext, TestRecord, record.id) - expect(retrievedRecord.createdAt.getTime()).toBeGreaterThan(time) - }) - }) - - describe('delete()', () => { - it('should throw RecordNotFoundError if the record does not exist', async () => { - const record = new TestRecord({ - id: 'test-id', - foo: 'test', - tags: { some: 'tag' }, - }) - - return expect(() => storageService.delete(agentContext, record)).rejects.toThrowError(RecordNotFoundError) - }) - - it('should delete the record', async () => { - const record = await insertRecord({ id: 'test-id' }) - await storageService.delete(agentContext, record) - - return expect(() => storageService.getById(agentContext, TestRecord, record.id)).rejects.toThrowError( - RecordNotFoundError - ) - }) - }) - - describe('getAll()', () => { - it('should retrieve all records', async () => { - const createdRecords = await Promise.all( - Array(5) - .fill(undefined) - .map((_, index) => insertRecord({ id: `record-${index}` })) - ) - - const records = await storageService.getAll(agentContext, TestRecord) - - expect(records).toEqual(expect.arrayContaining(createdRecords)) - }) - }) - - describe('findByQuery()', () => { - it('should retrieve all records that match the query', async () => { - const expectedRecord = await insertRecord({ tags: { myTag: 'foobar' } }) - await insertRecord({ tags: { myTag: 'notfoobar' } }) - - const records = await storageService.findByQuery(agentContext, TestRecord, { myTag: 'foobar' }) - - expect(records.length).toBe(1) - expect(records[0]).toEqual(expectedRecord) - }) - - it('finds records using $and statements', async () => { - const expectedRecord = await insertRecord({ tags: { myTag: 'foo', anotherTag: 'bar' } }) - await insertRecord({ tags: { myTag: 'notfoobar' } }) - - const records = await storageService.findByQuery(agentContext, TestRecord, { - $and: [{ myTag: 'foo' }, { anotherTag: 'bar' }], - }) - - expect(records.length).toBe(1) - expect(records[0]).toEqual(expectedRecord) - }) - - it('finds records using $or statements', async () => { - const expectedRecord = await insertRecord({ tags: { myTag: 'foo' } }) - const expectedRecord2 = await insertRecord({ tags: { anotherTag: 'bar' } }) - await insertRecord({ tags: { myTag: 'notfoobar' } }) - - const records = await storageService.findByQuery(agentContext, TestRecord, { - $or: [{ myTag: 'foo' }, { anotherTag: 'bar' }], - }) - - expect(records.length).toBe(2) - expect(records).toEqual(expect.arrayContaining([expectedRecord, expectedRecord2])) - }) - - it('finds records using $not statements', async () => { - const expectedRecord = await insertRecord({ tags: { myTag: 'foo' } }) - const expectedRecord2 = await insertRecord({ tags: { anotherTag: 'bar' } }) - await insertRecord({ tags: { myTag: 'notfoobar' } }) - - const records = await storageService.findByQuery(agentContext, TestRecord, { - $not: { myTag: 'notfoobar' }, - }) - - expect(records.length).toBe(2) - expect(records).toEqual(expect.arrayContaining([expectedRecord, expectedRecord2])) - }) - - it('correctly transforms an advanced query into a valid WQL query', async () => { - const indySpy = jest.fn() - const storageServiceWithoutIndySdk = new IndySdkStorageService({ - openWalletSearch: indySpy, - fetchWalletSearchNextRecords: jest.fn(() => ({ records: undefined })), - closeWalletSearch: jest.fn(), - } as unknown as IndySdk) - - await storageServiceWithoutIndySdk.findByQuery(agentContext, TestRecord, { - $and: [ - { - $or: [{ myTag: true }, { myTag: false }], - }, - { - $and: [{ theNumber: '0' }, { theNumber: '1' }], - }, - ], - $or: [ - { - aValue: ['foo', 'bar'], - }, - ], - $not: { myTag: 'notfoobar' }, - }) - - const expectedQuery = { - $and: [ - { - $and: undefined, - $not: undefined, - $or: [ - { myTag: '1', $and: undefined, $or: undefined, $not: undefined }, - { myTag: '0', $and: undefined, $or: undefined, $not: undefined }, - ], - }, - { - $or: undefined, - $not: undefined, - $and: [ - { theNumber: 'n__0', $and: undefined, $or: undefined, $not: undefined }, - { theNumber: 'n__1', $and: undefined, $or: undefined, $not: undefined }, - ], - }, - ], - $or: [ - { - 'aValue:foo': '1', - 'aValue:bar': '1', - $and: undefined, - $or: undefined, - $not: undefined, - }, - ], - $not: { myTag: 'notfoobar', $and: undefined, $or: undefined, $not: undefined }, - } - - expect(indySpy).toBeCalledWith(expect.anything(), expect.anything(), expectedQuery, expect.anything()) - }) - }) -}) diff --git a/packages/indy-sdk/src/storage/index.ts b/packages/indy-sdk/src/storage/index.ts deleted file mode 100644 index ff59756cfa..0000000000 --- a/packages/indy-sdk/src/storage/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './IndySdkStorageService' diff --git a/packages/indy-sdk/src/types.ts b/packages/indy-sdk/src/types.ts deleted file mode 100644 index f6ac41c161..0000000000 --- a/packages/indy-sdk/src/types.ts +++ /dev/null @@ -1,6 +0,0 @@ -import type { default as _IndySdk } from 'indy-sdk' - -type IndySdk = typeof _IndySdk - -export const IndySdkSymbol = Symbol('IndySdk') -export type { IndySdk } diff --git a/packages/indy-sdk/src/utils/__tests__/did.test.ts b/packages/indy-sdk/src/utils/__tests__/did.test.ts deleted file mode 100644 index 222f9898fd..0000000000 --- a/packages/indy-sdk/src/utils/__tests__/did.test.ts +++ /dev/null @@ -1,77 +0,0 @@ -import { isAbbreviatedVerkey, isFullVerkey, isLegacySelfCertifiedDid } from '../did' - -const validAbbreviatedVerkeys = [ - '~PKAYz8Ev4yoQgr2LaMAWFx', - '~Soy1augaQrQYtNZRRHsikB', - '~BUF7uxYTxZ6qYdZ4G9e1Gi', - '~DbZ4gkBqhFRVsT5P7BJqyZ', - '~4zmNTdG78iYyMAQdEQLrf8', -] - -const invalidAbbreviatedVerkeys = [ - '6YnVN5Qdb6mqimTRQcQmSXrHXKdTEdRn5YHZReezUTvt', - '8jG2Bim1HNSybCTdKBRppP4PCQSSijx1pBnreqsdo8JG', - 'ABUF7uxYTxZ6qYdZ4G9e1Gi', - '~Db3IgkBqhFRVsT5P7BJqyZ', - '~4zmNTlG78iYyMAQdEQLrf8', -] - -const validFullVerkeys = [ - '6YnVN5Qdb6mqimTRQcQmSXrHXKdTEdRn5YHZReezUTvt', - '8jG2Bim1HNSybCTdKBRppP4PCQSSijx1pBnreqsdo8JG', - '9wMLhw9SSxtTUyosrndMbvWY4TtDbVvRnMtzG2NysniP', - '6m2XT39vivJ7tLSxNPM8siMnhYCZcdMxbkTcJDSzAQTu', - 'CAgL85iEecPNQMmxQ1hgbqczwq7SAerQ8RbWTRtC7SoK', - 'MqXmB7cTsTXqyxDPBbrgu5EPqw61kouK1qjMvnoPa96', -] - -const invalidFullVerkeys = [ - '~PKAYz8Ev4yoQgr2LaMAWFx', - '~Soy1augaQrQYtNZRRHsikB', - '6YnVN5Qdb6mqimTRQcQmSXrHXKdTEdRn5YHZReezUTvta', - '6m2XT39vIvJ7tLSxNPM8siMnhYCZcdMxbkTcJDSzAQTu', - 'CAgL85iEecPNQMlxQ1hgbqczwq7SAerQ8RbWTRtC7SoK', -] - -describe('Utils | Did', () => { - describe('isSelfCertifiedDid()', () => { - test('returns true if the verkey is abbreviated', () => { - expect(isLegacySelfCertifiedDid('PW8ZHpNupeWXbmpPWog6Ki', '~QQ5jiH1dgXPAnvHdJvazn9')).toBe(true) - }) - - test('returns true if the verkey is not abbreviated and the did is generated from the verkey', () => { - expect(isLegacySelfCertifiedDid('Y8q4Aq6gRAcmB6jjKk3Z7t', 'HyEoPRNvC7q4jj5joUo8AWYtxbNccbEnTAeuMYkpmNS2')).toBe( - true - ) - }) - - test('returns false if the verkey is not abbreviated and the did is not generated from the verkey', () => { - expect(isLegacySelfCertifiedDid('Y8q4Aq6gRAcmB6jjKk3Z7t', 'AcU7DnRqoXGYATD6VqsRq4eHuz55gdM3uzFBEhFd6rGh')).toBe( - false - ) - }) - }) - - describe('isAbbreviatedVerkey()', () => { - test.each(validAbbreviatedVerkeys)('returns true when valid abbreviated verkey "%s" is passed in', (verkey) => { - expect(isAbbreviatedVerkey(verkey)).toBe(true) - }) - - test.each(invalidAbbreviatedVerkeys)( - 'returns false when invalid abbreviated verkey "%s" is passed in', - (verkey) => { - expect(isAbbreviatedVerkey(verkey)).toBe(false) - } - ) - }) - - describe('isFullVerkey()', () => { - test.each(validFullVerkeys)('returns true when valid full verkey "%s" is passed in', (verkey) => { - expect(isFullVerkey(verkey)).toBe(true) - }) - - test.each(invalidFullVerkeys)('returns false when invalid full verkey "%s" is passed in', (verkey) => { - expect(isFullVerkey(verkey)).toBe(false) - }) - }) -}) diff --git a/packages/indy-sdk/src/utils/assertIndySdkWallet.ts b/packages/indy-sdk/src/utils/assertIndySdkWallet.ts deleted file mode 100644 index 4308926919..0000000000 --- a/packages/indy-sdk/src/utils/assertIndySdkWallet.ts +++ /dev/null @@ -1,13 +0,0 @@ -import type { Wallet } from '@credo-ts/core' - -import { AriesFrameworkError } from '@credo-ts/core' - -import { IndySdkWallet } from '../wallet/IndySdkWallet' - -export function assertIndySdkWallet(wallet: Wallet): asserts wallet is IndySdkWallet { - if (!(wallet instanceof IndySdkWallet)) { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const walletClassName = (wallet as any).constructor?.name ?? 'unknown' - throw new AriesFrameworkError(`Expected wallet to be instance of IndySdkWallet, found ${walletClassName}`) - } -} diff --git a/packages/indy-sdk/src/utils/did.ts b/packages/indy-sdk/src/utils/did.ts deleted file mode 100644 index d7dabf0023..0000000000 --- a/packages/indy-sdk/src/utils/did.ts +++ /dev/null @@ -1,89 +0,0 @@ -/** - * Based on DidUtils implementation in Aries Framework .NET - * @see: https://github.com/hyperledger/aries-framework-dotnet/blob/f90eaf9db8548f6fc831abea917e906201755763/src/Hyperledger.Aries/Utils/DidUtils.cs - * - * Some context about full verkeys versus abbreviated verkeys: - * A standard verkey is 32 bytes, and by default in Indy the DID is chosen as the first 16 bytes of that key, before base58 encoding. - * An abbreviated verkey replaces the first 16 bytes of the verkey with ~ when it matches the DID. - * - * When a full verkey is used to register on the ledger, this is stored as a full verkey on the ledger and also returned from the ledger as a full verkey. - * The same applies to an abbreviated verkey. If an abbreviated verkey is used to register on the ledger, this is stored as an abbreviated verkey on the ledger and also returned from the ledger as an abbreviated verkey. - * - * For this reason we need some methods to check whether verkeys are full or abbreviated, so we can align this with `indy.abbreviateVerkey` - * - * Aries Framework .NET also abbreviates verkey before sending to ledger: - * https://github.com/hyperledger/aries-framework-dotnet/blob/f90eaf9db8548f6fc831abea917e906201755763/src/Hyperledger.Aries/Ledger/DefaultLedgerService.cs#L139-L147 - */ - -import { Buffer, TypedArrayEncoder } from '@credo-ts/core' - -export const FULL_VERKEY_REGEX = /^[1-9A-HJ-NP-Za-km-z]{43,44}$/ -export const ABBREVIATED_VERKEY_REGEX = /^~[1-9A-HJ-NP-Za-km-z]{21,22}$/ - -/** - * Check whether the did is a self certifying did. If the verkey is abbreviated this method - * will always return true. Make sure that the verkey you pass in this method belongs to the - * did passed in - * - * @return Boolean indicating whether the did is self certifying - */ -export function isLegacySelfCertifiedDid(did: string, verkey: string): boolean { - // If the verkey is Abbreviated, it means the full verkey - // is the did + the verkey - if (isAbbreviatedVerkey(verkey)) { - return true - } - - const didFromVerkey = legacyIndyDidFromPublicKeyBase58(verkey) - - if (didFromVerkey === did) { - return true - } - - return false -} - -export function legacyIndyDidFromPublicKeyBase58(publicKeyBase58: string): string { - const buffer = TypedArrayEncoder.fromBase58(publicKeyBase58) - - const did = TypedArrayEncoder.toBase58(buffer.slice(0, 16)) - - return did -} - -export function getFullVerkey(did: string, verkey: string) { - if (isFullVerkey(verkey)) return verkey - - // Did could have did:xxx prefix, only take the last item after : - const id = did.split(':').pop() ?? did - // Verkey is prefixed with ~ if abbreviated - const verkeyWithoutTilde = verkey.slice(1) - - // Create base58 encoded public key (32 bytes) - return TypedArrayEncoder.toBase58( - Buffer.concat([ - // Take did identifier (16 bytes) - TypedArrayEncoder.fromBase58(id), - // Concat the abbreviated verkey (16 bytes) - TypedArrayEncoder.fromBase58(verkeyWithoutTilde), - ]) - ) -} - -/** - * Check a base58 encoded string against a regex expression to determine if it is a full valid verkey - * @param verkey Base58 encoded string representation of a verkey - * @return Boolean indicating if the string is a valid verkey - */ -export function isFullVerkey(verkey: string): boolean { - return FULL_VERKEY_REGEX.test(verkey) -} - -/** - * Check a base58 encoded string against a regex expression to determine if it is a valid abbreviated verkey - * @param verkey Base58 encoded string representation of an abbreviated verkey - * @returns Boolean indicating if the string is a valid abbreviated verkey - */ -export function isAbbreviatedVerkey(verkey: string): boolean { - return ABBREVIATED_VERKEY_REGEX.test(verkey) -} diff --git a/packages/indy-sdk/src/utils/promises.ts b/packages/indy-sdk/src/utils/promises.ts deleted file mode 100644 index 0e843d73b5..0000000000 --- a/packages/indy-sdk/src/utils/promises.ts +++ /dev/null @@ -1,44 +0,0 @@ -// This file polyfills the allSettled method introduced in ESNext - -export type AllSettledFulfilled = { - status: 'fulfilled' - value: T -} - -export type AllSettledRejected = { - status: 'rejected' - // eslint-disable-next-line @typescript-eslint/no-explicit-any - reason: any -} - -export function allSettled(promises: Promise[]) { - return Promise.all( - promises.map((p) => - p - .then( - (value) => - ({ - status: 'fulfilled', - value, - } as AllSettledFulfilled) - ) - .catch( - (reason) => - ({ - status: 'rejected', - reason, - } as AllSettledRejected) - ) - ) - ) -} - -export function onlyFulfilled(entries: Array | AllSettledRejected>) { - // We filter for only the rejected values, so we can safely cast the type - return entries.filter((e) => e.status === 'fulfilled') as AllSettledFulfilled[] -} - -export function onlyRejected(entries: Array | AllSettledRejected>) { - // We filter for only the rejected values, so we can safely cast the type - return entries.filter((e) => e.status === 'rejected') as AllSettledRejected[] -} diff --git a/packages/indy-sdk/src/wallet/IndySdkWallet.ts b/packages/indy-sdk/src/wallet/IndySdkWallet.ts deleted file mode 100644 index 791b130dbf..0000000000 --- a/packages/indy-sdk/src/wallet/IndySdkWallet.ts +++ /dev/null @@ -1,645 +0,0 @@ -import type { - Buffer, - EncryptedMessage, - KeyDerivationMethod, - KeyPair, - UnpackedMessageContext, - Wallet, - WalletConfig, - WalletConfigRekey, - WalletCreateKeyOptions, - WalletExportImportConfig, - WalletSignOptions, - WalletVerifyOptions, -} from '@credo-ts/core' -import type { OpenWalletCredentials, WalletConfig as IndySdkWalletConfig, WalletStorageConfig } from 'indy-sdk' - -// eslint-disable-next-line import/order -import { - AriesFrameworkError, - InjectionSymbols, - isValidPrivateKey, - isValidSeed, - JsonEncoder, - Key, - KeyType, - Logger, - RecordNotFoundError, - SigningProviderRegistry, - TypedArrayEncoder, - WalletDuplicateError, - WalletError, - WalletExportPathExistsError, - WalletInvalidKeyError, - WalletKeyExistsError, - WalletNotFoundError, -} from '@credo-ts/core' - -const isError = (error: unknown): error is Error => error instanceof Error - -import { inject, injectable } from 'tsyringe' - -import { IndySdkError, isIndyError } from '../error' -import { IndySdk, IndySdkSymbol } from '../types' - -@injectable() -export class IndySdkWallet implements Wallet { - private walletConfig?: WalletConfig - private walletHandle?: number - - private logger: Logger - private signingKeyProviderRegistry: SigningProviderRegistry - private indySdk: IndySdk - - public constructor( - @inject(IndySdkSymbol) indySdk: IndySdk, - @inject(InjectionSymbols.Logger) logger: Logger, - signingKeyProviderRegistry: SigningProviderRegistry - ) { - this.logger = logger - this.signingKeyProviderRegistry = signingKeyProviderRegistry - this.indySdk = indySdk - } - - public get isProvisioned() { - return this.walletConfig !== undefined - } - - public get isInitialized() { - return this.walletHandle !== undefined - } - - public get handle() { - if (!this.walletHandle) { - throw new AriesFrameworkError( - 'Wallet has not been initialized yet. Make sure to await agent.initialize() before using the agent.' - ) - } - - return this.walletHandle - } - - public get supportedKeyTypes() { - const walletSupportedKeyTypes = [KeyType.Ed25519] - const signingKeyProviderSupportedKeyTypes = this.signingKeyProviderRegistry.supportedKeyTypes - - return Array.from(new Set([...walletSupportedKeyTypes, ...signingKeyProviderSupportedKeyTypes])) - } - - /** - * Dispose method is called when an agent context is disposed. - */ - public async dispose() { - if (this.isInitialized) { - await this.close() - } - } - - private walletStorageConfig(walletConfig: WalletConfig): IndySdkWalletConfig { - const walletStorageConfig: IndySdkWalletConfig = { - id: walletConfig.id, - storage_type: walletConfig.storage?.type, - } - - if (walletConfig.storage?.config) { - walletStorageConfig.storage_config = walletConfig.storage?.config as WalletStorageConfig - } - - return walletStorageConfig - } - - private walletCredentials( - walletConfig: WalletConfig, - rekey?: string, - rekeyDerivation?: KeyDerivationMethod - ): OpenWalletCredentials { - const walletCredentials: OpenWalletCredentials = { - key: walletConfig.key, - key_derivation_method: walletConfig.keyDerivationMethod, - } - if (rekey) { - walletCredentials.rekey = rekey - } - if (rekeyDerivation) { - walletCredentials.rekey_derivation_method = rekeyDerivation - } - if (walletConfig.storage?.credentials) { - walletCredentials.storage_credentials = walletConfig.storage?.credentials as Record - } - - return walletCredentials - } - - /** - * @throws {WalletDuplicateError} if the wallet already exists - * @throws {WalletError} if another error occurs - */ - public async create(walletConfig: WalletConfig): Promise { - await this.createAndOpen(walletConfig) - await this.close() - } - - /** - * @throws {WalletDuplicateError} if the wallet already exists - * @throws {WalletError} if another error occurs - */ - public async createAndOpen(walletConfig: WalletConfig): Promise { - this.logger.debug(`Creating wallet '${walletConfig.id}' using SQLite storage`) - - try { - await this.indySdk.createWallet(this.walletStorageConfig(walletConfig), this.walletCredentials(walletConfig)) - this.walletConfig = walletConfig - - await this.open(walletConfig) - } catch (error) { - if (isIndyError(error, 'WalletAlreadyExistsError')) { - const errorMessage = `Wallet '${walletConfig.id}' already exists` - this.logger.debug(errorMessage) - - throw new WalletDuplicateError(errorMessage, { - walletType: 'IndySdkWallet', - cause: error, - }) - } else { - if (!isError(error)) { - throw new AriesFrameworkError('Attempted to throw error, but it was not of type Error', { cause: error }) - } - const errorMessage = `Error creating wallet '${walletConfig.id}'` - this.logger.error(errorMessage, { - error, - errorMessage: error.message, - }) - - throw new WalletError(errorMessage, { cause: error }) - } - } - - this.logger.debug(`Successfully created wallet '${walletConfig.id}'`) - } - - /** - * @throws {WalletNotFoundError} if the wallet does not exist - * @throws {WalletError} if another error occurs - */ - public async open(walletConfig: WalletConfig): Promise { - await this._open(walletConfig) - } - - /** - * @throws {WalletNotFoundError} if the wallet does not exist - * @throws {WalletError} if another error occurs - */ - public async rotateKey(walletConfig: WalletConfigRekey): Promise { - if (!walletConfig.rekey) { - throw new WalletError('Wallet rekey undefined!. Please specify the new wallet key') - } - await this._open( - { - id: walletConfig.id, - key: walletConfig.key, - keyDerivationMethod: walletConfig.keyDerivationMethod, - }, - walletConfig.rekey, - walletConfig.rekeyDerivationMethod - ) - } - - /** - * @throws {WalletNotFoundError} if the wallet does not exist - * @throws {WalletError} if another error occurs - */ - private async _open( - walletConfig: WalletConfig, - rekey?: string, - rekeyDerivation?: KeyDerivationMethod - ): Promise { - if (this.walletHandle) { - throw new WalletError( - 'Wallet instance already opened. Close the currently opened wallet before re-opening the wallet' - ) - } - - try { - this.walletHandle = await this.indySdk.openWallet( - this.walletStorageConfig(walletConfig), - this.walletCredentials(walletConfig, rekey, rekeyDerivation) - ) - if (rekey) { - this.walletConfig = { ...walletConfig, key: rekey, keyDerivationMethod: rekeyDerivation } - } else { - this.walletConfig = walletConfig - } - } catch (error) { - if (isIndyError(error, 'WalletNotFoundError')) { - const errorMessage = `Wallet '${walletConfig.id}' not found` - this.logger.debug(errorMessage) - - throw new WalletNotFoundError(errorMessage, { - walletType: 'IndySdkWallet', - cause: error, - }) - } else if (isIndyError(error, 'WalletAccessFailed')) { - const errorMessage = `Incorrect key for wallet '${walletConfig.id}'` - this.logger.debug(errorMessage) - throw new WalletInvalidKeyError(errorMessage, { - walletType: 'IndySdkWallet', - cause: error, - }) - } else { - if (!isError(error)) { - throw new AriesFrameworkError('Attempted to throw error, but it was not of type Error', { cause: error }) - } - const errorMessage = `Error opening wallet '${walletConfig.id}': ${error.message}` - this.logger.error(errorMessage, { - error, - errorMessage: error.message, - }) - - throw new WalletError(errorMessage, { cause: error }) - } - } - - this.logger.debug(`Wallet '${walletConfig.id}' opened with handle '${this.handle}'`) - } - - /** - * @throws {WalletNotFoundError} if the wallet does not exist - * @throws {WalletError} if another error occurs - */ - public async delete(): Promise { - if (!this.walletConfig) { - throw new WalletError( - 'Can not delete wallet that does not have wallet config set. Make sure to call create wallet before deleting the wallet' - ) - } - - this.logger.info(`Deleting wallet '${this.walletConfig.id}'`) - - if (this.walletHandle) { - await this.close() - } - - try { - await this.indySdk.deleteWallet( - this.walletStorageConfig(this.walletConfig), - this.walletCredentials(this.walletConfig) - ) - } catch (error) { - if (isIndyError(error, 'WalletNotFoundError')) { - const errorMessage = `Error deleting wallet: wallet '${this.walletConfig.id}' not found` - this.logger.debug(errorMessage) - - throw new WalletNotFoundError(errorMessage, { - walletType: 'IndySdkWallet', - cause: error, - }) - } else { - if (!isError(error)) { - throw new AriesFrameworkError('Attempted to throw error, but it was not of type Error', { cause: error }) - } - const errorMessage = `Error deleting wallet '${this.walletConfig.id}': ${error.message}` - this.logger.error(errorMessage, { - error, - errorMessage: error.message, - }) - - throw new WalletError(errorMessage, { cause: error }) - } - } - } - - public async export(exportConfig: WalletExportImportConfig) { - try { - this.logger.debug(`Exporting wallet ${this.walletConfig?.id} to path ${exportConfig.path}`) - await this.indySdk.exportWallet(this.handle, exportConfig) - } catch (error) { - if (!isError(error)) { - throw new AriesFrameworkError('Attempted to throw error, but it was not of type Error', { cause: error }) - } - - // Export path already exists - if (isIndyError(error, 'CommonIOError')) { - throw new WalletExportPathExistsError( - `Unable to create export, wallet export at path '${exportConfig.path}' already exists`, - { cause: error } - ) - } - - const errorMessage = `Error exporting wallet: ${error.message}` - this.logger.error(errorMessage, { - error, - }) - - throw new WalletError(errorMessage, { cause: error }) - } - } - - public async import(walletConfig: WalletConfig, importConfig: WalletExportImportConfig) { - try { - this.logger.debug(`Importing wallet ${walletConfig.id} from path ${importConfig.path}`) - await this.indySdk.importWallet( - { id: walletConfig.id }, - { key: walletConfig.key, key_derivation_method: walletConfig.keyDerivationMethod }, - importConfig - ) - } catch (error) { - if (!isError(error)) { - throw new AriesFrameworkError('Attempted to throw error, but it was not of type Error', { cause: error }) - } - const errorMessage = `Error importing wallet': ${error.message}` - this.logger.error(errorMessage, { - error, - }) - - throw new WalletError(errorMessage, { cause: error }) - } - } - - /** - * @throws {WalletError} if the wallet is already closed or another error occurs - */ - public async close(): Promise { - this.logger.debug(`Closing wallet ${this.walletConfig?.id}`) - if (!this.walletHandle) { - throw new WalletError('Wallet is in invalid state, you are trying to close wallet that has no `walletHandle`.') - } - - try { - await this.indySdk.closeWallet(this.walletHandle) - this.walletHandle = undefined - } catch (error) { - if (isIndyError(error, 'WalletInvalidHandle')) { - const errorMessage = `Error closing wallet: wallet already closed` - this.logger.debug(errorMessage) - - throw new WalletError(errorMessage, { - cause: error, - }) - } else { - if (!isError(error)) { - throw new AriesFrameworkError('Attempted to throw error, but it was not of type Error', { cause: error }) - } - const errorMessage = `Error closing wallet': ${error.message}` - this.logger.error(errorMessage, { - error, - errorMessage: error.message, - }) - - throw new WalletError(errorMessage, { cause: error }) - } - } - } - - /** - * Create a key with an optional private key and keyType. - * The keypair is also automatically stored in the wallet afterwards - * - * Bls12381g1g2 and X25519 are not supported. - */ - public async createKey({ seed, privateKey, keyType }: WalletCreateKeyOptions): Promise { - try { - if (seed && privateKey) { - throw new WalletError('Only one of seed and privateKey can be set') - } - - if (seed && !isValidSeed(seed, keyType)) { - throw new WalletError('Invalid seed provided') - } - - if (privateKey && !isValidPrivateKey(privateKey, keyType)) { - throw new WalletError('Invalid private key provided') - } - - // Ed25519 is supported natively in Indy wallet - if (keyType === KeyType.Ed25519) { - if (seed) { - throw new WalletError( - 'IndySdkWallet does not support seed. You may rather want to specify a private key for deterministic ed25519 key generation' - ) - } - try { - const verkey = await this.indySdk.createKey(this.handle, { - seed: privateKey?.toString(), - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - //@ts-ignore - crypto_type: 'ed25519', - }) - - return Key.fromPublicKeyBase58(verkey, keyType) - } catch (error) { - // Handle case where key already exists - if (isIndyError(error, 'WalletItemAlreadyExists')) { - throw new WalletKeyExistsError('Key already exists') - } - - // Otherwise re-throw error - throw error - } - } - - // Check if there is a signing key provider for the specified key type. - if (this.signingKeyProviderRegistry.hasProviderForKeyType(keyType)) { - const signingKeyProvider = this.signingKeyProviderRegistry.getProviderForKeyType(keyType) - - const keyPair = await signingKeyProvider.createKeyPair({ seed, privateKey }) - await this.storeKeyPair(keyPair) - return Key.fromPublicKeyBase58(keyPair.publicKeyBase58, keyType) - } - } catch (error) { - // If already instance of `WalletError`, re-throw - if (error instanceof WalletError) throw error - - if (!isError(error)) { - throw new AriesFrameworkError(`Attempted to throw error, but it was not of type Error: ${error}`, { - cause: error, - }) - } - - throw new WalletError(`Error creating key with key type '${keyType}': ${error.message}`, { cause: error }) - } - - throw new WalletError(`Unsupported key type: '${keyType}' for wallet IndySdkWallet`) - } - - /** - * sign a Buffer with an instance of a Key class - * - * Bls12381g1g2, Bls12381g1 and X25519 are not supported. - * - * @param data Buffer The data that needs to be signed - * @param key Key The key that is used to sign the data - * - * @returns A signature for the data - */ - public async sign({ data, key }: WalletSignOptions): Promise { - try { - // Ed25519 is supported natively in Indy wallet - if (key.keyType === KeyType.Ed25519) { - // Checks to see if it is an not an Array of messages, but just a single one - if (!TypedArrayEncoder.isTypedArray(data)) { - throw new WalletError(`${KeyType.Ed25519} does not support multiple singing of multiple messages`) - } - return await this.indySdk.cryptoSign(this.handle, key.publicKeyBase58, data as Buffer) - } - - // Check if there is a signing key provider for the specified key type. - if (this.signingKeyProviderRegistry.hasProviderForKeyType(key.keyType)) { - const signingKeyProvider = this.signingKeyProviderRegistry.getProviderForKeyType(key.keyType) - - const keyPair = await this.retrieveKeyPair(key.publicKeyBase58) - const signed = await signingKeyProvider.sign({ - data, - privateKeyBase58: keyPair.privateKeyBase58, - publicKeyBase58: key.publicKeyBase58, - }) - - return signed - } - } catch (error) { - if (!isError(error)) { - throw new AriesFrameworkError('Attempted to throw error, but it was not of type Error', { cause: error }) - } - throw new WalletError(`Error signing data with verkey ${key.publicKeyBase58}`, { cause: error }) - } - throw new WalletError(`Unsupported keyType: ${key.keyType}`) - } - - /** - * Verify the signature with the data and the used key - * - * Bls12381g1g2, Bls12381g1 and X25519 are not supported. - * - * @param data Buffer The data that has to be confirmed to be signed - * @param key Key The key that was used in the signing process - * @param signature Buffer The signature that was created by the signing process - * - * @returns A boolean whether the signature was created with the supplied data and key - * - * @throws {WalletError} When it could not do the verification - * @throws {WalletError} When an unsupported keytype is used - */ - public async verify({ data, key, signature }: WalletVerifyOptions): Promise { - try { - // Ed25519 is supported natively in Indy wallet - if (key.keyType === KeyType.Ed25519) { - // Checks to see if it is an not an Array of messages, but just a single one - if (!TypedArrayEncoder.isTypedArray(data)) { - throw new WalletError(`${KeyType.Ed25519} does not support multiple singing of multiple messages`) - } - return await this.indySdk.cryptoVerify(key.publicKeyBase58, data as Buffer, signature) - } - - // Check if there is a signing key provider for the specified key type. - if (this.signingKeyProviderRegistry.hasProviderForKeyType(key.keyType)) { - const signingKeyProvider = this.signingKeyProviderRegistry.getProviderForKeyType(key.keyType) - - const signed = await signingKeyProvider.verify({ - data, - signature, - publicKeyBase58: key.publicKeyBase58, - }) - - return signed - } - } catch (error) { - if (!isError(error)) { - throw new AriesFrameworkError('Attempted to throw error, but it was not of type Error', { cause: error }) - } - throw new WalletError(`Error verifying signature of data signed with verkey ${key.publicKeyBase58}`, { - cause: error, - }) - } - throw new WalletError(`Unsupported keyType: ${key.keyType}`) - } - - public async pack( - payload: Record, - recipientKeys: string[], - senderVerkey?: string - ): Promise { - try { - const messageRaw = JsonEncoder.toBuffer(payload) - const packedMessage = await this.indySdk.packMessage(this.handle, messageRaw, recipientKeys, senderVerkey ?? null) - return JsonEncoder.fromBuffer(packedMessage) - } catch (error) { - if (!isError(error)) { - throw new AriesFrameworkError('Attempted to throw error, but it was not of type Error', { cause: error }) - } - throw new WalletError('Error packing message', { cause: error }) - } - } - - public async unpack(messagePackage: EncryptedMessage): Promise { - try { - const unpackedMessageBuffer = await this.indySdk.unpackMessage(this.handle, JsonEncoder.toBuffer(messagePackage)) - const unpackedMessage = JsonEncoder.fromBuffer(unpackedMessageBuffer) - return { - senderKey: unpackedMessage.sender_verkey, - recipientKey: unpackedMessage.recipient_verkey, - plaintextMessage: JsonEncoder.fromString(unpackedMessage.message), - } - } catch (error) { - if (!isError(error)) { - throw new AriesFrameworkError('Attempted to throw error, but it was not of type Error', { cause: error }) - } - throw new WalletError('Error unpacking message', { cause: error }) - } - } - - public async generateNonce(): Promise { - try { - return await this.indySdk.generateNonce() - } catch (error) { - if (!isError(error)) { - throw new AriesFrameworkError('Attempted to throw error, but it was not of type Error', { cause: error }) - } - throw new WalletError('Error generating nonce', { cause: error }) - } - } - - private async retrieveKeyPair(publicKeyBase58: string): Promise { - try { - const { value } = await this.indySdk.getWalletRecord(this.handle, 'KeyPairRecord', `key-${publicKeyBase58}`, {}) - if (value) { - return JsonEncoder.fromString(value) as KeyPair - } else { - throw new WalletError(`No content found for record with public key: ${publicKeyBase58}`) - } - } catch (error) { - if (isIndyError(error, 'WalletItemNotFound')) { - throw new RecordNotFoundError(`KeyPairRecord not found for public key: ${publicKeyBase58}.`, { - recordType: 'KeyPairRecord', - cause: error, - }) - } - throw isIndyError(error) ? new IndySdkError(error) : error - } - } - - private async storeKeyPair(keyPair: KeyPair): Promise { - try { - await this.indySdk.addWalletRecord( - this.handle, - 'KeyPairRecord', - `key-${keyPair.publicKeyBase58}`, - JSON.stringify(keyPair), - { - keyType: keyPair.keyType, - } - ) - } catch (error) { - if (isIndyError(error, 'WalletItemAlreadyExists')) { - throw new WalletKeyExistsError('Key already exists') - } - throw isIndyError(error) ? new IndySdkError(error) : error - } - } - - public async generateWalletKey() { - try { - return await this.indySdk.generateWalletKey() - } catch (error) { - throw new WalletError('Error generating wallet key', { cause: error }) - } - } -} diff --git a/packages/indy-sdk/src/wallet/__tests__/IndySdkWallet.test.ts b/packages/indy-sdk/src/wallet/__tests__/IndySdkWallet.test.ts deleted file mode 100644 index b6b799fa2e..0000000000 --- a/packages/indy-sdk/src/wallet/__tests__/IndySdkWallet.test.ts +++ /dev/null @@ -1,114 +0,0 @@ -import type { SigningProvider, WalletConfig } from '@credo-ts/core' - -import { - Key, - WalletKeyExistsError, - KeyType, - SigningProviderRegistry, - TypedArrayEncoder, - KeyDerivationMethod, -} from '@credo-ts/core' -import indySdk from 'indy-sdk' - -import testLogger from '../../../../core/tests/logger' -import { IndySdkWallet } from '../IndySdkWallet' - -// use raw key derivation method to speed up wallet creating / opening / closing between tests -const walletConfig: WalletConfig = { - id: 'Wallet: IndySdkWalletTest', - // generated using indy.generateWalletKey - key: 'CwNJroKHTSSj3XvE7ZAnuKiTn2C4QkFvxEqfm5rzhNrb', - keyDerivationMethod: KeyDerivationMethod.Raw, -} - -const signingProvider = { - keyType: KeyType.X25519, - createKeyPair: () => Promise.resolve({ keyType: KeyType.X25519, privateKeyBase58: 'b', publicKeyBase58: 'a' }), -} satisfies Partial - -describe('IndySdkWallet', () => { - let indySdkWallet: IndySdkWallet - - const privateKey = TypedArrayEncoder.fromString('sample-seed') - const message = TypedArrayEncoder.fromString('sample-message') - - beforeEach(async () => { - indySdkWallet = new IndySdkWallet( - indySdk, - testLogger, - new SigningProviderRegistry([signingProvider as unknown as SigningProvider]) - ) - await indySdkWallet.createAndOpen(walletConfig) - }) - - afterEach(async () => { - await indySdkWallet.delete() - }) - - test('Get the wallet handle', () => { - expect(indySdkWallet.handle).toEqual(expect.any(Number)) - }) - - test('supportedKeyTypes', () => { - // indy supports ed25519, signing provider supports x25519 - expect(indySdkWallet.supportedKeyTypes).toEqual([KeyType.Ed25519, KeyType.X25519]) - }) - - test('Generate Nonce', async () => { - await expect(indySdkWallet.generateNonce()).resolves.toEqual(expect.any(String)) - }) - - test('Create ed25519 keypair from private key', async () => { - await expect( - indySdkWallet.createKey({ - privateKey: TypedArrayEncoder.fromString('2103de41b4ae37e8e28586d84a342b67'), - keyType: KeyType.Ed25519, - }) - ).resolves.toMatchObject({ - keyType: KeyType.Ed25519, - }) - }) - - test('throws WalletKeyExistsError when a key already exists', async () => { - const privateKey = TypedArrayEncoder.fromString('2103de41b4ae37e8e28586d84a342b68') - await expect(indySdkWallet.createKey({ privateKey, keyType: KeyType.Ed25519 })).resolves.toEqual(expect.any(Key)) - await expect(indySdkWallet.createKey({ privateKey, keyType: KeyType.Ed25519 })).rejects.toThrowError( - WalletKeyExistsError - ) - - // This should result in the signign provider being called twice, resulting in the record - // being stored twice - await expect(indySdkWallet.createKey({ privateKey, keyType: KeyType.X25519 })).resolves.toEqual(expect.any(Key)) - await expect(indySdkWallet.createKey({ privateKey, keyType: KeyType.X25519 })).rejects.toThrowError( - WalletKeyExistsError - ) - }) - - test('Fail to create ed25519 keypair from invalid private key', async () => { - await expect(indySdkWallet.createKey({ privateKey, keyType: KeyType.Ed25519 })).rejects.toThrowError( - /Invalid private key provided/ - ) - }) - - test('Fail to create x25519 keypair', async () => { - await expect(indySdkWallet.createKey({ keyType: KeyType.Bls12381g1 })).rejects.toThrowError(/Unsupported key type/) - }) - - test('Create a signature with a ed25519 keypair', async () => { - const ed25519Key = await indySdkWallet.createKey({ keyType: KeyType.Ed25519 }) - const signature = await indySdkWallet.sign({ - data: message, - key: ed25519Key, - }) - expect(signature.length).toStrictEqual(64) - }) - - test('Verify a signed message with a ed25519 publicKey', async () => { - const ed25519Key = await indySdkWallet.createKey({ keyType: KeyType.Ed25519 }) - const signature = await indySdkWallet.sign({ - data: message, - key: ed25519Key, - }) - await expect(indySdkWallet.verify({ key: ed25519Key, data: message, signature })).resolves.toStrictEqual(true) - }) -}) diff --git a/packages/indy-sdk/src/wallet/index.ts b/packages/indy-sdk/src/wallet/index.ts deleted file mode 100644 index b327ed63bf..0000000000 --- a/packages/indy-sdk/src/wallet/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { IndySdkWallet } from './IndySdkWallet' diff --git a/packages/indy-sdk/tests/__fixtures__/anoncreds.ts b/packages/indy-sdk/tests/__fixtures__/anoncreds.ts deleted file mode 100644 index eb978ec748..0000000000 --- a/packages/indy-sdk/tests/__fixtures__/anoncreds.ts +++ /dev/null @@ -1,30 +0,0 @@ -export const credentialDefinitionValue = { - primary: { - n: '96517142458750088826087901549537285521906361834839650465292394026155791790248920518228426560592477800345470631128393537910767968076647428853737338120375137978526133371095345886547568849980095910835456337942570110635942227498396677781945046904040000347997661394155645138402989185582727368743644878567330299129483548946710969360956979880962101169330048328620192831242584775824654760726417810662811409929761424969870024291961980782988854217354212087291593903213167261779548063894662259300608395552269380441482047725811646638173390809967510159302372018819245039226007682154490256871635806558216146474297742733244470144481', - s: '20992997088800769394205042281221010730843336204635587269131066142238627416871294692123680065003125450990475247419429111144686875080339959479648984195457400282722471552678361441816569115316390063503704185107464429408708889920969284364549487320740759452356010336698287092961864738455949515401889999320804333605635972368885179914619910494573144273759358510644118555354521660927445864167887629319425342133470781407706668100509422240127902573158722086763638357241708157836231326104213948080124231104027985997092193458353052131052627451830345602820935886233072722689872803371231173593216542422645374438328309647440653637339', - r: { - master_secret: - '96243300745227716230048295249700256382424379142767068560156597061550615821183969840133023439359733351013932957841392861447122785423145599004240865527901625751619237368187131360686977600247815596986496835118582544022443932674638843143227258367859921648385998241629365673854479167826898057354386557912400420925145402535066400276579674049751639901555837852972622061540154688641944145082381483273814616102862399655638465723909813901943343059991047747289931252070264205125933226649905593045675877143065756794349492159868513288280364195700788501708587588090219665708038121636837649207584981238653023213330207384929738192210', - name: '73301750658973501389860306433954162777688414647250690792688553201037736559940890441467927863421690990807820789906540409252803697381653459639864945429958798104818241892796218340966964349674689564019059435289373607451125919476002261041343187491848656595845611576458601110066647002078334660251906541846222115184239401618625285703919125402959929850028352261117167621349930047514115676870868726855651130262227714591240534532398809967792128535084773798290351459391475237061458901325844643172504167457543287673202618731404966555015061917662865397763636445953946274068384614117513804834235388565249331682010365807270858083546', - }, - rctxt: - '37788128721284563440858950515231840450431543928224096081933216180465915572829884228780081835462293611329848268384962871736884632087015070623933628853658097637604059748079512999518737243304794110313829761155878287344472916564970806851294430356498883927870926898737394894892797927804721407643833828162246495645836390303263072281761384240973982733122383052566872688887552226083782030670443318152427129452272570595367287061688769394567289624972332234661767648489253220495098949161964171486245324730862072203259801377135500275012560207100571502032523912388082460843991502336467718632746396226650194750972544436894286230063', - z: '43785356695890052462955676926428400928903479009358861113206349419200366390858322895540291303484939601128045362682307382393826375825484851021601464391509750565285197155653613669680662395620338416776539485377195826876505126073018100680273457526216247879013350460071029101583221000647494610122617904515744711339846577920055655093367012508192004131719432915903924789974568341538556528133188398290594619318653419602058489178526243446782729272985727332736198326183868783570550373552407121582843992983431205917273352230155794805507408743590383242904107596623095433284330566906935063373759426916339149701872288610119965287995', - }, - revocation: { - g: '1 0A84C28144BC8B677839038FFFA824AB5ADE517F8DD4A89F092FAF9A3560C62D 1 00FD708E112EEA5D89AF9D0559795E6DBCF56D3B8CDF79EFF34A72EB741F896F 2 095E45DDF417D05FB10933FFC63D474548B7FFFF7888802F07FFFFFF7D07A8A8', - g_dash: - '1 201F3E23CC7E9284F3EFCF9500F1E2537C398EAB2E94D2EB801AECC7FBFBDC01 1 08132C7723CF9861D4CC24B56555EF1CBD9AE746C97B3ADFA36C669F2DCE09B6 1 1B2397FB2A1ADE704E2A1E4C242612F4677F9F1BD09E6B14C2E77E25EDA4C62E 1 00CDC2CF5F278D699D52223577AB032C150A3CB4C8E8AB07AB9D592772910E95 2 095E45DDF417D05FB10933FFC63D474548B7FFFF7888802F07FFFFFF7D07A8A8 1 0000000000000000000000000000000000000000000000000000000000000000', - h: '1 072E0A505004F2F32B4210E72FA18A2ADF17F31479BD2059B7A8C0BA58F2ACB3 1 05C70F039E60317003C41C319753ECACC629791FDB06D6ADC5B06DD94501B973 2 095E45DDF417D05FB10933FFC63D474548B7FFFF7888802F07FFFFFF7D07A8A8', - h0: '1 03CBE26D18118E9770D4A0B3E8607B3B3A8D3D3CA81FF8D41862430CC583156E 1 004A2A57E0A826AEFF007EDDAF89B02F054050843689167B10127FE9EDEEEDA9 2 095E45DDF417D05FB10933FFC63D474548B7FFFF7888802F07FFFFFF7D07A8A8', - h1: '1 10C9F9DE537994E4FEF2625AFA78342C8A096238A875F6899DD500230E6022E5 1 0C0A88F53D020557377B4ED9C3826E9B8F918DD03E23B0F8ECD922F8333359D3 2 095E45DDF417D05FB10933FFC63D474548B7FFFF7888802F07FFFFFF7D07A8A8', - h2: '1 017F748AEEC1DDE4E4C3FBAE771C041F0A6FAEAF34FD02AF773AC4B75025147B 1 1298DBD9A4BEE6AD54E060A57BCE932735B7738C30A9ADAEFE2F38E1858A0183 2 095E45DDF417D05FB10933FFC63D474548B7FFFF7888802F07FFFFFF7D07A8A8', - htilde: - '1 0C471F0451D6AC352E28B6ECDE8D7233B75530AE59276DF0F4B9A8B0C5C7E5DB 1 24CE4461910AA5D60C09C24EE0FE51E1B1600D8BA6E483E9050EF897CA3E3C8A 2 095E45DDF417D05FB10933FFC63D474548B7FFFF7888802F07FFFFFF7D07A8A8', - h_cap: - '1 225B2106DEBD353AABDFC4C7F7E8660D308FB514EA9DAE0533DDEB65CF796159 1 1F6093622F439FC22C64F157F4F35F7C592EC0169C6F0026BC44CD3E375974A7 1 142126FAC3657AD846D394E1F72FD01ECC15E84416713CD133980E324B24F4BC 1 0357995DBDCD4385E59E607761AB30AE8D9DDE005A777EE846EF51AE2816CD33 2 095E45DDF417D05FB10933FFC63D474548B7FFFF7888802F07FFFFFF7D07A8A8 1 0000000000000000000000000000000000000000000000000000000000000000', - u: '1 00D8DDC2EB6536CA320EE035D099937E59B11678162C1BFEB30C58FCA9F84650 1 1557A5B05A1A30D63322E187D323C9CA431BC5E811E68D4703933D9DDA26D299 1 10E8AB93AA87839B757521742EBA23C3B257C91F61A93D37AEC4C0A011B5F073 1 1DA65E40406A7875DA8CFCE9FD7F283145C166382A937B72819BDC335FE9A734 2 095E45DDF417D05FB10933FFC63D474548B7FFFF7888802F07FFFFFF7D07A8A8 1 0000000000000000000000000000000000000000000000000000000000000000', - pk: '1 1A7EBBE3E7F8ED50959851364B20997944FA8AE5E3FC0A2BB531BAA17179D320 1 02C55FE6F64A2A4FF49B37C513C39E56ECD565CFAD6CA46DC6D8095179351863 2 095E45DDF417D05FB10933FFC63D474548B7FFFF7888802F07FFFFFF7D07A8A8', - y: '1 1BF97F07270EC21A89E43BCA645D86A755F846B547238F1DA379E088CDD9B40D 1 146BB00F56FFC0DEF6541CEB484C718559B398DB1547B52850E46B23144161F1 1 079A1BEF8DFFA4E6352F701D476664340E7FBE5D3F46B897412BD2B5F10E33D7 1 02FDC508AEF90FB11961AF332BE4037973C76B954FFA48848F7E0588E93FCA8C 2 095E45DDF417D05FB10933FFC63D474548B7FFFF7888802F07FFFFFF7D07A8A8 1 0000000000000000000000000000000000000000000000000000000000000000', - }, -} diff --git a/packages/indy-sdk/tests/indy-did-registrar.e2e.test.ts b/packages/indy-sdk/tests/indy-did-registrar.e2e.test.ts deleted file mode 100644 index 657f051675..0000000000 --- a/packages/indy-sdk/tests/indy-did-registrar.e2e.test.ts +++ /dev/null @@ -1,125 +0,0 @@ -import type { IndySdkIndyDidCreateOptions } from '../src' - -import { Agent, TypedArrayEncoder, convertPublicKeyToX25519, JsonTransformer } from '@credo-ts/core' -import { generateKeyPairFromSeed } from '@stablelib/ed25519' - -import { getAgentOptions, importExistingIndyDidFromPrivateKey, publicDidSeed } from '../../core/tests' -import { legacyIndyDidFromPublicKeyBase58 } from '../src/utils/did' - -import { getIndySdkModules } from './setupIndySdkModule' - -const agentOptions = getAgentOptions('Indy Sdk Indy Did Registrar', {}, getIndySdkModules()) -const agent = new Agent(agentOptions) - -describe('Indy SDK Indy Did Registrar', () => { - beforeAll(async () => { - await agent.initialize() - }) - - afterAll(async () => { - await agent.shutdown() - await agent.wallet.delete() - }) - - it('should create a did:indy did', async () => { - // Add existing endorser did to the wallet - const unqualifiedSubmitterDid = await importExistingIndyDidFromPrivateKey( - agent, - TypedArrayEncoder.fromString(publicDidSeed) - ) - - // Generate a seed and the indy did. This allows us to create a new did every time - // but still check if the created output document is as expected. - const privateKey = TypedArrayEncoder.fromString( - Array(32 + 1) - .join((Math.random().toString(36) + '00000000000000000').slice(2, 18)) - .slice(0, 32) - ) - - const publicKeyEd25519 = generateKeyPairFromSeed(privateKey).publicKey - const x25519PublicKeyBase58 = TypedArrayEncoder.toBase58(convertPublicKeyToX25519(publicKeyEd25519)) - const ed25519PublicKeyBase58 = TypedArrayEncoder.toBase58(publicKeyEd25519) - const unqualifiedDid = legacyIndyDidFromPublicKeyBase58(ed25519PublicKeyBase58) - - const did = await agent.dids.create({ - method: 'indy', - options: { - submitterDid: `did:indy:pool:localtest:${unqualifiedSubmitterDid}`, - alias: 'Alias', - endpoints: { - endpoint: 'https://example.com/endpoint', - types: ['DIDComm', 'did-communication', 'endpoint'], - routingKeys: ['a-routing-key'], - }, - }, - secret: { - privateKey, - }, - }) - - expect(JsonTransformer.toJSON(did)).toMatchObject({ - didDocumentMetadata: {}, - didRegistrationMetadata: {}, - didState: { - state: 'finished', - did: `did:indy:pool:localtest:${unqualifiedDid}`, - didDocument: { - '@context': [ - 'https://w3id.org/did/v1', - 'https://w3id.org/security/suites/ed25519-2018/v1', - 'https://w3id.org/security/suites/x25519-2019/v1', - 'https://didcomm.org/messaging/contexts/v2', - ], - alsoKnownAs: undefined, - controller: undefined, - verificationMethod: [ - { - id: `did:indy:pool:localtest:${unqualifiedDid}#verkey`, - type: 'Ed25519VerificationKey2018', - controller: `did:indy:pool:localtest:${unqualifiedDid}`, - publicKeyBase58: ed25519PublicKeyBase58, - }, - { - id: `did:indy:pool:localtest:${unqualifiedDid}#key-agreement-1`, - type: 'X25519KeyAgreementKey2019', - controller: `did:indy:pool:localtest:${unqualifiedDid}`, - publicKeyBase58: x25519PublicKeyBase58, - }, - ], - service: [ - { - id: `did:indy:pool:localtest:${unqualifiedDid}#endpoint`, - serviceEndpoint: 'https://example.com/endpoint', - type: 'endpoint', - }, - { - accept: ['didcomm/aip2;env=rfc19'], - id: `did:indy:pool:localtest:${unqualifiedDid}#did-communication`, - priority: 0, - recipientKeys: [`did:indy:pool:localtest:${unqualifiedDid}#key-agreement-1`], - routingKeys: ['a-routing-key'], - serviceEndpoint: 'https://example.com/endpoint', - type: 'did-communication', - }, - { - accept: ['didcomm/v2'], - id: `did:indy:pool:localtest:${unqualifiedDid}#didcomm-1`, - routingKeys: ['a-routing-key'], - serviceEndpoint: 'https://example.com/endpoint', - type: 'DIDComm', - }, - ], - authentication: [`did:indy:pool:localtest:${unqualifiedDid}#verkey`], - assertionMethod: undefined, - keyAgreement: [`did:indy:pool:localtest:${unqualifiedDid}#key-agreement-1`], - capabilityInvocation: undefined, - capabilityDelegation: undefined, - id: `did:indy:pool:localtest:${unqualifiedDid}`, - }, - secret: { - privateKey, - }, - }, - }) - }) -}) diff --git a/packages/indy-sdk/tests/indy-did-resolver.e2e.test.ts b/packages/indy-sdk/tests/indy-did-resolver.e2e.test.ts deleted file mode 100644 index 2afd057288..0000000000 --- a/packages/indy-sdk/tests/indy-did-resolver.e2e.test.ts +++ /dev/null @@ -1,99 +0,0 @@ -import type { IndySdkIndyDidCreateOptions } from '../src' - -import { Agent, AriesFrameworkError, JsonTransformer, TypedArrayEncoder } from '@credo-ts/core' - -import { getAgentOptions, importExistingIndyDidFromPrivateKey, publicDidSeed } from '../../core/tests/helpers' - -import { getIndySdkModules } from './setupIndySdkModule' - -const agent = new Agent(getAgentOptions('Indy SDK Indy DID resolver', {}, getIndySdkModules())) - -describe('Indy SDK Indy DID resolver', () => { - beforeAll(async () => { - await agent.initialize() - }) - - afterAll(async () => { - await agent.shutdown() - await agent.wallet.delete() - }) - - it('should resolve a did:indy did', async () => { - // Add existing endorser did to the wallet - const unqualifiedSubmitterDid = await importExistingIndyDidFromPrivateKey( - agent, - TypedArrayEncoder.fromString(publicDidSeed) - ) - - const createResult = await agent.dids.create({ - method: 'indy', - options: { - submitterDid: `did:indy:pool:localtest:${unqualifiedSubmitterDid}`, - alias: 'Alias', - role: 'TRUSTEE', - endpoints: { - endpoint: 'http://localhost:3000', - }, - }, - }) - - // Terrible, but the did can't be immediately resolved, so we need to wait a bit - await new Promise((res) => setTimeout(res, 1000)) - - if (!createResult.didState.did) throw new AriesFrameworkError('Unable to register did') - - const didResult = await agent.dids.resolve(createResult.didState.did) - - expect(JsonTransformer.toJSON(didResult)).toMatchObject({ - didDocument: { - '@context': [ - 'https://w3id.org/did/v1', - 'https://w3id.org/security/suites/ed25519-2018/v1', - 'https://w3id.org/security/suites/x25519-2019/v1', - ], - id: createResult.didState.did, - alsoKnownAs: undefined, - controller: undefined, - verificationMethod: [ - { - type: 'Ed25519VerificationKey2018', - controller: createResult.didState.did, - id: `${createResult.didState.did}#verkey`, - publicKeyBase58: expect.any(String), - }, - { - controller: createResult.didState.did, - type: 'X25519KeyAgreementKey2019', - id: `${createResult.didState.did}#key-agreement-1`, - publicKeyBase58: expect.any(String), - }, - ], - capabilityDelegation: undefined, - capabilityInvocation: undefined, - authentication: [`${createResult.didState.did}#verkey`], - assertionMethod: undefined, - keyAgreement: [`${createResult.didState.did}#key-agreement-1`], - service: [ - { - id: `${createResult.didState.did}#endpoint`, - serviceEndpoint: 'http://localhost:3000', - type: 'endpoint', - }, - { - id: `${createResult.didState.did}#did-communication`, - accept: ['didcomm/aip2;env=rfc19'], - priority: 0, - recipientKeys: [`${createResult.didState.did}#key-agreement-1`], - routingKeys: [], - serviceEndpoint: 'http://localhost:3000', - type: 'did-communication', - }, - ], - }, - didDocumentMetadata: {}, - didResolutionMetadata: { - contentType: 'application/did+ld+json', - }, - }) - }) -}) diff --git a/packages/indy-sdk/tests/indy-sdk-anoncreds-registry.e2e.test.ts b/packages/indy-sdk/tests/indy-sdk-anoncreds-registry.e2e.test.ts deleted file mode 100644 index 256168ff94..0000000000 --- a/packages/indy-sdk/tests/indy-sdk-anoncreds-registry.e2e.test.ts +++ /dev/null @@ -1,345 +0,0 @@ -import { Agent, Key, KeyType, TypedArrayEncoder } from '@credo-ts/core' - -import { - agentDependencies, - getAgentConfig, - importExistingIndyDidFromPrivateKey, - publicDidSeed, -} from '../../core/tests/helpers' -import { IndySdkAnonCredsRegistry } from '../src/anoncreds/services/IndySdkAnonCredsRegistry' -import { IndySdkPoolService } from '../src/ledger' - -import { credentialDefinitionValue } from './__fixtures__/anoncreds' -import { getIndySdkModules, indySdk } from './setupIndySdkModule' - -const agentConfig = getAgentConfig('IndySdkAnonCredsRegistry') -const indySdkModules = getIndySdkModules() - -const agent = new Agent({ - config: agentConfig, - dependencies: agentDependencies, - modules: indySdkModules, -}) - -const indySdkAnonCredsRegistry = new IndySdkAnonCredsRegistry() -const indySdkPoolService = agent.dependencyManager.resolve(IndySdkPoolService) -const pool = indySdkPoolService.getPoolForNamespace('pool:localtest') - -describe('IndySdkAnonCredsRegistry', () => { - beforeAll(async () => { - await agent.initialize() - - // We need to import the endorser did/key into the wallet - await importExistingIndyDidFromPrivateKey(agent, TypedArrayEncoder.fromString(publicDidSeed)) - }) - - afterAll(async () => { - await agent.shutdown() - await agent.wallet.delete() - }) - - // TODO: use different issuer for schema and credential definition to catch possible bugs - // One test as the credential definition depends on the schema - test('register and resolve a schema and credential definition', async () => { - const dynamicVersion = `1.${Math.random() * 100}` - - const legacyIssuerId = 'TL1EaPFCZ8Si5aUrqScBDt' - const signingKey = Key.fromPublicKeyBase58('FMGcFuU3QwAQLywxvmEnSorQT3NwU9wgDMMTaDFtvswm', KeyType.Ed25519) - const didIndyIssuerId = 'did:indy:pool:localtest:TL1EaPFCZ8Si5aUrqScBDt' - - const legacySchemaId = `TL1EaPFCZ8Si5aUrqScBDt:2:test:${dynamicVersion}` - const didIndySchemaId = `did:indy:pool:localtest:TL1EaPFCZ8Si5aUrqScBDt/anoncreds/v0/SCHEMA/test/${dynamicVersion}` - - const schemaResult = await indySdkAnonCredsRegistry.registerSchema(agent.context, { - schema: { - attrNames: ['name'], - issuerId: didIndyIssuerId, - name: 'test', - version: dynamicVersion, - }, - options: {}, - }) - - expect(schemaResult).toMatchObject({ - schemaState: { - state: 'finished', - schema: { - attrNames: ['name'], - issuerId: didIndyIssuerId, - name: 'test', - version: dynamicVersion, - }, - schemaId: didIndySchemaId, - }, - registrationMetadata: {}, - schemaMetadata: { - indyLedgerSeqNo: expect.any(Number), - }, - }) - - // Wait some time before resolving credential definition object - await new Promise((res) => setTimeout(res, 1000)) - - // Resolve using legacy schema id - const legacySchema = await indySdkAnonCredsRegistry.getSchema(agent.context, legacySchemaId) - expect(legacySchema).toMatchObject({ - schema: { - attrNames: ['name'], - name: 'test', - version: dynamicVersion, - issuerId: 'TL1EaPFCZ8Si5aUrqScBDt', - }, - schemaId: `TL1EaPFCZ8Si5aUrqScBDt:2:test:${dynamicVersion}`, - resolutionMetadata: {}, - schemaMetadata: { - didIndyNamespace: 'pool:localtest', - indyLedgerSeqNo: expect.any(Number), - }, - }) - - // Resolve using did indy schema id - const didIndySchema = await indySdkAnonCredsRegistry.getSchema(agent.context, didIndySchemaId) - expect(didIndySchema).toMatchObject({ - schema: { - attrNames: ['name'], - name: 'test', - version: dynamicVersion, - issuerId: didIndyIssuerId, - }, - schemaId: didIndySchemaId, - resolutionMetadata: {}, - schemaMetadata: { - didIndyNamespace: 'pool:localtest', - indyLedgerSeqNo: expect.any(Number), - }, - }) - - const legacyCredentialDefinitionId = `TL1EaPFCZ8Si5aUrqScBDt:3:CL:${schemaResult.schemaMetadata.indyLedgerSeqNo}:TAG` - const didIndyCredentialDefinitionId = `did:indy:pool:localtest:TL1EaPFCZ8Si5aUrqScBDt/anoncreds/v0/CLAIM_DEF/${schemaResult.schemaMetadata.indyLedgerSeqNo}/TAG` - const credentialDefinitionResult = await indySdkAnonCredsRegistry.registerCredentialDefinition(agent.context, { - credentialDefinition: { - issuerId: didIndyIssuerId, - tag: 'TAG', - schemaId: didIndySchemaId, - type: 'CL', - value: credentialDefinitionValue, - }, - options: {}, - }) - - expect(credentialDefinitionResult).toMatchObject({ - credentialDefinitionMetadata: {}, - credentialDefinitionState: { - credentialDefinition: { - issuerId: didIndyIssuerId, - tag: 'TAG', - schemaId: didIndySchemaId, - type: 'CL', - value: credentialDefinitionValue, - }, - credentialDefinitionId: didIndyCredentialDefinitionId, - state: 'finished', - }, - registrationMetadata: {}, - }) - - // Wait some time before resolving credential definition object - await new Promise((res) => setTimeout(res, 1000)) - - // Resolve using legacy credential definition id - const legacyCredentialDefinition = await indySdkAnonCredsRegistry.getCredentialDefinition( - agent.context, - legacyCredentialDefinitionId - ) - expect(legacyCredentialDefinition).toMatchObject({ - credentialDefinitionId: legacyCredentialDefinitionId, - credentialDefinition: { - issuerId: legacyIssuerId, - schemaId: legacySchemaId, - tag: 'TAG', - type: 'CL', - value: credentialDefinitionValue, - }, - credentialDefinitionMetadata: { - didIndyNamespace: 'pool:localtest', - }, - resolutionMetadata: {}, - }) - - // resolve using did indy credential definition id - const didIndyCredentialDefinition = await indySdkAnonCredsRegistry.getCredentialDefinition( - agent.context, - didIndyCredentialDefinitionId - ) - - expect(didIndyCredentialDefinition).toMatchObject({ - credentialDefinitionId: didIndyCredentialDefinitionId, - credentialDefinition: { - issuerId: didIndyIssuerId, - schemaId: didIndySchemaId, - tag: 'TAG', - type: 'CL', - value: credentialDefinitionValue, - }, - credentialDefinitionMetadata: { - didIndyNamespace: 'pool:localtest', - }, - resolutionMetadata: {}, - }) - - // We don't support creating a revocation registry using Credo yet, so we directly use indy-sdk to register the revocation registry - const legacyRevocationRegistryId = `TL1EaPFCZ8Si5aUrqScBDt:4:TL1EaPFCZ8Si5aUrqScBDt:3:CL:${schemaResult.schemaMetadata.indyLedgerSeqNo}:TAG:CL_ACCUM:tag` - const didIndyRevocationRegistryId = `did:indy:pool:localtest:TL1EaPFCZ8Si5aUrqScBDt/anoncreds/v0/REV_REG_DEF/${schemaResult.schemaMetadata.indyLedgerSeqNo}/TAG/tag` - const revocationRegistryRequest = await indySdk.buildRevocRegDefRequest('TL1EaPFCZ8Si5aUrqScBDt', { - id: legacyRevocationRegistryId, - credDefId: legacyCredentialDefinitionId, - revocDefType: 'CL_ACCUM', - tag: 'tag', - value: { - issuanceType: 'ISSUANCE_BY_DEFAULT', - maxCredNum: 100, - publicKeys: { - accumKey: { - z: '1 1812B206EB395D3AEBD4BBF53EBB0FFC3371D8BD6175316AB32C1C5F65452051 1 22A079D49C5351EFDC1410C81A1F6D8B2E3B79CFF20A30690C118FE2050F72CB 1 0FFC28B923A4654E261DB4CB5B9BABEFCB4DB189B20F52412B0CC9CCCBB8A3B2 1 1EE967C43EF1A3F487061D21B07076A26C126AAF7712E7B5CF5A53688DDD5CC0 1 009ED4D65879CA81DA8227D34CEA3B759B4627E1E2FFB273E9645CD4F3B10F19 1 1CF070212E1E213AEB472F56EDFC9D48009796C77B2D8CC16F2836E37B8715C2 1 04954F0B7B468781BAAE3291DD0E6FFA7F1AF66CAA4094D37B24363CC34606FB 1 115367CB755E9DB18781B3825CB1AEE2C334558B2C038E13DF57BB57CE1CF847 1 110D37EC05862EE2757A7DF39E814876FC97376FF8105D2D29619CB575537BDE 1 13C559A9563FCE083B3B39AE7E8FCA4099BEF3A4C8C6672E543D521F9DA88F96 1 137D87CC22ACC1B6B8C20EABE59F6ED456A58FE4CBEEFDFC4FA9B87E3EF32D17 1 00A2A9711737AAF0404F35AE502887AC6172B2B57D236BD4A40B45F659BFC696', - }, - }, - tailsHash: 'HLKresYcDSZYSKogq8wive4zyXNY84669MygftLFBG1i', - tailsLocation: '/var/folders/l3/xy8jzyvj4p5_d9g1123rt4bw0000gn/T/HLKresYcDSZYSKogq8wive4zyXNY84669MygftLFBG1i', - }, - ver: '1.0', - }) - - await indySdkPoolService.submitWriteRequest(agent.context, pool, revocationRegistryRequest, signingKey) - - // indySdk.buildRevRegEntry panics, so we just pass a custom request directly - const entryResponse = await indySdkPoolService.submitWriteRequest( - agent.context, - pool, - { - identifier: legacyIssuerId, - operation: { - revocDefType: 'CL_ACCUM', - revocRegDefId: legacyRevocationRegistryId, - type: '114', - value: { - accum: - '1 0000000000000000000000000000000000000000000000000000000000000000 1 0000000000000000000000000000000000000000000000000000000000000000 2 095E45DDF417D05FB10933FFC63D474548B7FFFF7888802F07FFFFFF7D07A8A8 1 0000000000000000000000000000000000000000000000000000000000000000 1 0000000000000000000000000000000000000000000000000000000000000000 1 0000000000000000000000000000000000000000000000000000000000000000', - }, - }, - protocolVersion: 2, - reqId: Math.floor(Math.random() * 1000000), - }, - signingKey - ) - - const legacyRevocationRegistryDefinition = await indySdkAnonCredsRegistry.getRevocationRegistryDefinition( - agent.context, - legacyRevocationRegistryId - ) - expect(legacyRevocationRegistryDefinition).toMatchObject({ - revocationRegistryDefinitionId: legacyRevocationRegistryId, - revocationRegistryDefinition: { - issuerId: legacyIssuerId, - revocDefType: 'CL_ACCUM', - value: { - maxCredNum: 100, - tailsHash: 'HLKresYcDSZYSKogq8wive4zyXNY84669MygftLFBG1i', - tailsLocation: - '/var/folders/l3/xy8jzyvj4p5_d9g1123rt4bw0000gn/T/HLKresYcDSZYSKogq8wive4zyXNY84669MygftLFBG1i', - publicKeys: { - accumKey: { - z: '1 1812B206EB395D3AEBD4BBF53EBB0FFC3371D8BD6175316AB32C1C5F65452051 1 22A079D49C5351EFDC1410C81A1F6D8B2E3B79CFF20A30690C118FE2050F72CB 1 0FFC28B923A4654E261DB4CB5B9BABEFCB4DB189B20F52412B0CC9CCCBB8A3B2 1 1EE967C43EF1A3F487061D21B07076A26C126AAF7712E7B5CF5A53688DDD5CC0 1 009ED4D65879CA81DA8227D34CEA3B759B4627E1E2FFB273E9645CD4F3B10F19 1 1CF070212E1E213AEB472F56EDFC9D48009796C77B2D8CC16F2836E37B8715C2 1 04954F0B7B468781BAAE3291DD0E6FFA7F1AF66CAA4094D37B24363CC34606FB 1 115367CB755E9DB18781B3825CB1AEE2C334558B2C038E13DF57BB57CE1CF847 1 110D37EC05862EE2757A7DF39E814876FC97376FF8105D2D29619CB575537BDE 1 13C559A9563FCE083B3B39AE7E8FCA4099BEF3A4C8C6672E543D521F9DA88F96 1 137D87CC22ACC1B6B8C20EABE59F6ED456A58FE4CBEEFDFC4FA9B87E3EF32D17 1 00A2A9711737AAF0404F35AE502887AC6172B2B57D236BD4A40B45F659BFC696', - }, - }, - }, - tag: 'tag', - credDefId: legacyCredentialDefinitionId, - }, - revocationRegistryDefinitionMetadata: { - issuanceType: 'ISSUANCE_BY_DEFAULT', - didIndyNamespace: 'pool:localtest', - }, - resolutionMetadata: {}, - }) - - const didIndyRevocationRegistryDefinition = await indySdkAnonCredsRegistry.getRevocationRegistryDefinition( - agent.context, - didIndyRevocationRegistryId - ) - expect(didIndyRevocationRegistryDefinition).toMatchObject({ - revocationRegistryDefinitionId: didIndyRevocationRegistryId, - revocationRegistryDefinition: { - issuerId: didIndyIssuerId, - revocDefType: 'CL_ACCUM', - value: { - maxCredNum: 100, - tailsHash: 'HLKresYcDSZYSKogq8wive4zyXNY84669MygftLFBG1i', - tailsLocation: - '/var/folders/l3/xy8jzyvj4p5_d9g1123rt4bw0000gn/T/HLKresYcDSZYSKogq8wive4zyXNY84669MygftLFBG1i', - publicKeys: { - accumKey: { - z: '1 1812B206EB395D3AEBD4BBF53EBB0FFC3371D8BD6175316AB32C1C5F65452051 1 22A079D49C5351EFDC1410C81A1F6D8B2E3B79CFF20A30690C118FE2050F72CB 1 0FFC28B923A4654E261DB4CB5B9BABEFCB4DB189B20F52412B0CC9CCCBB8A3B2 1 1EE967C43EF1A3F487061D21B07076A26C126AAF7712E7B5CF5A53688DDD5CC0 1 009ED4D65879CA81DA8227D34CEA3B759B4627E1E2FFB273E9645CD4F3B10F19 1 1CF070212E1E213AEB472F56EDFC9D48009796C77B2D8CC16F2836E37B8715C2 1 04954F0B7B468781BAAE3291DD0E6FFA7F1AF66CAA4094D37B24363CC34606FB 1 115367CB755E9DB18781B3825CB1AEE2C334558B2C038E13DF57BB57CE1CF847 1 110D37EC05862EE2757A7DF39E814876FC97376FF8105D2D29619CB575537BDE 1 13C559A9563FCE083B3B39AE7E8FCA4099BEF3A4C8C6672E543D521F9DA88F96 1 137D87CC22ACC1B6B8C20EABE59F6ED456A58FE4CBEEFDFC4FA9B87E3EF32D17 1 00A2A9711737AAF0404F35AE502887AC6172B2B57D236BD4A40B45F659BFC696', - }, - }, - }, - tag: 'tag', - credDefId: didIndyCredentialDefinitionId, - }, - revocationRegistryDefinitionMetadata: { - issuanceType: 'ISSUANCE_BY_DEFAULT', - didIndyNamespace: 'pool:localtest', - }, - resolutionMetadata: {}, - }) - - const legacyRevocationStatusList = await indySdkAnonCredsRegistry.getRevocationStatusList( - agent.context, - legacyRevocationRegistryId, - entryResponse.result.txnMetadata.txnTime - ) - - expect(legacyRevocationStatusList).toMatchObject({ - resolutionMetadata: {}, - revocationStatusList: { - issuerId: legacyIssuerId, - currentAccumulator: - '1 0000000000000000000000000000000000000000000000000000000000000000 1 0000000000000000000000000000000000000000000000000000000000000000 2 095E45DDF417D05FB10933FFC63D474548B7FFFF7888802F07FFFFFF7D07A8A8 1 0000000000000000000000000000000000000000000000000000000000000000 1 0000000000000000000000000000000000000000000000000000000000000000 1 0000000000000000000000000000000000000000000000000000000000000000', - revRegDefId: legacyRevocationRegistryId, - revocationList: [ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - ], - timestamp: entryResponse.result.txnMetadata.txnTime, - }, - revocationStatusListMetadata: { - didIndyNamespace: 'pool:localtest', - }, - }) - - const didIndyRevocationStatusList = await indySdkAnonCredsRegistry.getRevocationStatusList( - agent.context, - didIndyRevocationRegistryId, - entryResponse.result.txnMetadata.txnTime - ) - - expect(didIndyRevocationStatusList).toMatchObject({ - resolutionMetadata: {}, - revocationStatusList: { - issuerId: didIndyIssuerId, - currentAccumulator: - '1 0000000000000000000000000000000000000000000000000000000000000000 1 0000000000000000000000000000000000000000000000000000000000000000 2 095E45DDF417D05FB10933FFC63D474548B7FFFF7888802F07FFFFFF7D07A8A8 1 0000000000000000000000000000000000000000000000000000000000000000 1 0000000000000000000000000000000000000000000000000000000000000000 1 0000000000000000000000000000000000000000000000000000000000000000', - revRegDefId: didIndyRevocationRegistryId, - revocationList: [ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - ], - timestamp: entryResponse.result.txnMetadata.txnTime, - }, - revocationStatusListMetadata: { - didIndyNamespace: 'pool:localtest', - }, - }) - }) -}) diff --git a/packages/indy-sdk/tests/postgres.e2e.test.ts b/packages/indy-sdk/tests/postgres.e2e.test.ts deleted file mode 100644 index a59359f9d8..0000000000 --- a/packages/indy-sdk/tests/postgres.e2e.test.ts +++ /dev/null @@ -1,112 +0,0 @@ -/* eslint-disable @typescript-eslint/no-non-null-assertion */ -import type { SubjectMessage } from '../../../tests/transport/SubjectInboundTransport' -import type { ConnectionRecord } from '../../core/src/modules/connections' -import type { IndySdkPostgresStorageConfig } from '../../node/src' - -import { Subject } from 'rxjs' - -import { SubjectInboundTransport } from '../../../tests/transport/SubjectInboundTransport' -import { SubjectOutboundTransport } from '../../../tests/transport/SubjectOutboundTransport' -import { Agent } from '../../core/src/agent/Agent' -import { HandshakeProtocol } from '../../core/src/modules/connections' -import { waitForBasicMessage, getPostgresAgentOptions } from '../../core/tests/helpers' -import { loadIndySdkPostgresPlugin, IndySdkPostgresWalletScheme } from '../../node/src' - -import { getIndySdkModules } from './setupIndySdkModule' - -const alicePostgresAgentOptions = getPostgresAgentOptions( - 'AgentsAlice', - { - endpoints: ['rxjs:alice'], - }, - getIndySdkModules() -) - -const bobPostgresAgentOptions = getPostgresAgentOptions( - 'AgentsBob', - { - endpoints: ['rxjs:bob'], - }, - getIndySdkModules() -) - -describe('postgres agents', () => { - let aliceAgent: Agent - let bobAgent: Agent - let aliceConnection: ConnectionRecord - - afterAll(async () => { - await bobAgent.shutdown() - await bobAgent.wallet.delete() - await aliceAgent.shutdown() - await aliceAgent.wallet.delete() - }) - - test('make a connection between postgres agents', async () => { - const aliceMessages = new Subject() - const bobMessages = new Subject() - - const subjectMap = { - 'rxjs:alice': aliceMessages, - 'rxjs:bob': bobMessages, - } - - const storageConfig: IndySdkPostgresStorageConfig = { - type: 'postgres_storage', - config: { - url: 'localhost:5432', - wallet_scheme: IndySdkPostgresWalletScheme.DatabasePerWallet, - }, - credentials: { - account: 'postgres', - password: 'postgres', - admin_account: 'postgres', - admin_password: 'postgres', - }, - } - - // loading the postgres wallet plugin - loadIndySdkPostgresPlugin(storageConfig.config, storageConfig.credentials) - - aliceAgent = new Agent(alicePostgresAgentOptions) - aliceAgent.registerInboundTransport(new SubjectInboundTransport(aliceMessages)) - aliceAgent.registerOutboundTransport(new SubjectOutboundTransport(subjectMap)) - await aliceAgent.initialize() - - bobAgent = new Agent(bobPostgresAgentOptions) - bobAgent.registerInboundTransport(new SubjectInboundTransport(bobMessages)) - bobAgent.registerOutboundTransport(new SubjectOutboundTransport(subjectMap)) - await bobAgent.initialize() - - const aliceBobOutOfBandRecord = await aliceAgent.oob.createInvitation({ - handshakeProtocols: [HandshakeProtocol.Connections], - }) - - const { connectionRecord: bobConnectionAtBobAlice } = await bobAgent.oob.receiveInvitation( - aliceBobOutOfBandRecord.outOfBandInvitation - ) - await bobAgent.connections.returnWhenIsConnected(bobConnectionAtBobAlice!.id) - - const [aliceConnectionAtAliceBob] = await aliceAgent.connections.findAllByOutOfBandId(aliceBobOutOfBandRecord.id) - aliceConnection = await aliceAgent.connections.returnWhenIsConnected(aliceConnectionAtAliceBob!.id) - }) - - test('send a message to connection', async () => { - const message = 'hello, world' - await aliceAgent.basicMessages.sendMessage(aliceConnection.id, message) - - const basicMessage = await waitForBasicMessage(bobAgent, { - content: message, - }) - - expect(basicMessage.content).toBe(message) - }) - - test('can shutdown and re-initialize the same postgres agent', async () => { - expect(aliceAgent.isInitialized).toBe(true) - await aliceAgent.shutdown() - expect(aliceAgent.isInitialized).toBe(false) - await aliceAgent.initialize() - expect(aliceAgent.isInitialized).toBe(true) - }) -}) diff --git a/packages/indy-sdk/tests/setup.ts b/packages/indy-sdk/tests/setup.ts deleted file mode 100644 index 34e38c9705..0000000000 --- a/packages/indy-sdk/tests/setup.ts +++ /dev/null @@ -1 +0,0 @@ -jest.setTimeout(120000) diff --git a/packages/indy-sdk/tests/setupIndySdkModule.ts b/packages/indy-sdk/tests/setupIndySdkModule.ts deleted file mode 100644 index 2cc5a4f988..0000000000 --- a/packages/indy-sdk/tests/setupIndySdkModule.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { DidsModule, utils } from '@credo-ts/core' -import indySdk from 'indy-sdk' - -import { genesisPath, taaVersion, taaAcceptanceMechanism } from '../../core/tests/helpers' -import { - IndySdkModule, - IndySdkModuleConfig, - IndySdkIndyDidRegistrar, - IndySdkSovDidResolver, - IndySdkIndyDidResolver, -} from '../src' - -export { indySdk } - -export const getIndySdkModuleConfig = () => - new IndySdkModuleConfig({ - indySdk, - networks: [ - { - id: `localhost-${utils.uuid()}`, - isProduction: false, - genesisPath, - indyNamespace: 'pool:localtest', - transactionAuthorAgreement: { version: taaVersion, acceptanceMechanism: taaAcceptanceMechanism }, - }, - ], - }) - -export const getIndySdkModules = () => ({ - indySdk: new IndySdkModule(getIndySdkModuleConfig()), - dids: new DidsModule({ - registrars: [new IndySdkIndyDidRegistrar()], - resolvers: [new IndySdkSovDidResolver(), new IndySdkIndyDidResolver()], - }), -}) diff --git a/packages/indy-sdk/tests/sov-did-resolver.e2e.test.ts b/packages/indy-sdk/tests/sov-did-resolver.e2e.test.ts deleted file mode 100644 index 7cceab928a..0000000000 --- a/packages/indy-sdk/tests/sov-did-resolver.e2e.test.ts +++ /dev/null @@ -1,102 +0,0 @@ -import type { IndySdkIndyDidCreateOptions } from '../src' - -import { parseIndyDid } from '@credo-ts/anoncreds' -import { Agent, AriesFrameworkError, JsonTransformer, TypedArrayEncoder } from '@credo-ts/core' - -import { getAgentOptions, importExistingIndyDidFromPrivateKey, publicDidSeed } from '../../core/tests/helpers' - -import { getIndySdkModules } from './setupIndySdkModule' - -const agent = new Agent(getAgentOptions('Indy SDK Sov DID resolver', {}, getIndySdkModules())) - -describe('Indy SDK Sov DID resolver', () => { - beforeAll(async () => { - await agent.initialize() - }) - - afterAll(async () => { - await agent.shutdown() - await agent.wallet.delete() - }) - - test('resolve a did:sov did', async () => { - // Add existing endorser did to the wallet - const unqualifiedSubmitterDid = await importExistingIndyDidFromPrivateKey( - agent, - TypedArrayEncoder.fromString(publicDidSeed) - ) - - const createResult = await agent.dids.create({ - method: 'indy', - options: { - submitterDid: `did:indy:pool:localtest:${unqualifiedSubmitterDid}`, - alias: 'Alias', - role: 'TRUSTEE', - endpoints: { - endpoint: 'http://localhost:3000', - }, - }, - }) - - // Terrible, but the did can't be immediately resolved, so we need to wait a bit - await new Promise((res) => setTimeout(res, 1000)) - - if (!createResult.didState.did) throw new AriesFrameworkError('Unable to register did') - - const { namespaceIdentifier } = parseIndyDid(createResult.didState.did) - const sovDid = `did:sov:${namespaceIdentifier}` - const didResult = await agent.dids.resolve(sovDid) - - expect(JsonTransformer.toJSON(didResult)).toMatchObject({ - didDocument: { - '@context': [ - 'https://w3id.org/did/v1', - 'https://w3id.org/security/suites/ed25519-2018/v1', - 'https://w3id.org/security/suites/x25519-2019/v1', - ], - id: sovDid, - alsoKnownAs: undefined, - controller: undefined, - verificationMethod: [ - { - type: 'Ed25519VerificationKey2018', - controller: sovDid, - id: `${sovDid}#key-1`, - publicKeyBase58: expect.any(String), - }, - { - controller: sovDid, - type: 'X25519KeyAgreementKey2019', - id: `${sovDid}#key-agreement-1`, - publicKeyBase58: expect.any(String), - }, - ], - capabilityDelegation: undefined, - capabilityInvocation: undefined, - authentication: [`${sovDid}#key-1`], - assertionMethod: [`${sovDid}#key-1`], - keyAgreement: [`${sovDid}#key-agreement-1`], - service: [ - { - id: `${sovDid}#endpoint`, - serviceEndpoint: 'http://localhost:3000', - type: 'endpoint', - }, - { - id: `${sovDid}#did-communication`, - accept: ['didcomm/aip2;env=rfc19'], - priority: 0, - recipientKeys: [`${sovDid}#key-agreement-1`], - routingKeys: [], - serviceEndpoint: 'http://localhost:3000', - type: 'did-communication', - }, - ], - }, - didDocumentMetadata: {}, - didResolutionMetadata: { - contentType: 'application/did+ld+json', - }, - }) - }) -}) diff --git a/packages/indy-sdk/tsconfig.build.json b/packages/indy-sdk/tsconfig.build.json deleted file mode 100644 index 2b75d0adab..0000000000 --- a/packages/indy-sdk/tsconfig.build.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "extends": "../../tsconfig.build.json", - "compilerOptions": { - "outDir": "./build" - }, - "include": ["src/**/*"] -} diff --git a/packages/indy-sdk/tsconfig.json b/packages/indy-sdk/tsconfig.json deleted file mode 100644 index 46efe6f721..0000000000 --- a/packages/indy-sdk/tsconfig.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "extends": "../../tsconfig.json", - "compilerOptions": { - "types": ["jest"] - } -} diff --git a/packages/indy-vdr/src/IndyVdrModule.ts b/packages/indy-vdr/src/IndyVdrModule.ts index c9593c1be8..85e48bc1af 100644 --- a/packages/indy-vdr/src/IndyVdrModule.ts +++ b/packages/indy-vdr/src/IndyVdrModule.ts @@ -23,7 +23,7 @@ export class IndyVdrModule implements Module { dependencyManager .resolve(AgentConfig) .logger.warn( - "The '@credo-ts/indy-vdr' module is experimental and could have unexpected breaking changes. When using this module, make sure to use strict versions for all @aries-framework packages." + "The '@credo-ts/indy-vdr' module is experimental and could have unexpected breaking changes. When using this module, make sure to use strict versions for all @credo-ts packages." ) // Config diff --git a/packages/indy-vdr/src/anoncreds/IndyVdrAnonCredsRegistry.ts b/packages/indy-vdr/src/anoncreds/IndyVdrAnonCredsRegistry.ts index 7be534ad28..3d93942bd4 100644 --- a/packages/indy-vdr/src/anoncreds/IndyVdrAnonCredsRegistry.ts +++ b/packages/indy-vdr/src/anoncreds/IndyVdrAnonCredsRegistry.ts @@ -478,11 +478,11 @@ export class IndyVdrAnonCredsRegistry implements AnonCredsRegistry { revocationRegistryDefinitionId: string ): Promise { try { - const indySdkPoolService = agentContext.dependencyManager.resolve(IndyVdrPoolService) + const indyVdrPoolService = agentContext.dependencyManager.resolve(IndyVdrPoolService) const { did, namespaceIdentifier, credentialDefinitionTag, revocationRegistryTag, schemaSeqNo } = parseIndyRevocationRegistryId(revocationRegistryDefinitionId) - const { pool } = await indySdkPoolService.getPoolForDid(agentContext, did) + const { pool } = await indyVdrPoolService.getPoolForDid(agentContext, did) agentContext.config.logger.debug( `Using ledger '${pool.indyNamespace}' to retrieve revocation registry definition '${revocationRegistryDefinitionId}'` diff --git a/packages/indy-vdr/src/anoncreds/utils/identifiers.ts b/packages/indy-vdr/src/anoncreds/utils/identifiers.ts index caac46d966..7681a51327 100644 --- a/packages/indy-vdr/src/anoncreds/utils/identifiers.ts +++ b/packages/indy-vdr/src/anoncreds/utils/identifiers.ts @@ -1,8 +1,3 @@ -/** - * NOTE: this file is availalbe in both the indy-sdk and indy-vdr packages. If making changes to - * this file, make sure to update both files if applicable. - */ - import { unqualifiedSchemaIdRegex, unqualifiedCredentialDefinitionIdRegex, diff --git a/packages/indy-vdr/src/dids/__tests__/IndyVdrIndyDidRegistrar.test.ts b/packages/indy-vdr/src/dids/__tests__/IndyVdrIndyDidRegistrar.test.ts index 271e568e25..866f8e7880 100644 --- a/packages/indy-vdr/src/dids/__tests__/IndyVdrIndyDidRegistrar.test.ts +++ b/packages/indy-vdr/src/dids/__tests__/IndyVdrIndyDidRegistrar.test.ts @@ -14,15 +14,14 @@ import { Key, KeyType, RepositoryEventTypes, - SigningProviderRegistry, TypedArrayEncoder, VerificationMethod, } from '@credo-ts/core' import { Subject } from 'rxjs' import { InMemoryStorageService } from '../../../../../tests/InMemoryStorageService' -import { agentDependencies, getAgentConfig, getAgentContext, indySdk, mockProperty } from '../../../../core/tests' -import { IndySdkWallet } from '../../../../indy-sdk/src' +import { InMemoryWallet } from '../../../../../tests/InMemoryWallet' +import { agentDependencies, getAgentConfig, getAgentContext, mockProperty } from '../../../../core/tests' import { IndyVdrPool, IndyVdrPoolService } from '../../pool' import { IndyVdrIndyDidRegistrar } from '../IndyVdrIndyDidRegistrar' @@ -32,8 +31,7 @@ const poolMock = new IndyVdrPoolMock() mockProperty(poolMock, 'indyNamespace', 'ns1') const agentConfig = getAgentConfig('IndyVdrIndyDidRegistrar') - -const wallet = new IndySdkWallet(indySdk, agentConfig.logger, new SigningProviderRegistry([])) +const wallet = new InMemoryWallet() jest .spyOn(wallet, 'createKey') diff --git a/packages/indy-vdr/tests/indy-vdr-anoncreds-registry.e2e.test.ts b/packages/indy-vdr/tests/indy-vdr-anoncreds-registry.e2e.test.ts index dd0b3e1e6a..211066e7f6 100644 --- a/packages/indy-vdr/tests/indy-vdr-anoncreds-registry.e2e.test.ts +++ b/packages/indy-vdr/tests/indy-vdr-anoncreds-registry.e2e.test.ts @@ -8,9 +8,7 @@ import { import { Agent, DidsModule, TypedArrayEncoder } from '@credo-ts/core' import { indyVdr } from '@hyperledger/indy-vdr-nodejs' -import { agentDependencies, getAgentConfig, importExistingIndyDidFromPrivateKey } from '../../core/tests/helpers' -import { IndySdkModule } from '../../indy-sdk/src' -import { indySdk } from '../../indy-sdk/tests/setupIndySdkModule' +import { getInMemoryAgentOptions, importExistingIndyDidFromPrivateKey } from '../../core/tests/helpers' import { IndyVdrIndyDidResolver, IndyVdrModule, IndyVdrSovDidResolver } from '../src' import { IndyVdrAnonCredsRegistry } from '../src/anoncreds/IndyVdrAnonCredsRegistry' import { IndyVdrIndyDidRegistrar } from '../src/dids/IndyVdrIndyDidRegistrar' @@ -19,49 +17,45 @@ import { IndyVdrPoolService } from '../src/pool' import { credentialDefinitionValue, revocationRegistryDefinitionValue } from './__fixtures__/anoncreds' import { indyVdrModuleConfig } from './helpers' -const endorserConfig = getAgentConfig('IndyVdrAnonCredsRegistryEndorser') -const agentConfig = getAgentConfig('IndyVdrAnonCredsRegistryAgent') - const indyVdrAnonCredsRegistry = new IndyVdrAnonCredsRegistry() -const endorser = new Agent({ - config: endorserConfig, - dependencies: agentDependencies, - modules: { - indyVdr: new IndyVdrModule({ - indyVdr, - networks: indyVdrModuleConfig.networks, - }), - indySdk: new IndySdkModule({ - indySdk, - }), - dids: new DidsModule({ - registrars: [new IndyVdrIndyDidRegistrar()], - resolvers: [new IndyVdrSovDidResolver(), new IndyVdrIndyDidResolver()], - }), - }, -}) - -const agent = new Agent({ - config: agentConfig, - dependencies: agentDependencies, - modules: { - indyVdr: new IndyVdrModule({ - indyVdr, - networks: indyVdrModuleConfig.networks, - }), - indySdk: new IndySdkModule({ - indySdk, - }), - dids: new DidsModule({ - registrars: [new IndyVdrIndyDidRegistrar()], - resolvers: [new IndyVdrSovDidResolver(), new IndyVdrIndyDidResolver()], - }), - }, -}) +const endorser = new Agent( + getInMemoryAgentOptions( + 'IndyVdrAnonCredsRegistryEndorser', + {}, + { + indyVdr: new IndyVdrModule({ + indyVdr, + networks: indyVdrModuleConfig.networks, + }), + dids: new DidsModule({ + registrars: [new IndyVdrIndyDidRegistrar()], + resolvers: [new IndyVdrSovDidResolver(), new IndyVdrIndyDidResolver()], + }), + } + ) +) + +const agent = new Agent( + getInMemoryAgentOptions( + 'IndyVdrAnonCredsRegistryAgent', + {}, + { + indyVdr: new IndyVdrModule({ + indyVdr, + networks: indyVdrModuleConfig.networks, + }), + dids: new DidsModule({ + registrars: [new IndyVdrIndyDidRegistrar()], + resolvers: [new IndyVdrSovDidResolver(), new IndyVdrIndyDidResolver()], + }), + } + ) +) const indyVdrPoolService = endorser.dependencyManager.resolve(IndyVdrPoolService) +// FIXME: this test is very slow, probably due to the sleeps. Can we speed it up? describe('IndyVdrAnonCredsRegistry', () => { let endorserDid: string beforeAll(async () => { diff --git a/packages/indy-vdr/tests/indy-vdr-did-registrar.e2e.test.ts b/packages/indy-vdr/tests/indy-vdr-did-registrar.e2e.test.ts index c8ea5738a9..9cd8063c7e 100644 --- a/packages/indy-vdr/tests/indy-vdr-did-registrar.e2e.test.ts +++ b/packages/indy-vdr/tests/indy-vdr-did-registrar.e2e.test.ts @@ -15,10 +15,11 @@ import { import { indyVdr } from '@hyperledger/indy-vdr-nodejs' import { convertPublicKeyToX25519, generateKeyPairFromSeed } from '@stablelib/ed25519' -import { sleep } from '../../core/src/utils/sleep' -import { getAgentOptions, importExistingIndyDidFromPrivateKey } from '../../core/tests/helpers' -import { IndySdkModule } from '../../indy-sdk/src' -import { indySdk } from '../../indy-sdk/tests/setupIndySdkModule' +import { + getInMemoryAgentOptions, + importExistingIndyDidFromPrivateKey, + retryUntilResult, +} from '../../core/tests/helpers' import { IndyVdrModule, IndyVdrSovDidResolver } from '../src' import { IndyVdrIndyDidRegistrar } from '../src/dids/IndyVdrIndyDidRegistrar' import { IndyVdrIndyDidResolver } from '../src/dids/IndyVdrIndyDidResolver' @@ -27,7 +28,7 @@ import { indyDidFromNamespaceAndInitialKey } from '../src/dids/didIndyUtil' import { indyVdrModuleConfig } from './helpers' const endorser = new Agent( - getAgentOptions( + getInMemoryAgentOptions( 'Indy VDR Indy DID Registrar', {}, { @@ -35,9 +36,6 @@ const endorser = new Agent( networks: indyVdrModuleConfig.networks, indyVdr, }), - indySdk: new IndySdkModule({ - indySdk, - }), dids: new DidsModule({ registrars: [new IndyVdrIndyDidRegistrar()], resolvers: [new IndyVdrIndyDidResolver(), new IndyVdrSovDidResolver()], @@ -46,7 +44,7 @@ const endorser = new Agent( ) ) const agent = new Agent( - getAgentOptions( + getInMemoryAgentOptions( 'Indy VDR Indy DID Registrar', {}, { @@ -54,9 +52,6 @@ const agent = new Agent( indyVdr, networks: indyVdrModuleConfig.networks, }), - indySdk: new IndySdkModule({ - indySdk, - }), dids: new DidsModule({ registrars: [new IndyVdrIndyDidRegistrar()], resolvers: [new IndyVdrIndyDidResolver(), new IndyVdrSovDidResolver()], @@ -125,33 +120,31 @@ describe('Indy VDR Indy Did Registrar', () => { const did = didRegistrationResult.didState.did if (!did) throw Error('did not defined') - // Wait some time pass to let ledger settle the object - await sleep(1000) - - const didResolutionResult = await endorser.dids.resolve(did) - expect(JsonTransformer.toJSON(didResolutionResult)).toMatchObject({ - didDocument: { - '@context': ['https://w3id.org/did/v1', 'https://w3id.org/security/suites/ed25519-2018/v1'], - id: did, - alsoKnownAs: undefined, - controller: undefined, - verificationMethod: [ - { - type: 'Ed25519VerificationKey2018', - controller: did, - id: `${did}#verkey`, - publicKeyBase58: expect.any(String), - }, - ], - capabilityDelegation: undefined, - capabilityInvocation: undefined, - authentication: [`${did}#verkey`], - service: undefined, - }, - didDocumentMetadata: {}, - didResolutionMetadata: { - contentType: 'application/did+ld+json', - }, + // Tries to call it in an interval until it succeeds (with maxAttempts) + // As the ledger write is not always consistent in how long it takes + // to write the data, we need to retry until we get a result. + const didDocument = await retryUntilResult(async () => { + const result = await endorser.dids.resolve(did) + return result.didDocument + }) + + expect(JsonTransformer.toJSON(didDocument)).toMatchObject({ + '@context': ['https://w3id.org/did/v1', 'https://w3id.org/security/suites/ed25519-2018/v1'], + id: did, + alsoKnownAs: undefined, + controller: undefined, + verificationMethod: [ + { + type: 'Ed25519VerificationKey2018', + controller: did, + id: `${did}#verkey`, + publicKeyBase58: expect.any(String), + }, + ], + capabilityDelegation: undefined, + capabilityInvocation: undefined, + authentication: [`${did}#verkey`], + service: undefined, }) }) @@ -210,6 +203,9 @@ describe('Indy VDR Indy Did Registrar', () => { secret: didState.secret, }) + if (didCreateSubmitResult.didState.state !== 'finished') { + throw new Error(`Unexpected did state, ${JSON.stringify(didCreateSubmitResult.didState, null, 2)}`) + } expect(JsonTransformer.toJSON(didCreateSubmitResult)).toMatchObject({ didDocumentMetadata: {}, didRegistrationMetadata: {}, @@ -237,33 +233,31 @@ describe('Indy VDR Indy Did Registrar', () => { }, }) - // Wait some time pass to let ledger settle the object - await sleep(1000) - - const didResult = await endorser.dids.resolve(did) - expect(JsonTransformer.toJSON(didResult)).toMatchObject({ - didDocument: { - '@context': ['https://w3id.org/did/v1', 'https://w3id.org/security/suites/ed25519-2018/v1'], - id: did, - alsoKnownAs: undefined, - controller: undefined, - verificationMethod: [ - { - type: 'Ed25519VerificationKey2018', - controller: did, - id: `${did}#verkey`, - publicKeyBase58: ed25519PublicKeyBase58, - }, - ], - capabilityDelegation: undefined, - capabilityInvocation: undefined, - authentication: [`${did}#verkey`], - service: undefined, - }, - didDocumentMetadata: {}, - didResolutionMetadata: { - contentType: 'application/did+ld+json', - }, + // Tries to call it in an interval until it succeeds (with maxAttempts) + // As the ledger write is not always consistent in how long it takes + // to write the data, we need to retry until we get a result. + const didDocument = await retryUntilResult(async () => { + const result = await endorser.dids.resolve(did) + return result.didDocument + }) + + expect(JsonTransformer.toJSON(didDocument)).toMatchObject({ + '@context': ['https://w3id.org/did/v1', 'https://w3id.org/security/suites/ed25519-2018/v1'], + id: did, + alsoKnownAs: undefined, + controller: undefined, + verificationMethod: [ + { + type: 'Ed25519VerificationKey2018', + controller: did, + id: `${did}#verkey`, + publicKeyBase58: ed25519PublicKeyBase58, + }, + ], + capabilityDelegation: undefined, + capabilityInvocation: undefined, + authentication: [`${did}#verkey`], + service: undefined, }) }) @@ -317,33 +311,31 @@ describe('Indy VDR Indy Did Registrar', () => { }, }) - // Wait some time pass to let ledger settle the object - await sleep(1000) - - const didResult = await endorser.dids.resolve(did) - expect(JsonTransformer.toJSON(didResult)).toMatchObject({ - didDocument: { - '@context': ['https://w3id.org/did/v1', 'https://w3id.org/security/suites/ed25519-2018/v1'], - id: did, - alsoKnownAs: undefined, - controller: undefined, - verificationMethod: [ - { - type: 'Ed25519VerificationKey2018', - controller: did, - id: `${did}#verkey`, - publicKeyBase58: ed25519PublicKeyBase58, - }, - ], - capabilityDelegation: undefined, - capabilityInvocation: undefined, - authentication: [`${did}#verkey`], - service: undefined, - }, - didDocumentMetadata: {}, - didResolutionMetadata: { - contentType: 'application/did+ld+json', - }, + // Tries to call it in an interval until it succeeds (with maxAttempts) + // As the ledger write is not always consistent in how long it takes + // to write the data, we need to retry until we get a result. + const didDocument = await retryUntilResult(async () => { + const result = await endorser.dids.resolve(did) + return result.didDocument + }) + + expect(JsonTransformer.toJSON(didDocument)).toMatchObject({ + '@context': ['https://w3id.org/did/v1', 'https://w3id.org/security/suites/ed25519-2018/v1'], + id: did, + alsoKnownAs: undefined, + controller: undefined, + verificationMethod: [ + { + type: 'Ed25519VerificationKey2018', + controller: did, + id: `${did}#verkey`, + publicKeyBase58: ed25519PublicKeyBase58, + }, + ], + capabilityDelegation: undefined, + capabilityInvocation: undefined, + authentication: [`${did}#verkey`], + service: undefined, }) }) @@ -458,17 +450,15 @@ describe('Indy VDR Indy Did Registrar', () => { }, }) - // Wait some time pass to let ledger settle the object - await sleep(1000) - - const didResult = await endorser.dids.resolve(did) - expect(JsonTransformer.toJSON(didResult)).toMatchObject({ - didDocument: expectedDidDocument, - didDocumentMetadata: {}, - didResolutionMetadata: { - contentType: 'application/did+ld+json', - }, + // Tries to call it in an interval until it succeeds (with maxAttempts) + // As the ledger write is not always consistent in how long it takes + // to write the data, we need to retry until we get a result. + const didDocument = await retryUntilResult(async () => { + const result = await endorser.dids.resolve(did) + return result.didDocument }) + + expect(JsonTransformer.toJSON(didDocument)).toMatchObject(expectedDidDocument) }) test('can register an endorsed did:indy with services - did and verkey specified - using attrib endpoint', async () => { @@ -598,6 +588,10 @@ describe('Indy VDR Indy Did Registrar', () => { ], } + if (didCreateSubmitResult.didState.state !== 'finished') { + throw new Error(`Unexpected did state, ${JSON.stringify(didCreateSubmitResult.didState, null, 2)}`) + } + expect(JsonTransformer.toJSON(didCreateSubmitResult)).toMatchObject({ didDocumentMetadata: {}, didRegistrationMetadata: {}, @@ -607,16 +601,15 @@ describe('Indy VDR Indy Did Registrar', () => { didDocument: expectedDidDocument, }, }) - // Wait some time pass to let ledger settle the object - await sleep(1000) - const didResult = await endorser.dids.resolve(did) - expect(JsonTransformer.toJSON(didResult)).toMatchObject({ - didDocument: expectedDidDocument, - didDocumentMetadata: {}, - didResolutionMetadata: { - contentType: 'application/did+ld+json', - }, + // Tries to call it in an interval until it succeeds (with maxAttempts) + // As the ledger write is not always consistent in how long it takes + // to write the data, we need to retry until we get a result. + const didDocument = await retryUntilResult(async () => { + const result = await endorser.dids.resolve(did) + return result.didDocument }) + + expect(JsonTransformer.toJSON(didDocument)).toMatchObject(expectedDidDocument) }) }) diff --git a/packages/indy-vdr/tests/indy-vdr-indy-did-resolver.e2e.test.ts b/packages/indy-vdr/tests/indy-vdr-indy-did-resolver.e2e.test.ts index b344de08b5..1d7a8f9373 100644 --- a/packages/indy-vdr/tests/indy-vdr-indy-did-resolver.e2e.test.ts +++ b/packages/indy-vdr/tests/indy-vdr-indy-did-resolver.e2e.test.ts @@ -1,16 +1,14 @@ import { DidsModule, Agent, TypedArrayEncoder, JsonTransformer } from '@credo-ts/core' import { indyVdr } from '@hyperledger/indy-vdr-nodejs' -import { getAgentOptions, importExistingIndyDidFromPrivateKey } from '../../core/tests/helpers' -import { IndySdkModule } from '../../indy-sdk/src' -import { indySdk } from '../../indy-sdk/tests/setupIndySdkModule' +import { getInMemoryAgentOptions, importExistingIndyDidFromPrivateKey } from '../../core/tests/helpers' import { IndyVdrModule } from '../src' import { IndyVdrIndyDidRegistrar, IndyVdrIndyDidResolver, IndyVdrSovDidResolver } from '../src/dids' import { createDidOnLedger, indyVdrModuleConfig } from './helpers' const agent = new Agent( - getAgentOptions( + getInMemoryAgentOptions( 'Indy VDR Indy DID resolver', {}, { @@ -18,9 +16,6 @@ const agent = new Agent( indyVdr, networks: indyVdrModuleConfig.networks, }), - indySdk: new IndySdkModule({ - indySdk, - }), dids: new DidsModule({ registrars: [new IndyVdrIndyDidRegistrar()], resolvers: [new IndyVdrIndyDidResolver(), new IndyVdrSovDidResolver()], diff --git a/packages/indy-vdr/tests/indy-vdr-pool.e2e.test.ts b/packages/indy-vdr/tests/indy-vdr-pool.e2e.test.ts index adff66cdd8..ba23c7b384 100644 --- a/packages/indy-vdr/tests/indy-vdr-pool.e2e.test.ts +++ b/packages/indy-vdr/tests/indy-vdr-pool.e2e.test.ts @@ -1,12 +1,11 @@ import type { Key } from '@credo-ts/core' -import { TypedArrayEncoder, KeyType, SigningProviderRegistry } from '@credo-ts/core' +import { TypedArrayEncoder, KeyType } from '@credo-ts/core' import { GetNymRequest, NymRequest, SchemaRequest, CredentialDefinitionRequest } from '@hyperledger/indy-vdr-shared' +import { InMemoryWallet } from '../../../tests/InMemoryWallet' import { genesisTransactions, getAgentConfig, getAgentContext } from '../../core/tests/helpers' import testLogger from '../../core/tests/logger' -import { IndySdkWallet } from '../../indy-sdk/src' -import { indySdk } from '../../indy-sdk/tests/setupIndySdkModule' import { IndyVdrPool } from '../src/pool' import { IndyVdrPoolService } from '../src/pool/IndyVdrPoolService' import { indyDidFromPublicKeyBase58 } from '../src/utils/did' @@ -14,7 +13,7 @@ import { indyDidFromPublicKeyBase58 } from '../src/utils/did' import { indyVdrModuleConfig } from './helpers' const indyVdrPoolService = new IndyVdrPoolService(testLogger, indyVdrModuleConfig) -const wallet = new IndySdkWallet(indySdk, testLogger, new SigningProviderRegistry([])) +const wallet = new InMemoryWallet() const agentConfig = getAgentConfig('IndyVdrPoolService') const agentContext = getAgentContext({ wallet, agentConfig }) diff --git a/packages/indy-vdr/tests/indy-vdr-sov-did-resolver.e2e.test.ts b/packages/indy-vdr/tests/indy-vdr-sov-did-resolver.e2e.test.ts index af73ef9d60..2088c50d51 100644 --- a/packages/indy-vdr/tests/indy-vdr-sov-did-resolver.e2e.test.ts +++ b/packages/indy-vdr/tests/indy-vdr-sov-did-resolver.e2e.test.ts @@ -2,16 +2,14 @@ import { parseIndyDid } from '@credo-ts/anoncreds' import { DidsModule, Agent, TypedArrayEncoder, JsonTransformer } from '@credo-ts/core' import { indyVdr } from '@hyperledger/indy-vdr-nodejs' -import { getAgentOptions, importExistingIndyDidFromPrivateKey } from '../../core/tests/helpers' -import { IndySdkModule } from '../../indy-sdk/src' -import { indySdk } from '../../indy-sdk/tests/setupIndySdkModule' +import { getInMemoryAgentOptions, importExistingIndyDidFromPrivateKey } from '../../core/tests/helpers' import { IndyVdrModule } from '../src' import { IndyVdrIndyDidRegistrar, IndyVdrIndyDidResolver, IndyVdrSovDidResolver } from '../src/dids' import { createDidOnLedger, indyVdrModuleConfig } from './helpers' const agent = new Agent( - getAgentOptions( + getInMemoryAgentOptions( 'Indy VDR Sov DID resolver', {}, { @@ -19,9 +17,6 @@ const agent = new Agent( indyVdr, networks: indyVdrModuleConfig.networks, }), - indySdk: new IndySdkModule({ - indySdk, - }), dids: new DidsModule({ registrars: [new IndyVdrIndyDidRegistrar()], resolvers: [new IndyVdrIndyDidResolver(), new IndyVdrSovDidResolver()], diff --git a/packages/node/src/PostgresPlugin.ts b/packages/node/src/PostgresPlugin.ts deleted file mode 100644 index 22478d2b0a..0000000000 --- a/packages/node/src/PostgresPlugin.ts +++ /dev/null @@ -1,108 +0,0 @@ -import { Library } from '@2060.io/ffi-napi' -import { types } from '@2060.io/ref-napi' -import fs from 'fs' -import os from 'os' -import path from 'path' - -const LIBNAME = 'indystrgpostgres' -const ENV_VAR = 'LIB_INDY_STRG_POSTGRES' - -type Platform = 'darwin' | 'linux' | 'win32' - -type ExtensionMap = Record - -const extensions: ExtensionMap = { - darwin: { prefix: 'lib', extension: '.dylib' }, - linux: { prefix: 'lib', extension: '.so' }, - win32: { extension: '.dll' }, -} - -const libPaths: Record> = { - darwin: ['/usr/local/lib/', '/usr/lib/', '/opt/homebrew/opt/'], - linux: ['/usr/lib/', '/usr/local/lib/'], - win32: ['c:\\windows\\system32\\'], -} - -// Alias for a simple function to check if the path exists -const doesPathExist = fs.existsSync - -const getLibrary = () => { - // Detect OS; darwin, linux and windows are only supported - const platform = os.platform() - - if (platform !== 'linux' && platform !== 'win32' && platform !== 'darwin') - throw new Error(`Unsupported platform: ${platform}. linux, win32 and darwin are supported.`) - - // Get a potential path from the environment variable - const pathFromEnvironment = process.env[ENV_VAR] - - // Get the paths specific to the users operating system - const platformPaths = libPaths[platform] - - // Check if the path from the environment variable is supplied and add it - // We use unshift here so that when we want to get a valid library path this will be the first to resolve - if (pathFromEnvironment) platformPaths.unshift(pathFromEnvironment) - - // Create the path + file - const libraries = platformPaths.map((p) => - path.join(p, `${extensions[platform].prefix ?? ''}${LIBNAME}${extensions[platform].extension}`) - ) - - // Gaurd so we quit if there is no valid path for the library - if (!libraries.some(doesPathExist)) - throw new Error(`Could not find ${LIBNAME} with these paths: ${libraries.join(' ')}`) - - // Get the first valid library - // Casting here as a string because there is a guard of none of the paths - // would be valid - const validLibraryPath = libraries.find((l) => doesPathExist(l)) as string - - return Library(validLibraryPath, { - postgresstorage_init: [types.int, []], - init_storagetype: [types.int, ['string', 'string']], - }) -} - -type NativeIndyPostgres = { - postgresstorage_init: () => number - init_storagetype: (arg0: string, arg1: string) => number -} - -let indyPostgresStorage: NativeIndyPostgres | undefined - -export interface IndySdkPostgresWalletStorageConfig { - url: string - wallet_scheme: IndySdkPostgresWalletScheme - path?: string -} - -export interface IndySdkPostgresWalletStorageCredentials { - account: string - password: string - admin_account: string - admin_password: string -} - -export enum IndySdkPostgresWalletScheme { - DatabasePerWallet = 'DatabasePerWallet', - MultiWalletSingleTable = 'MultiWalletSingleTable', - MultiWalletSingleTableSharedPool = 'MultiWalletSingleTableSharedPool', -} - -export interface IndySdkPostgresStorageConfig { - type: 'postgres_storage' - config: IndySdkPostgresWalletStorageConfig - credentials: IndySdkPostgresWalletStorageCredentials -} - -export function loadIndySdkPostgresPlugin( - config: IndySdkPostgresWalletStorageConfig, - credentials: IndySdkPostgresWalletStorageCredentials -) { - if (!indyPostgresStorage) { - indyPostgresStorage = getLibrary() - } - - indyPostgresStorage.postgresstorage_init() - indyPostgresStorage.init_storagetype(JSON.stringify(config), JSON.stringify(credentials)) -} diff --git a/packages/node/src/index.ts b/packages/node/src/index.ts index a4f231c5da..18d6dfd6a5 100644 --- a/packages/node/src/index.ts +++ b/packages/node/src/index.ts @@ -4,7 +4,6 @@ import { EventEmitter } from 'events' import WebSocket from 'ws' import { NodeFileSystem } from './NodeFileSystem' -import { IndySdkPostgresStorageConfig, loadIndySdkPostgresPlugin, IndySdkPostgresWalletScheme } from './PostgresPlugin' import { HttpInboundTransport } from './transport/HttpInboundTransport' import { WsInboundTransport } from './transport/WsInboundTransport' @@ -15,11 +14,4 @@ const agentDependencies: AgentDependencies = { WebSocketClass: WebSocket, } -export { - agentDependencies, - HttpInboundTransport, - WsInboundTransport, - loadIndySdkPostgresPlugin, - IndySdkPostgresStorageConfig, - IndySdkPostgresWalletScheme, -} +export { agentDependencies, HttpInboundTransport, WsInboundTransport } diff --git a/packages/openid4vc-client/src/OpenId4VcClientModule.ts b/packages/openid4vc-client/src/OpenId4VcClientModule.ts index a6385c76f6..932f90c8b8 100644 --- a/packages/openid4vc-client/src/OpenId4VcClientModule.ts +++ b/packages/openid4vc-client/src/OpenId4VcClientModule.ts @@ -19,7 +19,7 @@ export class OpenId4VcClientModule implements Module { dependencyManager .resolve(AgentConfig) .logger.warn( - "The '@credo-ts/openid4vc-client' module is experimental and could have unexpected breaking changes. When using this module, make sure to use strict versions for all @aries-framework packages." + "The '@credo-ts/openid4vc-client' module is experimental and could have unexpected breaking changes. When using this module, make sure to use strict versions for all @credo-ts packages." ) // Api diff --git a/packages/openid4vc-client/tests/openid4vc-client.e2e.test.ts b/packages/openid4vc-client/tests/openid4vc-client.e2e.test.ts index c4089e2a37..b0a19263af 100644 --- a/packages/openid4vc-client/tests/openid4vc-client.e2e.test.ts +++ b/packages/openid4vc-client/tests/openid4vc-client.e2e.test.ts @@ -12,10 +12,9 @@ import { } from '@credo-ts/core' import nock, { cleanAll, enableNetConnect } from 'nock' -import { AskarModule } from '../../askar/src' -import { askarModuleConfig } from '../../askar/tests/helpers' +import { InMemoryWalletModule } from '../../../tests/InMemoryWalletModule' import { customDocumentLoader } from '../../core/src/modules/vc/data-integrity/__tests__/documentLoader' -import { getAgentOptions } from '../../core/tests' +import { getInMemoryAgentOptions } from '../../core/tests' import { mattrLaunchpadJsonLd, waltIdJffJwt } from './fixtures' @@ -26,23 +25,21 @@ const modules = { w3cCredentials: new W3cCredentialsModule({ documentLoader: customDocumentLoader, }), - askar: new AskarModule(askarModuleConfig), + inMemory: new InMemoryWalletModule(), } describe('OpenId4VcClient', () => { let agent: Agent beforeEach(async () => { - const agentOptions = getAgentOptions('OpenId4VcClient Agent', {}, modules) - + const agentOptions = getInMemoryAgentOptions('OpenId4VcClient Agent', {}, modules) agent = new Agent(agentOptions) - await agent.initialize() }) afterEach(async () => { - await agent.shutdown() await agent.wallet.delete() + await agent.shutdown() }) describe('Pre-authorized flow', () => { diff --git a/packages/question-answer/src/__tests__/QuestionAnswerService.test.ts b/packages/question-answer/src/__tests__/QuestionAnswerService.test.ts index a323bf6e8d..1a45b7c173 100644 --- a/packages/question-answer/src/__tests__/QuestionAnswerService.test.ts +++ b/packages/question-answer/src/__tests__/QuestionAnswerService.test.ts @@ -1,13 +1,12 @@ import type { AgentConfig, AgentContext, Repository, Wallet } from '@credo-ts/core' import type { QuestionAnswerStateChangedEvent, ValidResponse } from '@credo-ts/question-answer' -import { EventEmitter, SigningProviderRegistry, InboundMessageContext, DidExchangeState } from '@credo-ts/core' +import { EventEmitter, InboundMessageContext, DidExchangeState } from '@credo-ts/core' import { agentDependencies } from '@credo-ts/node' import { Subject } from 'rxjs' +import { InMemoryWallet } from '../../../../tests/InMemoryWallet' import { getAgentConfig, getAgentContext, getMockConnection, mockFunction } from '../../../core/tests/helpers' -import { IndySdkWallet } from '../../../indy-sdk/src' -import { indySdk } from '../../../indy-sdk/tests/setupIndySdkModule' import { QuestionAnswerRecord, @@ -61,7 +60,7 @@ describe('QuestionAnswerService', () => { beforeAll(async () => { agentConfig = getAgentConfig('QuestionAnswerServiceTest') - wallet = new IndySdkWallet(indySdk, agentConfig.logger, new SigningProviderRegistry([])) + wallet = new InMemoryWallet() agentContext = getAgentContext() // eslint-disable-next-line @typescript-eslint/no-non-null-assertion await wallet.createAndOpen(agentConfig.walletConfig!) diff --git a/packages/question-answer/tests/question-answer.e2e.test.ts b/packages/question-answer/tests/question-answer.e2e.test.ts index b3576bad3a..dafbc55cdd 100644 --- a/packages/question-answer/tests/question-answer.e2e.test.ts +++ b/packages/question-answer/tests/question-answer.e2e.test.ts @@ -2,8 +2,7 @@ import type { ConnectionRecord } from '@credo-ts/core' import { Agent } from '@credo-ts/core' -import { indySdk, setupSubjectTransports, testLogger, getAgentOptions, makeConnection } from '../../core/tests' -import { IndySdkModule } from '../../indy-sdk/src' +import { setupSubjectTransports, testLogger, makeConnection, getInMemoryAgentOptions } from '../../core/tests' import { waitForQuestionAnswerRecord } from './helpers' @@ -11,12 +10,9 @@ import { QuestionAnswerModule, QuestionAnswerRole, QuestionAnswerState } from '@ const modules = { questionAnswer: new QuestionAnswerModule(), - indySdk: new IndySdkModule({ - indySdk, - }), } -const bobAgentOptions = getAgentOptions( +const bobAgentOptions = getInMemoryAgentOptions( 'Bob Question Answer', { endpoints: ['rxjs:bob'], @@ -24,7 +20,7 @@ const bobAgentOptions = getAgentOptions( modules ) -const aliceAgentOptions = getAgentOptions( +const aliceAgentOptions = getInMemoryAgentOptions( 'Alice Question Answer', { endpoints: ['rxjs:alice'], diff --git a/packages/react-native/jest.config.ts b/packages/react-native/jest.config.ts index 6426c5d8b8..2556d19c61 100644 --- a/packages/react-native/jest.config.ts +++ b/packages/react-native/jest.config.ts @@ -7,10 +7,6 @@ import packageJson from './package.json' const config: Config.InitialOptions = { ...base, displayName: packageJson.name, - moduleNameMapper: { - ...base.moduleNameMapper, - 'indy-sdk-react-native': 'indy-sdk', - }, } export default config diff --git a/packages/sd-jwt-vc/package.json b/packages/sd-jwt-vc/package.json index 447aa65b1b..d2bede53cd 100644 --- a/packages/sd-jwt-vc/package.json +++ b/packages/sd-jwt-vc/package.json @@ -32,7 +32,6 @@ "jwt-sd": "^0.1.2" }, "devDependencies": { - "@hyperledger/aries-askar-nodejs": "^0.2.0-dev.5", "reflect-metadata": "^0.1.13", "rimraf": "^4.4.0", "typescript": "~4.9.5" diff --git a/packages/sd-jwt-vc/src/SdJwtVcModule.ts b/packages/sd-jwt-vc/src/SdJwtVcModule.ts index f2c9508967..19f92b3230 100644 --- a/packages/sd-jwt-vc/src/SdJwtVcModule.ts +++ b/packages/sd-jwt-vc/src/SdJwtVcModule.ts @@ -20,7 +20,7 @@ export class SdJwtVcModule implements Module { dependencyManager .resolve(AgentConfig) .logger.warn( - "The '@credo-ts/sd-jwt-vc' module is experimental and could have unexpected breaking changes. When using this module, make sure to use strict versions for all @aries-framework packages." + "The '@credo-ts/sd-jwt-vc' module is experimental and could have unexpected breaking changes. When using this module, make sure to use strict versions for all @credo-ts packages." ) // Api diff --git a/packages/sd-jwt-vc/src/__tests__/SdJwtVcService.test.ts b/packages/sd-jwt-vc/src/__tests__/SdJwtVcService.test.ts index 020aea72fb..f21a5510c6 100644 --- a/packages/sd-jwt-vc/src/__tests__/SdJwtVcService.test.ts +++ b/packages/sd-jwt-vc/src/__tests__/SdJwtVcService.test.ts @@ -1,20 +1,17 @@ import type { Key, Logger } from '@credo-ts/core' -import { AskarModule } from '@credo-ts/askar' import { getJwkFromKey, DidKey, DidsModule, KeyDidRegistrar, KeyDidResolver, - utils, KeyType, Agent, TypedArrayEncoder, } from '@credo-ts/core' -import { ariesAskar } from '@hyperledger/aries-askar-nodejs' -import { agentDependencies } from '../../../core/tests' +import { getInMemoryAgentOptions } from '../../../core/tests' import { SdJwtVcService } from '../SdJwtVcService' import { SdJwtVcRepository } from '../repository' @@ -27,17 +24,18 @@ import { simpleJwtVcPresentation, } from './sdjwtvc.fixtures' -const agent = new Agent({ - config: { label: 'sdjwtvcserviceagent', walletConfig: { id: utils.uuid(), key: utils.uuid() } }, - modules: { - askar: new AskarModule({ ariesAskar }), - dids: new DidsModule({ - resolvers: [new KeyDidResolver()], - registrars: [new KeyDidRegistrar()], - }), - }, - dependencies: agentDependencies, -}) +const agent = new Agent( + getInMemoryAgentOptions( + 'sdjwtvcserviceagent', + {}, + { + dids: new DidsModule({ + resolvers: [new KeyDidResolver()], + registrars: [new KeyDidRegistrar()], + }), + } + ) +) const logger = jest.fn() as unknown as Logger agent.context.wallet.generateNonce = jest.fn(() => Promise.resolve('salt')) diff --git a/packages/sd-jwt-vc/tests/sdJwtVc.e2e.test.ts b/packages/sd-jwt-vc/tests/sdJwtVc.e2e.test.ts index bdc7122104..89aae8ad85 100644 --- a/packages/sd-jwt-vc/tests/sdJwtVc.e2e.test.ts +++ b/packages/sd-jwt-vc/tests/sdJwtVc.e2e.test.ts @@ -1,34 +1,24 @@ import type { Key } from '@credo-ts/core' -import { AskarModule } from '@credo-ts/askar' -import { - Agent, - DidKey, - DidsModule, - KeyDidRegistrar, - KeyDidResolver, - KeyType, - TypedArrayEncoder, - utils, -} from '@credo-ts/core' -import { ariesAskar } from '@hyperledger/aries-askar-nodejs' - -import { agentDependencies } from '../../core/tests' +import { Agent, DidKey, DidsModule, KeyDidRegistrar, KeyDidResolver, KeyType, TypedArrayEncoder } from '@credo-ts/core' + +import { getInMemoryAgentOptions } from '../../core/tests' import { SdJwtVcModule } from '../src' const getAgent = (label: string) => - new Agent({ - config: { label, walletConfig: { id: utils.uuid(), key: utils.uuid() } }, - modules: { - sdJwt: new SdJwtVcModule(), - askar: new AskarModule({ ariesAskar }), - dids: new DidsModule({ - resolvers: [new KeyDidResolver()], - registrars: [new KeyDidRegistrar()], - }), - }, - dependencies: agentDependencies, - }) + new Agent( + getInMemoryAgentOptions( + label, + {}, + { + sdJwt: new SdJwtVcModule(), + dids: new DidsModule({ + resolvers: [new KeyDidResolver()], + registrars: [new KeyDidRegistrar()], + }), + } + ) + ) describe('sd-jwt-vc end to end test', () => { const issuer = getAgent('sdjwtvcissueragent') diff --git a/packages/tenants/src/TenantsModule.ts b/packages/tenants/src/TenantsModule.ts index 58660e70a0..0489967637 100644 --- a/packages/tenants/src/TenantsModule.ts +++ b/packages/tenants/src/TenantsModule.ts @@ -27,7 +27,7 @@ export class TenantsModule imp dependencyManager .resolve(AgentConfig) .logger.warn( - "The '@credo-ts/tenants' module is experimental and could have unexpected breaking changes. When using this module, make sure to use strict versions for all @aries-framework packages." + "The '@credo-ts/tenants' module is experimental and could have unexpected breaking changes. When using this module, make sure to use strict versions for all @credo-ts packages." ) // Api diff --git a/packages/tenants/src/__tests__/TenantAgent.test.ts b/packages/tenants/src/__tests__/TenantAgent.test.ts index c4c3589492..6989bfc47c 100644 --- a/packages/tenants/src/__tests__/TenantAgent.test.ts +++ b/packages/tenants/src/__tests__/TenantAgent.test.ts @@ -1,25 +1,11 @@ import { Agent, AgentContext } from '@credo-ts/core' -import { indySdk } from '../../../core/tests' -import { agentDependencies, getAgentConfig, getAgentContext } from '../../../core/tests/helpers' -import { IndySdkModule } from '../../../indy-sdk/src' +import { getAgentConfig, getAgentContext, getInMemoryAgentOptions } from '../../../core/tests/helpers' import { TenantAgent } from '../TenantAgent' describe('TenantAgent', () => { test('possible to construct a TenantAgent instance', () => { - const agent = new Agent({ - config: { - label: 'test', - walletConfig: { - id: 'Wallet: TenantAgentRoot', - key: 'Wallet: TenantAgentRoot', - }, - }, - dependencies: agentDependencies, - modules: { - indySdk: new IndySdkModule({ indySdk }), - }, - }) + const agent = new Agent(getInMemoryAgentOptions('TenantAgentRoot')) const tenantDependencyManager = agent.dependencyManager.createChild() diff --git a/packages/tenants/src/__tests__/TenantsApi.test.ts b/packages/tenants/src/__tests__/TenantsApi.test.ts index 82b84bfb06..baf4f2fc69 100644 --- a/packages/tenants/src/__tests__/TenantsApi.test.ts +++ b/packages/tenants/src/__tests__/TenantsApi.test.ts @@ -1,7 +1,6 @@ import { Agent, AgentContext, InjectionSymbols } from '@credo-ts/core' -import { indySdk, getAgentContext, getAgentOptions, mockFunction } from '../../../core/tests' -import { IndySdkModule } from '../../../indy-sdk/src' +import { getAgentContext, getInMemoryAgentOptions, mockFunction } from '../../../core/tests' import { TenantAgent } from '../TenantAgent' import { TenantsApi } from '../TenantsApi' import { TenantAgentContextProvider } from '../context/TenantAgentContextProvider' @@ -16,7 +15,7 @@ const AgentContextProviderMock = TenantAgentContextProvider as jest.Mock { const tenantAgentContext = await tenantSessionCoordinator.getContextForSession(tenantRecord) - expect(wallet.initialize).toHaveBeenCalledWith(tenantRecord.config.walletConfig) + expect(wallet.initialize).toHaveBeenCalledWith({ + ...tenantRecord.config.walletConfig, + storage: { config: { inMemory: true }, type: 'sqlite' }, + }) expect(tenantSessionMutexMock.acquireSession).toHaveBeenCalledTimes(1) - expect(extendSpy).toHaveBeenCalledWith(tenantRecord.config) + expect(extendSpy).toHaveBeenCalledWith({ + ...tenantRecord.config, + walletConfig: { ...tenantRecord.config.walletConfig, storage: { config: { inMemory: true }, type: 'sqlite' } }, + }) expect(createChildSpy).toHaveBeenCalledWith() expect(tenantDependencyManager.registerInstance).toHaveBeenCalledWith(AgentContext, expect.any(AgentContext)) expect(tenantDependencyManager.registerInstance).toHaveBeenCalledWith(AgentConfig, expect.any(AgentConfig)) @@ -136,7 +142,10 @@ describe('TenantSessionCoordinator', () => { await expect(tenantSessionCoordinator.getContextForSession(tenantRecord)).rejects.toThrowError('Test error') - expect(wallet.initialize).toHaveBeenCalledWith(tenantRecord.config.walletConfig) + expect(wallet.initialize).toHaveBeenCalledWith({ + ...tenantRecord.config.walletConfig, + storage: { config: { inMemory: true }, type: 'sqlite' }, + }) expect(tenantSessionMutexMock.acquireSession).toHaveBeenCalledTimes(1) expect(tenantSessionMutexMock.releaseSession).toHaveBeenCalledTimes(1) }) @@ -192,7 +201,10 @@ describe('TenantSessionCoordinator', () => { }) // Initialize should only be called once - expect(wallet.initialize).toHaveBeenCalledWith(tenantRecord.config.walletConfig) + expect(wallet.initialize).toHaveBeenCalledWith({ + ...tenantRecord.config.walletConfig, + storage: { config: { inMemory: true }, type: 'sqlite' }, + }) expect(wallet.initialize).toHaveBeenCalledTimes(1) expect(tenantAgentContext1).toBe(tenantAgentContext2) diff --git a/packages/tenants/tests/tenant-sessions.e2e.test.ts b/packages/tenants/tests/tenant-sessions.e2e.test.ts index d348240b34..a434141bea 100644 --- a/packages/tenants/tests/tenant-sessions.e2e.test.ts +++ b/packages/tenants/tests/tenant-sessions.e2e.test.ts @@ -3,16 +3,17 @@ import type { InitConfig } from '@credo-ts/core' import { ConnectionsModule, Agent } from '@credo-ts/core' import { agentDependencies } from '@credo-ts/node' -import { testLogger, indySdk } from '../../core/tests' -import { IndySdkModule } from '../../indy-sdk/src' +import { InMemoryWalletModule } from '../../../tests/InMemoryWalletModule' +import { uuid } from '../../core/src/utils/uuid' +import { testLogger } from '../../core/tests' import { TenantsModule } from '@credo-ts/tenants' const agentConfig: InitConfig = { label: 'Tenant Agent 1', walletConfig: { - id: 'Wallet: tenant sessions e2e agent 1', - key: 'Wallet: tenant sessions e2e agent 1', + id: `tenant sessions e2e agent 1 - ${uuid().slice(0, 4)}`, + key: `tenant sessions e2e agent 1`, }, logger: testLogger, endpoints: ['rxjs:tenant-agent1'], @@ -24,7 +25,7 @@ const agent = new Agent({ dependencies: agentDependencies, modules: { tenants: new TenantsModule({ sessionAcquireTimeout: 10000 }), - indySdk: new IndySdkModule({ indySdk }), + inMemory: new InMemoryWalletModule(), connections: new ConnectionsModule({ autoAcceptConnections: true, }), @@ -67,17 +68,16 @@ describe('Tenants Sessions E2E', () => { const tenantRecordPromises = [] for (let tenantNo = 0; tenantNo < numberOfTenants; tenantNo++) { - const tenantRecord = agent.modules.tenants.createTenant({ + const tenantRecordPromise = agent.modules.tenants.createTenant({ config: { label: 'Agent 1 Tenant 1', }, }) - tenantRecordPromises.push(tenantRecord) + tenantRecordPromises.push(tenantRecordPromise) } const tenantRecords = await Promise.all(tenantRecordPromises) - const tenantAgentPromises = [] for (const tenantRecord of tenantRecords) { for (let session = 0; session < numberOfSessions; session++) { diff --git a/packages/tenants/tests/tenants-askar-profiles.e2e.test.ts b/packages/tenants/tests/tenants-askar-profiles.e2e.test.ts index a32a79394e..93761bc218 100644 --- a/packages/tenants/tests/tenants-askar-profiles.e2e.test.ts +++ b/packages/tenants/tests/tenants-askar-profiles.e2e.test.ts @@ -5,7 +5,7 @@ import { agentDependencies } from '@credo-ts/node' import { AskarModule, AskarMultiWalletDatabaseScheme, AskarProfileWallet, AskarWallet } from '../../askar/src' import { askarModuleConfig } from '../../askar/tests/helpers' -import { testLogger } from '../../core/tests' +import { getAskarWalletConfig, testLogger } from '../../core/tests' import { TenantsModule } from '@credo-ts/tenants' @@ -13,10 +13,7 @@ describe('Tenants Askar database schemes E2E', () => { test('uses AskarWallet for all wallets and tenants when database schema is DatabasePerWallet', async () => { const agentConfig: InitConfig = { label: 'Tenant Agent 1', - walletConfig: { - id: 'Wallet: askar tenants without profiles e2e agent 1', - key: 'Wallet: askar tenants without profiles e2e agent 1', - }, + walletConfig: getAskarWalletConfig('askar tenants without profiles e2e agent 1', { inMemory: false }), logger: testLogger, } @@ -74,10 +71,7 @@ describe('Tenants Askar database schemes E2E', () => { test('uses AskarWallet for main agent, and ProfileAskarWallet for tenants', async () => { const agentConfig: InitConfig = { label: 'Tenant Agent 1', - walletConfig: { - id: 'Wallet: askar tenants with profiles e2e agent 1', - key: 'Wallet: askar tenants with profiles e2e agent 1', - }, + walletConfig: getAskarWalletConfig('askar tenants with profiles e2e agent 1'), logger: testLogger, } diff --git a/packages/tenants/tests/tenants.e2e.test.ts b/packages/tenants/tests/tenants.e2e.test.ts index 3e9ad92480..c55c5bb95c 100644 --- a/packages/tenants/tests/tenants.e2e.test.ts +++ b/packages/tenants/tests/tenants.e2e.test.ts @@ -3,18 +3,19 @@ import type { InitConfig } from '@credo-ts/core' import { ConnectionsModule, OutOfBandRecord, Agent, CacheModule, InMemoryLruCache } from '@credo-ts/core' import { agentDependencies } from '@credo-ts/node' +import { InMemoryWalletModule } from '../../../tests/InMemoryWalletModule' import { SubjectInboundTransport } from '../../../tests/transport/SubjectInboundTransport' import { SubjectOutboundTransport } from '../../../tests/transport/SubjectOutboundTransport' -import { testLogger, indySdk } from '../../core/tests' -import { IndySdkModule } from '../../indy-sdk/src' +import { uuid } from '../../core/src/utils/uuid' +import { testLogger } from '../../core/tests' import { TenantsModule } from '@credo-ts/tenants' const agent1Config: InitConfig = { label: 'Tenant Agent 1', walletConfig: { - id: 'Wallet: tenants e2e agent 1', - key: 'Wallet: tenants e2e agent 1', + id: `tenants e2e agent 1 - ${uuid().slice(0, 4)}`, + key: `tenants e2e agent 1`, }, logger: testLogger, endpoints: ['rxjs:tenant-agent1'], @@ -23,8 +24,8 @@ const agent1Config: InitConfig = { const agent2Config: InitConfig = { label: 'Tenant Agent 2', walletConfig: { - id: 'Wallet: tenants e2e agent 2', - key: 'Wallet: tenants e2e agent 2', + id: `tenants e2e agent 2 - ${uuid().slice(0, 4)}`, + key: `tenants e2e agent 2`, }, logger: testLogger, endpoints: ['rxjs:tenant-agent2'], @@ -35,7 +36,7 @@ const agent1 = new Agent({ config: agent1Config, modules: { tenants: new TenantsModule(), - indySdk: new IndySdkModule({ indySdk }), + inMemory: new InMemoryWalletModule(), connections: new ConnectionsModule({ autoAcceptConnections: true, }), @@ -50,7 +51,7 @@ const agent2 = new Agent({ config: agent2Config, modules: { tenants: new TenantsModule(), - indySdk: new IndySdkModule({ indySdk }), + inMemory: new InMemoryWalletModule(), connections: new ConnectionsModule({ autoAcceptConnections: true, }), diff --git a/samples/extension-module/package.json b/samples/extension-module/package.json index f685881ee5..76016ac980 100644 --- a/samples/extension-module/package.json +++ b/samples/extension-module/package.json @@ -13,15 +13,17 @@ "responder": "ts-node responder.ts" }, "devDependencies": { - "@credo-ts/core": "*", - "@credo-ts/node": "*", - "ts-node": "^10.4.0" - }, - "dependencies": { + "ts-node": "^10.4.0", "@types/express": "^4.17.13", "@types/uuid": "^9.0.1", - "@types/ws": "^8.5.4", + "@types/ws": "^8.5.4" + }, + "dependencies": { + "@credo-ts/core": "*", + "@credo-ts/node": "*", + "@credo-ts/askar": "*", "class-validator": "0.14.0", - "rxjs": "^7.2.0" + "rxjs": "^7.2.0", + "@hyperledger/aries-askar-nodejs": "^0.2.0-dev.5" } } diff --git a/samples/extension-module/tests/dummy.e2e.test.ts b/samples/extension-module/tests/dummy.e2e.test.ts index c042a7d546..50458e9044 100644 --- a/samples/extension-module/tests/dummy.e2e.test.ts +++ b/samples/extension-module/tests/dummy.e2e.test.ts @@ -1,13 +1,13 @@ import type { SubjectMessage } from '../../../tests/transport/SubjectInboundTransport' import type { ConnectionRecord } from '@credo-ts/core' +import { AskarModule } from '@credo-ts/askar' import { Agent } from '@credo-ts/core' +import { ariesAskar } from '@hyperledger/aries-askar-nodejs' import { Subject } from 'rxjs' -import { indySdk } from '../../../packages/core/tests' import { getAgentOptions, makeConnection } from '../../../packages/core/tests/helpers' import testLogger from '../../../packages/core/tests/logger' -import { IndySdkModule } from '../../../packages/indy-sdk/src' import { SubjectInboundTransport } from '../../../tests/transport/SubjectInboundTransport' import { SubjectOutboundTransport } from '../../../tests/transport/SubjectOutboundTransport' import { DummyModule } from '../dummy/DummyModule' @@ -17,7 +17,9 @@ import { waitForDummyRecord } from './helpers' const modules = { dummy: new DummyModule(), - indySdk: new IndySdkModule({ indySdk }), + askar: new AskarModule({ + ariesAskar, + }), } const bobAgentOptions = getAgentOptions( diff --git a/tests/InMemoryStorageService.ts b/tests/InMemoryStorageService.ts index 40f48c8406..2fb57419c3 100644 --- a/tests/InMemoryStorageService.ts +++ b/tests/InMemoryStorageService.ts @@ -2,6 +2,8 @@ import type { AgentContext } from '../packages/core/src/agent' import type { BaseRecord, TagsBase } from '../packages/core/src/storage/BaseRecord' import type { StorageService, BaseRecordConstructor, Query } from '../packages/core/src/storage/StorageService' +import { InMemoryWallet } from './InMemoryWallet' + import { RecordNotFoundError, RecordDuplicateError, JsonTransformer, injectable } from '@credo-ts/core' interface StorageRecord { @@ -15,16 +17,19 @@ interface InMemoryRecords { [id: string]: StorageRecord } +interface ContextCorrelationIdToRecords { + [contextCorrelationId: string]: { + records: InMemoryRecords + creationDate: Date + } +} + @injectable() // eslint-disable-next-line @typescript-eslint/no-explicit-any export class InMemoryStorageService = BaseRecord> implements StorageService { - public records: InMemoryRecords - - public constructor(records: InMemoryRecords = {}) { - this.records = records - } + public contextCorrelationIdToRecords: ContextCorrelationIdToRecords = {} private recordToInstance(record: StorageRecord, recordClass: BaseRecordConstructor): T { const instance = JsonTransformer.fromJSON(record.value, recordClass) @@ -34,16 +39,43 @@ export class InMemoryStorageService = BaseRe return instance } + private getRecordsForContext(agentContext: AgentContext): InMemoryRecords { + const contextCorrelationId = agentContext.contextCorrelationId + + if (!this.contextCorrelationIdToRecords[contextCorrelationId]) { + this.contextCorrelationIdToRecords[contextCorrelationId] = { + records: {}, + creationDate: new Date(), + } + } else if (agentContext.wallet instanceof InMemoryWallet && agentContext.wallet.activeWalletId) { + const walletCreationDate = agentContext.wallet.inMemoryWallets[agentContext.wallet.activeWalletId].creationDate + const storageCreationDate = this.contextCorrelationIdToRecords[contextCorrelationId].creationDate + + // If the storage was created before the wallet, it means the wallet has been deleted in the meantime + // and thus we need to recreate the storage as we don't want to serve records from the previous wallet + // FIXME: this is a flaw in our wallet/storage model. I think wallet should be for keys, and storage + // for records and you can create them separately. But that's a bigger change. + if (storageCreationDate < walletCreationDate) { + this.contextCorrelationIdToRecords[contextCorrelationId] = { + records: {}, + creationDate: new Date(), + } + } + } + + return this.contextCorrelationIdToRecords[contextCorrelationId].records + } + /** @inheritDoc */ public async save(agentContext: AgentContext, record: T) { record.updatedAt = new Date() const value = JsonTransformer.toJSON(record) - if (this.records[record.id]) { + if (this.getRecordsForContext(agentContext)[record.id]) { throw new RecordDuplicateError(`Record with id ${record.id} already exists`, { recordType: record.type }) } - this.records[record.id] = { + this.getRecordsForContext(agentContext)[record.id] = { value, id: record.id, type: record.type, @@ -57,13 +89,13 @@ export class InMemoryStorageService = BaseRe const value = JsonTransformer.toJSON(record) delete value._tags - if (!this.records[record.id]) { + if (!this.getRecordsForContext(agentContext)[record.id]) { throw new RecordNotFoundError(`record with id ${record.id} not found.`, { recordType: record.type, }) } - this.records[record.id] = { + this.getRecordsForContext(agentContext)[record.id] = { value, id: record.id, type: record.type, @@ -73,13 +105,13 @@ export class InMemoryStorageService = BaseRe /** @inheritDoc */ public async delete(agentContext: AgentContext, record: T) { - if (!this.records[record.id]) { + if (!this.getRecordsForContext(agentContext)[record.id]) { throw new RecordNotFoundError(`record with id ${record.id} not found.`, { recordType: record.type, }) } - delete this.records[record.id] + delete this.getRecordsForContext(agentContext)[record.id] } /** @inheritDoc */ @@ -88,18 +120,18 @@ export class InMemoryStorageService = BaseRe recordClass: BaseRecordConstructor, id: string ): Promise { - if (!this.records[id]) { + if (!this.getRecordsForContext(agentContext)[id]) { throw new RecordNotFoundError(`record with id ${id} not found.`, { recordType: recordClass.type, }) } - delete this.records[id] + delete this.getRecordsForContext(agentContext)[id] } /** @inheritDoc */ public async getById(agentContext: AgentContext, recordClass: BaseRecordConstructor, id: string): Promise { - const record = this.records[id] + const record = this.getRecordsForContext(agentContext)[id] if (!record) { throw new RecordNotFoundError(`record with id ${id} not found.`, { @@ -112,7 +144,7 @@ export class InMemoryStorageService = BaseRe /** @inheritDoc */ public async getAll(agentContext: AgentContext, recordClass: BaseRecordConstructor): Promise { - const records = Object.values(this.records) + const records = Object.values(this.getRecordsForContext(agentContext)) .filter((record) => record.type === recordClass.type) .map((record) => this.recordToInstance(record, recordClass)) @@ -125,7 +157,7 @@ export class InMemoryStorageService = BaseRe recordClass: BaseRecordConstructor, query: Query ): Promise { - const records = Object.values(this.records) + const records = Object.values(this.getRecordsForContext(agentContext)) .filter((record) => record.type === recordClass.type) .filter((record) => filterByQuery(record, query)) .map((record) => this.recordToInstance(record, recordClass)) @@ -165,6 +197,10 @@ function matchSimpleQuery>(record: StorageRe const tags = record.tags as TagsBase for (const [key, value] of Object.entries(query)) { + // We don't query for value undefined, the value should be null in that case + if (value === undefined) continue + + // TODO: support null if (Array.isArray(value)) { const tagValue = tags[key] if (!Array.isArray(tagValue) || !value.every((v) => tagValue.includes(v))) { diff --git a/tests/InMemoryWallet.ts b/tests/InMemoryWallet.ts new file mode 100644 index 0000000000..fd46f2359e --- /dev/null +++ b/tests/InMemoryWallet.ts @@ -0,0 +1,343 @@ +import type { + EncryptedMessage, + WalletConfig, + WalletCreateKeyOptions, + WalletSignOptions, + UnpackedMessageContext, + WalletVerifyOptions, + Wallet, +} from '@credo-ts/core' + +import { CryptoBox, Store, Key as AskarKey, keyAlgFromString } from '@hyperledger/aries-askar-nodejs' +import BigNumber from 'bn.js' + +import { didcommV1Pack, didcommV1Unpack } from '../packages/askar/src/wallet/didcommV1' + +import { + JsonEncoder, + WalletNotFoundError, + injectable, + isValidSeed, + isValidPrivateKey, + KeyType, + Buffer, + AriesFrameworkError, + WalletError, + Key, + TypedArrayEncoder, +} from '@credo-ts/core' + +const isError = (error: unknown): error is Error => error instanceof Error + +interface InMemoryKey { + publicKeyBytes: Uint8Array + secretKeyBytes: Uint8Array + keyType: KeyType +} + +interface InMemoryKeys { + [id: string]: InMemoryKey +} + +interface InMemoryWallets { + [id: string]: { + keys: InMemoryKeys + creationDate: Date + } +} + +@injectable() +export class InMemoryWallet implements Wallet { + // activeWalletId can be set even if wallet is closed. So make sure to also look at + // isInitialized to see if the wallet is actually open + public activeWalletId?: string + + public inMemoryWallets: InMemoryWallets = {} + /** + * Abstract methods that need to be implemented by subclasses + */ + public isInitialized = false + public isProvisioned = false + + public get supportedKeyTypes() { + return [KeyType.Ed25519, KeyType.P256] + } + + private get inMemoryKeys(): InMemoryKeys { + if (!this.activeWalletId || !this.isInitialized) { + throw new WalletError('No active wallet') + } + + if (!this.inMemoryWallets[this.activeWalletId]) { + throw new WalletError('wallet does not exist') + } + + return this.inMemoryWallets[this.activeWalletId].keys + } + + public async create(walletConfig: WalletConfig) { + if (this.inMemoryWallets[walletConfig.id]) { + throw new WalletError('Wallet already exists') + } + + this.inMemoryWallets[walletConfig.id] = { + keys: {}, + creationDate: new Date(), + } + } + + public async createAndOpen(walletConfig: WalletConfig) { + await this.create(walletConfig) + await this.open(walletConfig) + } + + public async open(walletConfig: WalletConfig) { + if (this.isInitialized) { + throw new WalletError('A wallet is already open') + } + + if (!this.inMemoryWallets[walletConfig.id]) { + throw new WalletNotFoundError('Wallet does not exist', { walletType: 'InMemoryWallet' }) + } + + this.activeWalletId = walletConfig.id + this.isProvisioned = true + this.isInitialized = true + } + + public rotateKey(): Promise { + throw new Error('Method not implemented.') + } + + public async close() { + this.isInitialized = false + } + + public async delete() { + if (!this.activeWalletId) { + throw new WalletError('wallet is not provisioned') + } + + delete this.inMemoryWallets[this.activeWalletId] + this.activeWalletId = undefined + this.isProvisioned = false + } + + public async export() { + throw new Error('Method not implemented.') + } + + public async import() { + throw new Error('Method not implemented.') + } + + public async dispose() { + this.isInitialized = false + } + + /** + * Create a key with an optional seed and keyType. + * The keypair is also automatically stored in the wallet afterwards + */ + public async createKey({ seed, privateKey, keyType }: WalletCreateKeyOptions): Promise { + try { + if (seed && privateKey) { + throw new WalletError('Only one of seed and privateKey can be set') + } + + if (seed && !isValidSeed(seed, keyType)) { + throw new WalletError('Invalid seed provided') + } + + if (privateKey && !isValidPrivateKey(privateKey, keyType)) { + throw new WalletError('Invalid private key provided') + } + + if (!this.supportedKeyTypes.includes(keyType)) { + throw new WalletError(`Unsupported key type: '${keyType}'`) + } + + const algorithm = keyAlgFromString(keyType) + + // Create key + let key: AskarKey | undefined + try { + key = privateKey + ? AskarKey.fromSecretBytes({ secretKey: privateKey, algorithm }) + : seed + ? AskarKey.fromSeed({ seed, algorithm }) + : AskarKey.generate(algorithm) + + const keyPublicBytes = key.publicBytes + // Store key + this.inMemoryKeys[TypedArrayEncoder.toBase58(keyPublicBytes)] = { + publicKeyBytes: keyPublicBytes, + secretKeyBytes: key.secretBytes, + keyType, + } + + return Key.fromPublicKey(keyPublicBytes, keyType) + } finally { + key?.handle.free() + } + } catch (error) { + // If already instance of `WalletError`, re-throw + if (error instanceof WalletError) throw error + + if (!isError(error)) { + throw new AriesFrameworkError('Attempted to throw error, but it was not of type Error', { cause: error }) + } + throw new WalletError(`Error creating key with key type '${keyType}': ${error.message}`, { cause: error }) + } + } + + /** + * sign a Buffer with an instance of a Key class + * + * @param data Buffer The data that needs to be signed + * @param key Key The key that is used to sign the data + * + * @returns A signature for the data + */ + public async sign({ data, key }: WalletSignOptions): Promise { + const inMemoryKey = this.inMemoryKeys[key.publicKeyBase58] + if (!inMemoryKey) { + throw new WalletError(`Key not found in wallet`) + } + + if (!TypedArrayEncoder.isTypedArray(data)) { + throw new WalletError(`Currently not supporting signing of multiple messages`) + } + + let askarKey: AskarKey | undefined + try { + const inMemoryKey = this.inMemoryKeys[key.publicKeyBase58] + askarKey = AskarKey.fromSecretBytes({ + algorithm: keyAlgFromString(inMemoryKey.keyType), + secretKey: inMemoryKey.secretKeyBytes, + }) + + const signed = askarKey.signMessage({ message: data as Buffer }) + + return Buffer.from(signed) + } finally { + askarKey?.handle.free() + } + } + + /** + * Verify the signature with the data and the used key + * + * @param data Buffer The data that has to be confirmed to be signed + * @param key Key The key that was used in the signing process + * @param signature Buffer The signature that was created by the signing process + * + * @returns A boolean whether the signature was created with the supplied data and key + * + * @throws {WalletError} When it could not do the verification + * @throws {WalletError} When an unsupported keytype is used + */ + public async verify({ data, key, signature }: WalletVerifyOptions): Promise { + if (!TypedArrayEncoder.isTypedArray(data)) { + throw new WalletError(`Currently not supporting signing of multiple messages`) + } + + let askarKey: AskarKey | undefined + try { + askarKey = AskarKey.fromPublicBytes({ + algorithm: keyAlgFromString(key.keyType), + publicKey: key.publicKey, + }) + return askarKey.verifySignature({ message: data as Buffer, signature }) + } finally { + askarKey?.handle.free() + } + } + + /** + * Pack a message using DIDComm V1 algorithm + * + * @param payload message to send + * @param recipientKeys array containing recipient keys in base58 + * @param senderVerkey sender key in base58 + * @returns JWE Envelope to send + */ + public async pack( + payload: Record, + recipientKeys: string[], + senderVerkey?: string // in base58 + ): Promise { + const senderKey = senderVerkey ? this.inMemoryKeys[senderVerkey] : undefined + + if (senderVerkey && !senderKey) { + throw new WalletError(`Sender key not found`) + } + + const askarSenderKey = senderKey + ? AskarKey.fromSecretBytes({ + algorithm: keyAlgFromString(senderKey.keyType), + secretKey: senderKey.secretKeyBytes, + }) + : undefined + + try { + const envelope = didcommV1Pack(payload, recipientKeys, askarSenderKey) + return envelope + } finally { + askarSenderKey?.handle.free() + } + } + + /** + * Unpacks a JWE Envelope coded using DIDComm V1 algorithm + * + * @param messagePackage JWE Envelope + * @returns UnpackedMessageContext with plain text message, sender key and recipient key + */ + public async unpack(messagePackage: EncryptedMessage): Promise { + const protectedJson = JsonEncoder.fromBase64(messagePackage.protected) + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const recipientKids: string[] = protectedJson.recipients.map((r: any) => r.header.kid) + + for (const recipientKid of recipientKids) { + const recipientKey = this.inMemoryKeys[recipientKid] + const recipientAskarKey = recipientKey + ? AskarKey.fromSecretBytes({ + algorithm: keyAlgFromString(recipientKey.keyType), + secretKey: recipientKey.secretKeyBytes, + }) + : undefined + try { + if (recipientAskarKey) { + const unpacked = didcommV1Unpack(messagePackage, recipientAskarKey) + return unpacked + } + } finally { + recipientAskarKey?.handle.free() + } + } + + throw new WalletError('No corresponding recipient key found') + } + + public async generateNonce(): Promise { + try { + // generate an 80-bit nonce suitable for AnonCreds proofs + const nonce = CryptoBox.randomNonce().slice(0, 10) + return new BigNumber(nonce).toString() + } catch (error) { + if (!isError(error)) { + throw new AriesFrameworkError('Attempted to throw error, but it was not of type Error', { cause: error }) + } + throw new WalletError('Error generating nonce', { cause: error }) + } + } + + public async generateWalletKey() { + try { + return Store.generateRawKey() + } catch (error) { + throw new WalletError('Error generating wallet key', { cause: error }) + } + } +} diff --git a/tests/InMemoryWalletModule.ts b/tests/InMemoryWalletModule.ts new file mode 100644 index 0000000000..c33326b79f --- /dev/null +++ b/tests/InMemoryWalletModule.ts @@ -0,0 +1,22 @@ +import type { DependencyManager, Module } from '@credo-ts/core' + +import { InMemoryStorageService } from './InMemoryStorageService' +import { InMemoryWallet } from './InMemoryWallet' + +import { AriesFrameworkError, InjectionSymbols } from '@credo-ts/core' + +export class InMemoryWalletModule implements Module { + public register(dependencyManager: DependencyManager) { + if (dependencyManager.isRegistered(InjectionSymbols.Wallet)) { + throw new AriesFrameworkError('There is an instance of Wallet already registered') + } else { + dependencyManager.registerContextScoped(InjectionSymbols.Wallet, InMemoryWallet) + } + + if (dependencyManager.isRegistered(InjectionSymbols.StorageService)) { + throw new AriesFrameworkError('There is an instance of StorageService already registered') + } else { + dependencyManager.registerSingleton(InjectionSymbols.StorageService, InMemoryStorageService) + } + } +} diff --git a/tests/e2e-askar-indy-sdk-wallet-subject.test.ts b/tests/e2e-askar-indy-vdr-anoncreds-rs.test.ts similarity index 83% rename from tests/e2e-askar-indy-sdk-wallet-subject.test.ts rename to tests/e2e-askar-indy-vdr-anoncreds-rs.test.ts index 560f031dc4..4d948dd281 100644 --- a/tests/e2e-askar-indy-sdk-wallet-subject.test.ts +++ b/tests/e2e-askar-indy-vdr-anoncreds-rs.test.ts @@ -3,10 +3,8 @@ import type { AnonCredsTestsAgent } from '../packages/anoncreds/tests/legacyAnon import { Subject } from 'rxjs' -import { - getAskarAnonCredsIndyModules, - getLegacyAnonCredsModules, -} from '../packages/anoncreds/tests/legacyAnonCredsSetup' +import { getAnonCredsIndyModules } from '../packages/anoncreds/tests/legacyAnonCredsSetup' +import { askarModule } from '../packages/askar/tests/helpers' import { getAgentOptions } from '../packages/core/tests/helpers' import { e2eTest } from './e2e-test' @@ -25,12 +23,13 @@ const recipientAgentOptions = getAgentOptions( 'E2E Askar Subject Recipient', {}, { - ...getAskarAnonCredsIndyModules({ + ...getAnonCredsIndyModules({ autoAcceptCredentials: AutoAcceptCredential.ContentApproved, }), mediationRecipient: new MediationRecipientModule({ mediatorPickupStrategy: MediatorPickupStrategy.PickUpV1, }), + askar: askarModule, } ) const mediatorAgentOptions = getAgentOptions( @@ -39,25 +38,27 @@ const mediatorAgentOptions = getAgentOptions( endpoints: ['rxjs:mediator'], }, { - ...getAskarAnonCredsIndyModules({ + ...getAnonCredsIndyModules({ autoAcceptCredentials: AutoAcceptCredential.ContentApproved, }), mediator: new MediatorModule({ autoAcceptMediationRequests: true }), + askar: askarModule, } ) const senderAgentOptions = getAgentOptions( - 'E2E Indy SDK Subject Sender', + 'E2E Askar Subject Sender', { endpoints: ['rxjs:sender'], }, { - ...getLegacyAnonCredsModules({ + ...getAnonCredsIndyModules({ autoAcceptCredentials: AutoAcceptCredential.ContentApproved, }), mediationRecipient: new MediationRecipientModule({ mediatorPollingInterval: 1000, mediatorPickupStrategy: MediatorPickupStrategy.PickUpV1, }), + askar: askarModule, } ) @@ -67,9 +68,9 @@ describe('E2E Askar-AnonCredsRS-IndyVDR Subject tests', () => { let senderAgent: AnonCredsTestsAgent beforeEach(async () => { - recipientAgent = new Agent(recipientAgentOptions) as AnonCredsTestsAgent - mediatorAgent = new Agent(mediatorAgentOptions) as AnonCredsTestsAgent - senderAgent = new Agent(senderAgentOptions) as AnonCredsTestsAgent + recipientAgent = new Agent(recipientAgentOptions) as unknown as AnonCredsTestsAgent + mediatorAgent = new Agent(mediatorAgentOptions) as unknown as AnonCredsTestsAgent + senderAgent = new Agent(senderAgentOptions) as unknown as AnonCredsTestsAgent }) afterEach(async () => { diff --git a/tests/e2e-http.test.ts b/tests/e2e-http.test.ts index 45cc0bfae4..d4cc8eb163 100644 --- a/tests/e2e-http.test.ts +++ b/tests/e2e-http.test.ts @@ -1,7 +1,7 @@ import type { AnonCredsTestsAgent } from '../packages/anoncreds/tests/legacyAnonCredsSetup' -import { getLegacyAnonCredsModules } from '../packages/anoncreds/tests/legacyAnonCredsSetup' -import { getAgentOptions } from '../packages/core/tests/helpers' +import { getAnonCredsIndyModules } from '../packages/anoncreds/tests/legacyAnonCredsSetup' +import { getInMemoryAgentOptions } from '../packages/core/tests/helpers' import { e2eTest } from './e2e-test' @@ -15,11 +15,11 @@ import { } from '@credo-ts/core' import { HttpInboundTransport } from '@credo-ts/node' -const recipientAgentOptions = getAgentOptions( +const recipientAgentOptions = getInMemoryAgentOptions( 'E2E HTTP Recipient', {}, { - ...getLegacyAnonCredsModules({ + ...getAnonCredsIndyModules({ autoAcceptCredentials: AutoAcceptCredential.ContentApproved, }), mediationRecipient: new MediationRecipientModule({ @@ -29,13 +29,13 @@ const recipientAgentOptions = getAgentOptions( ) const mediatorPort = 3000 -const mediatorAgentOptions = getAgentOptions( +const mediatorAgentOptions = getInMemoryAgentOptions( 'E2E HTTP Mediator', { endpoints: [`http://localhost:${mediatorPort}`], }, { - ...getLegacyAnonCredsModules({ + ...getAnonCredsIndyModules({ autoAcceptCredentials: AutoAcceptCredential.ContentApproved, }), mediator: new MediatorModule({ @@ -45,13 +45,13 @@ const mediatorAgentOptions = getAgentOptions( ) const senderPort = 3001 -const senderAgentOptions = getAgentOptions( +const senderAgentOptions = getInMemoryAgentOptions( 'E2E HTTP Sender', { endpoints: [`http://localhost:${senderPort}`], }, { - ...getLegacyAnonCredsModules({ + ...getAnonCredsIndyModules({ autoAcceptCredentials: AutoAcceptCredential.ContentApproved, }), mediationRecipient: new MediationRecipientModule({ diff --git a/tests/e2e-subject.test.ts b/tests/e2e-subject.test.ts index 35656e6835..cc9670abbf 100644 --- a/tests/e2e-subject.test.ts +++ b/tests/e2e-subject.test.ts @@ -3,8 +3,8 @@ import type { AnonCredsTestsAgent } from '../packages/anoncreds/tests/legacyAnon import { Subject } from 'rxjs' -import { getLegacyAnonCredsModules } from '../packages/anoncreds/tests/legacyAnonCredsSetup' -import { getAgentOptions } from '../packages/core/tests/helpers' +import { getAnonCredsIndyModules } from '../packages/anoncreds/tests/legacyAnonCredsSetup' +import { getInMemoryAgentOptions } from '../packages/core/tests/helpers' import { e2eTest } from './e2e-test' import { SubjectInboundTransport } from './transport/SubjectInboundTransport' @@ -18,11 +18,11 @@ import { MediationRecipientModule, } from '@credo-ts/core' -const recipientAgentOptions = getAgentOptions( +const recipientAgentOptions = getInMemoryAgentOptions( 'E2E Subject Recipient', {}, { - ...getLegacyAnonCredsModules({ + ...getAnonCredsIndyModules({ autoAcceptCredentials: AutoAcceptCredential.ContentApproved, }), mediationRecipient: new MediationRecipientModule({ @@ -30,25 +30,25 @@ const recipientAgentOptions = getAgentOptions( }), } ) -const mediatorAgentOptions = getAgentOptions( +const mediatorAgentOptions = getInMemoryAgentOptions( 'E2E Subject Mediator', { endpoints: ['rxjs:mediator'], }, { - ...getLegacyAnonCredsModules({ + ...getAnonCredsIndyModules({ autoAcceptCredentials: AutoAcceptCredential.ContentApproved, }), mediator: new MediatorModule({ autoAcceptMediationRequests: true }), } ) -const senderAgentOptions = getAgentOptions( +const senderAgentOptions = getInMemoryAgentOptions( 'E2E Subject Sender', { endpoints: ['rxjs:sender'], }, { - ...getLegacyAnonCredsModules({ + ...getAnonCredsIndyModules({ autoAcceptCredentials: AutoAcceptCredential.ContentApproved, }), mediationRecipient: new MediationRecipientModule({ diff --git a/tests/e2e-ws-pickup-v2.test.ts b/tests/e2e-ws-pickup-v2.test.ts index 68c64cda7f..3a61a0ff2a 100644 --- a/tests/e2e-ws-pickup-v2.test.ts +++ b/tests/e2e-ws-pickup-v2.test.ts @@ -1,6 +1,7 @@ import type { AnonCredsTestsAgent } from '../packages/anoncreds/tests/legacyAnonCredsSetup' -import { getLegacyAnonCredsModules } from '../packages/anoncreds/tests/legacyAnonCredsSetup' +import { getAnonCredsIndyModules } from '../packages/anoncreds/tests/legacyAnonCredsSetup' +import { askarModule } from '../packages/askar/tests/helpers' import { getAgentOptions } from '../packages/core/tests/helpers' import { e2eTest } from './e2e-test' @@ -15,16 +16,19 @@ import { } from '@credo-ts/core' import { WsInboundTransport } from '@credo-ts/node' +// FIXME: somehow if we use the in memory wallet and storage service in the WS test it will fail, +// but it succeeds with Askar. We should look into this at some point const recipientOptions = getAgentOptions( 'E2E WS Pickup V2 Recipient ', {}, { - ...getLegacyAnonCredsModules({ + ...getAnonCredsIndyModules({ autoAcceptCredentials: AutoAcceptCredential.ContentApproved, }), mediationRecipient: new MediationRecipientModule({ mediatorPickupStrategy: MediatorPickupStrategy.PickUpV2, }), + askar: askarModule, } ) @@ -36,10 +40,11 @@ const mediatorOptions = getAgentOptions( endpoints: [`ws://localhost:${mediatorPort}`], }, { - ...getLegacyAnonCredsModules({ + ...getAnonCredsIndyModules({ autoAcceptCredentials: AutoAcceptCredential.ContentApproved, }), mediator: new MediatorModule({ autoAcceptMediationRequests: true }), + askar: askarModule, } ) @@ -50,13 +55,14 @@ const senderOptions = getAgentOptions( endpoints: [`ws://localhost:${senderPort}`], }, { - ...getLegacyAnonCredsModules({ + ...getAnonCredsIndyModules({ autoAcceptCredentials: AutoAcceptCredential.ContentApproved, }), mediationRecipient: new MediationRecipientModule({ mediatorPollingInterval: 1000, mediatorPickupStrategy: MediatorPickupStrategy.PickUpV1, }), + askar: askarModule, } ) @@ -66,9 +72,9 @@ describe('E2E WS Pickup V2 tests', () => { let senderAgent: AnonCredsTestsAgent beforeEach(async () => { - recipientAgent = new Agent(recipientOptions) as AnonCredsTestsAgent - mediatorAgent = new Agent(mediatorOptions) as AnonCredsTestsAgent - senderAgent = new Agent(senderOptions) as AnonCredsTestsAgent + recipientAgent = new Agent(recipientOptions) as unknown as AnonCredsTestsAgent + mediatorAgent = new Agent(mediatorOptions) as unknown as AnonCredsTestsAgent + senderAgent = new Agent(senderOptions) as unknown as AnonCredsTestsAgent }) afterEach(async () => { diff --git a/tests/e2e-ws.test.ts b/tests/e2e-ws.test.ts index 76aa6c9a9f..f3563ab409 100644 --- a/tests/e2e-ws.test.ts +++ b/tests/e2e-ws.test.ts @@ -1,6 +1,7 @@ import type { AnonCredsTestsAgent } from '../packages/anoncreds/tests/legacyAnonCredsSetup' -import { getLegacyAnonCredsModules } from '../packages/anoncreds/tests/legacyAnonCredsSetup' +import { getAnonCredsIndyModules } from '../packages/anoncreds/tests/legacyAnonCredsSetup' +import { askarModule } from '../packages/askar/tests/helpers' import { getAgentOptions } from '../packages/core/tests/helpers' import { e2eTest } from './e2e-test' @@ -15,16 +16,19 @@ import { } from '@credo-ts/core' import { WsInboundTransport } from '@credo-ts/node' +// FIXME: somehow if we use the in memory wallet and storage service in the WS test it will fail, +// but it succeeds with Askar. We should look into this at some point const recipientAgentOptions = getAgentOptions( 'E2E WS Recipient ', {}, { - ...getLegacyAnonCredsModules({ + ...getAnonCredsIndyModules({ autoAcceptCredentials: AutoAcceptCredential.ContentApproved, }), mediationRecipient: new MediationRecipientModule({ mediatorPickupStrategy: MediatorPickupStrategy.PickUpV1, }), + askar: askarModule, } ) @@ -35,10 +39,11 @@ const mediatorAgentOptions = getAgentOptions( endpoints: [`ws://localhost:${mediatorPort}`], }, { - ...getLegacyAnonCredsModules({ + ...getAnonCredsIndyModules({ autoAcceptCredentials: AutoAcceptCredential.ContentApproved, }), mediator: new MediatorModule({ autoAcceptMediationRequests: true }), + askar: askarModule, } ) @@ -49,13 +54,14 @@ const senderAgentOptions = getAgentOptions( endpoints: [`ws://localhost:${senderPort}`], }, { - ...getLegacyAnonCredsModules({ + ...getAnonCredsIndyModules({ autoAcceptCredentials: AutoAcceptCredential.ContentApproved, }), mediationRecipient: new MediationRecipientModule({ mediatorPollingInterval: 1000, mediatorPickupStrategy: MediatorPickupStrategy.PickUpV1, }), + askar: askarModule, } ) @@ -65,9 +71,9 @@ describe('E2E WS tests', () => { let senderAgent: AnonCredsTestsAgent beforeEach(async () => { - recipientAgent = new Agent(recipientAgentOptions) as AnonCredsTestsAgent - mediatorAgent = new Agent(mediatorAgentOptions) as AnonCredsTestsAgent - senderAgent = new Agent(senderAgentOptions) as AnonCredsTestsAgent + recipientAgent = new Agent(recipientAgentOptions) as unknown as AnonCredsTestsAgent + mediatorAgent = new Agent(mediatorAgentOptions) as unknown as AnonCredsTestsAgent + senderAgent = new Agent(senderAgentOptions) as unknown as AnonCredsTestsAgent }) afterEach(async () => { diff --git a/yarn.lock b/yarn.lock index 59c30b61a1..6c138fa5ae 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1474,7 +1474,7 @@ resolved "https://registry.yarnpkg.com/@fastify/busboy/-/busboy-2.1.0.tgz#0709e9f4cb252351c609c6e6d8d6779a8d25edff" integrity sha512-+KpH+QxZU7O4675t3mnkQKcZZg56u+K/Ct2K+N2AZYNVK8kyeo/bI18tI8aPm3tvNNRyTWfj6s5tnGNlcbQRsA== -"@gar/promisify@^1.0.1", "@gar/promisify@^1.1.3": +"@gar/promisify@^1.1.3": version "1.1.3" resolved "https://registry.yarnpkg.com/@gar/promisify/-/promisify-1.1.3.tgz#555193ab2e3bb3b6adc3d551c9c030d9e860daf6" integrity sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw== @@ -2164,14 +2164,6 @@ treeverse "^3.0.0" walk-up-path "^1.0.0" -"@npmcli/fs@^1.0.0": - version "1.1.1" - resolved "https://registry.yarnpkg.com/@npmcli/fs/-/fs-1.1.1.tgz#72f719fe935e687c56a4faecf3c03d06ba593257" - integrity sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ== - dependencies: - "@gar/promisify" "^1.0.1" - semver "^7.3.5" - "@npmcli/fs@^2.1.0": version "2.1.2" resolved "https://registry.yarnpkg.com/@npmcli/fs/-/fs-2.1.2.tgz#a9e2541a4a2fec2e69c29b35e6060973da79b865" @@ -2252,14 +2244,6 @@ pacote "^15.0.0" semver "^7.3.5" -"@npmcli/move-file@^1.0.1": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@npmcli/move-file/-/move-file-1.1.2.tgz#1a82c3e372f7cae9253eb66d72543d6b8685c674" - integrity sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg== - dependencies: - mkdirp "^1.0.4" - rimraf "^3.0.2" - "@npmcli/move-file@^2.0.0": version "2.0.1" resolved "https://registry.yarnpkg.com/@npmcli/move-file/-/move-file-2.0.1.tgz#26f6bdc379d87f75e55739bab89db525b06100e4" @@ -3059,11 +3043,6 @@ "@stablelib/wipe" "^1.0.1" "@stablelib/xchacha20" "^1.0.1" -"@tootallnate/once@1": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" - integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw== - "@tootallnate/once@2": version "2.0.0" resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-2.0.0.tgz#f544a148d3ab35801c1f633a7441fd87c2e484bf" @@ -3142,6 +3121,13 @@ dependencies: "@types/node" "*" +"@types/bn.js@^5.1.5": + version "5.1.5" + resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-5.1.5.tgz#2e0dacdcce2c0f16b905d20ff87aedbc6f7b4bf0" + integrity sha512-V46N0zwKRF5Q00AZ6hWtN0T8gGmDUaUzLWQvHFo5yThtVwK/VCenFY3wXVbOvNfajEpsTfQM4IN9k/d6gUVX3A== + dependencies: + "@types/node" "*" + "@types/body-parser@*": version "1.19.2" resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.2.tgz#aea2059e28b7658639081347ac4fab3de166e6f0" @@ -3213,13 +3199,6 @@ dependencies: "@types/node" "*" -"@types/indy-sdk@*", "@types/indy-sdk@1.16.27", "@types/indy-sdk@^1.16.26": - version "1.16.27" - resolved "https://registry.yarnpkg.com/@types/indy-sdk/-/indy-sdk-1.16.27.tgz#f5f01fe2cd39b74cacf91ea84d46a2e351cefa3b" - integrity sha512-ASEGYOuz8Acbybz4W2CYTG/fF7H9UQmJIG5wz8PSAvme07QU04Yzj4RJ5Nzzjej0X/AApEHS/5Jpk3iXTOs9HQ== - dependencies: - buffer "^6.0.0" - "@types/inquirer@^8.2.6": version "8.2.6" resolved "https://registry.yarnpkg.com/@types/inquirer/-/inquirer-8.2.6.tgz#abd41a5fb689c7f1acb12933d787d4262a02a0ab" @@ -3247,10 +3226,10 @@ dependencies: "@types/istanbul-lib-report" "*" -"@types/jest@^29.5.5": - version "29.5.5" - resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.5.5.tgz#727204e06228fe24373df9bae76b90f3e8236a2a" - integrity sha512-ebylz2hnsWR9mYvmBFbXJXr+33UPc4+ZdxyDXh5w0FlPBTfCVN3wPL+kuOiQt3xvrK419v7XWeAs+AeOksafXg== +"@types/jest@^29.5.11": + version "29.5.11" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.5.11.tgz#0c13aa0da7d0929f078ab080ae5d4ced80fa2f2c" + integrity sha512-S2mHmYIVe13vrm6q4kN6fLYYAka15ALQki/vgDC3mIukEOx8WJlv0kQPM+d4w8Gp6u0uSdKND04IlTXBv0rwnQ== dependencies: expect "^29.0.0" pretty-format "^29.0.0" @@ -3614,7 +3593,7 @@ agent-base@6, agent-base@^6.0.2: dependencies: debug "4" -agentkeepalive@^4.1.3, agentkeepalive@^4.2.1: +agentkeepalive@^4.2.1: version "4.3.0" resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-4.3.0.tgz#bb999ff07412653c1803b3ced35e50729830a255" integrity sha512-7Epl1Blf4Sy37j4v9f9FjICCh4+KAQOyXgHEwlyBiAQLbhKdq/i2QQU3amQalS/wPhdPzDXPL5DMR5bkn+YeWg== @@ -4234,13 +4213,6 @@ bin-links@^4.0.1: read-cmd-shim "^4.0.0" write-file-atomic "^5.0.0" -bindings@^1.3.1: - version "1.5.0" - resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" - integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== - dependencies: - file-uri-to-path "1.0.0" - bl@^4.0.3, bl@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a" @@ -4388,7 +4360,7 @@ buffer@^5.5.0: base64-js "^1.3.1" ieee754 "^1.1.13" -buffer@^6.0.0, buffer@^6.0.3: +buffer@^6.0.3: version "6.0.3" resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== @@ -4430,30 +4402,6 @@ bytes@3.1.2: resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== -cacache@^15.2.0: - version "15.3.0" - resolved "https://registry.yarnpkg.com/cacache/-/cacache-15.3.0.tgz#dc85380fb2f556fe3dda4c719bfa0ec875a7f1eb" - integrity sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ== - dependencies: - "@npmcli/fs" "^1.0.0" - "@npmcli/move-file" "^1.0.1" - chownr "^2.0.0" - fs-minipass "^2.0.0" - glob "^7.1.4" - infer-owner "^1.0.4" - lru-cache "^6.0.0" - minipass "^3.1.1" - minipass-collect "^1.0.2" - minipass-flush "^1.0.5" - minipass-pipeline "^1.2.2" - mkdirp "^1.0.3" - p-map "^4.0.0" - promise-inflight "^1.0.1" - rimraf "^3.0.2" - ssri "^8.0.1" - tar "^6.0.2" - unique-filename "^1.1.1" - cacache@^16.0.0, cacache@^16.1.0: version "16.1.3" resolved "https://registry.yarnpkg.com/cacache/-/cacache-16.1.3.tgz#a02b9f34ecfaf9a78c9f4bc16fceb94d5d67a38e" @@ -5612,7 +5560,7 @@ encodeurl@~1.0.2: resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== -encoding@^0.1.12, encoding@^0.1.13: +encoding@^0.1.13: version "0.1.13" resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.13.tgz#56574afdd791f54a8e9b2785c0582a2d26210fa9" integrity sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A== @@ -6344,11 +6292,6 @@ file-entry-cache@^6.0.1: dependencies: flat-cache "^3.0.4" -file-uri-to-path@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" - integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== - file-url@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/file-url/-/file-url-3.0.0.tgz#247a586a746ce9f7a8ed05560290968afc262a77" @@ -7188,15 +7131,6 @@ http-errors@2.0.0: statuses "2.0.1" toidentifier "1.0.1" -http-proxy-agent@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz#8a8c8ef7f5932ccf953c296ca8291b95aa74aa3a" - integrity sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg== - dependencies: - "@tootallnate/once" "1" - agent-base "6" - debug "4" - http-proxy-agent@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz#5129800203520d434f142bc78ff3c170800f2b43" @@ -7310,15 +7244,6 @@ indent-string@^4.0.0: resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== -indy-sdk@^1.16.0-dev-1636, indy-sdk@^1.16.0-dev-1655: - version "1.16.0-dev-1655" - resolved "https://registry.yarnpkg.com/indy-sdk/-/indy-sdk-1.16.0-dev-1655.tgz#098c38df4a6eb4e13f89c0b86ebe9636944b71e0" - integrity sha512-MSWRY8rdnGAegs4v4AnzE6CT9O/3JBMUiE45I0Ihj2DMuH+XS1EJZUQEJsyis6aOQzRavv/xVtaBC8o+6azKuw== - dependencies: - bindings "^1.3.1" - nan "^2.11.1" - node-gyp "^8.0.0" - infer-owner@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/infer-owner/-/infer-owner-1.0.4.tgz#c4cefcaa8e51051c2a40ba2ce8a3d27295af9467" @@ -9035,28 +8960,6 @@ make-fetch-happen@^11.0.0, make-fetch-happen@^11.0.1: socks-proxy-agent "^7.0.0" ssri "^10.0.0" -make-fetch-happen@^9.1.0: - version "9.1.0" - resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz#53085a09e7971433e6765f7971bf63f4e05cb968" - integrity sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg== - dependencies: - agentkeepalive "^4.1.3" - cacache "^15.2.0" - http-cache-semantics "^4.1.0" - http-proxy-agent "^4.0.1" - https-proxy-agent "^5.0.0" - is-lambda "^1.0.1" - lru-cache "^6.0.0" - minipass "^3.1.3" - minipass-collect "^1.0.2" - minipass-fetch "^1.3.2" - minipass-flush "^1.0.5" - minipass-pipeline "^1.2.4" - negotiator "^0.6.2" - promise-retry "^2.0.1" - socks-proxy-agent "^6.0.0" - ssri "^8.0.0" - make-promises-safe@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/make-promises-safe/-/make-promises-safe-5.1.0.tgz#dd9d311f555bcaa144f12e225b3d37785f0aa8f2" @@ -9547,17 +9450,6 @@ minipass-collect@^1.0.2: dependencies: minipass "^3.0.0" -minipass-fetch@^1.3.2: - version "1.4.1" - resolved "https://registry.yarnpkg.com/minipass-fetch/-/minipass-fetch-1.4.1.tgz#d75e0091daac1b0ffd7e9d41629faff7d0c1f1b6" - integrity sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw== - dependencies: - minipass "^3.1.0" - minipass-sized "^1.0.3" - minizlib "^2.0.0" - optionalDependencies: - encoding "^0.1.12" - minipass-fetch@^2.0.3: version "2.1.2" resolved "https://registry.yarnpkg.com/minipass-fetch/-/minipass-fetch-2.1.2.tgz#95560b50c472d81a3bc76f20ede80eaed76d8add" @@ -9595,7 +9487,7 @@ minipass-json-stream@^1.0.1: jsonparse "^1.3.1" minipass "^3.0.0" -minipass-pipeline@^1.2.2, minipass-pipeline@^1.2.4: +minipass-pipeline@^1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz#68472f79711c084657c067c5c6ad93cddea8214c" integrity sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A== @@ -9617,7 +9509,7 @@ minipass@^2.6.0, minipass@^2.9.0: safe-buffer "^5.1.2" yallist "^3.0.0" -minipass@^3.0.0, minipass@^3.1.0, minipass@^3.1.1, minipass@^3.1.3, minipass@^3.1.6: +minipass@^3.0.0, minipass@^3.1.1, minipass@^3.1.6: version "3.3.6" resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.3.6.tgz#7bba384db3a1520d18c9c0e5251c3444e95dd94a" integrity sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw== @@ -9641,7 +9533,7 @@ minizlib@^1.3.3: dependencies: minipass "^2.9.0" -minizlib@^2.0.0, minizlib@^2.1.1, minizlib@^2.1.2: +minizlib@^2.1.1, minizlib@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931" integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg== @@ -9737,11 +9629,6 @@ mute-stream@0.0.8, mute-stream@~0.0.4: resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== -nan@^2.11.1: - version "2.17.0" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.17.0.tgz#c0150a2368a182f033e9aa5195ec76ea41a199cb" - integrity sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ== - nanoid@^3.3.6: version "3.3.7" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8" @@ -9783,7 +9670,7 @@ needle@^2.5.2: iconv-lite "^0.4.4" sax "^1.2.4" -negotiator@0.6.3, negotiator@^0.6.2, negotiator@^0.6.3: +negotiator@0.6.3, negotiator@^0.6.3: version "0.6.3" resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== @@ -9925,22 +9812,6 @@ node-gyp-build@^4.2.1, node-gyp-build@^4.3.0: resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.6.0.tgz#0c52e4cbf54bbd28b709820ef7b6a3c2d6209055" integrity sha512-NTZVKn9IylLwUzaKjkas1e4u2DLNcV4rdYagA4PWdPwW87Bi7z+BznyKSRwS/761tV/lzCGXplWsiaMjLqP2zQ== -node-gyp@^8.0.0: - version "8.4.1" - resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-8.4.1.tgz#3d49308fc31f768180957d6b5746845fbd429937" - integrity sha512-olTJRgUtAb/hOXG0E93wZDs5YiJlgbXxTwQAFHyNlRsXQnYzUaF2aGgujZbw+hR8aF4ZG/rST57bWMWD16jr9w== - dependencies: - env-paths "^2.2.0" - glob "^7.1.4" - graceful-fs "^4.2.6" - make-fetch-happen "^9.1.0" - nopt "^5.0.0" - npmlog "^6.0.0" - rimraf "^3.0.2" - semver "^7.3.5" - tar "^6.1.2" - which "^2.0.2" - node-gyp@^9.0.0: version "9.3.1" resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-9.3.1.tgz#1e19f5f290afcc9c46973d68700cbd21a96192e4" @@ -11744,18 +11615,18 @@ semver@7.3.8: dependencies: lru-cache "^6.0.0" -semver@7.x, semver@^7.0.0, semver@^7.1.1, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8, semver@^7.5.3, semver@^7.5.4: +semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0, semver@^6.3.1: + version "6.3.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== + +semver@^7.0.0, semver@^7.1.1, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8, semver@^7.5.3, semver@^7.5.4: version "7.5.4" resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== dependencies: lru-cache "^6.0.0" -semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0, semver@^6.3.1: - version "6.3.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" - integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== - send@0.18.0: version "0.18.0" resolved "https://registry.yarnpkg.com/send/-/send-0.18.0.tgz#670167cc654b05f5aa4a767f9113bb371bc706be" @@ -11959,15 +11830,6 @@ snapdragon@^0.8.1: source-map-resolve "^0.5.0" use "^3.1.0" -socks-proxy-agent@^6.0.0: - version "6.2.1" - resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-6.2.1.tgz#2687a31f9d7185e38d530bef1944fe1f1496d6ce" - integrity sha512-a6KW9G+6B3nWZ1yB8G7pJwL3ggLy1uTzKAgCb7ttblwqdz9fMGJUuTy3uFzEP48FAs9FLILlmzDlE2JJhVQaXQ== - dependencies: - agent-base "^6.0.2" - debug "^4.3.3" - socks "^2.6.2" - socks-proxy-agent@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-7.0.0.tgz#dc069ecf34436621acb41e3efa66ca1b5fed15b6" @@ -12110,13 +11972,6 @@ ssri@^10.0.0, ssri@^10.0.1: dependencies: minipass "^4.0.0" -ssri@^8.0.0, ssri@^8.0.1: - version "8.0.1" - resolved "https://registry.yarnpkg.com/ssri/-/ssri-8.0.1.tgz#638e4e439e2ffbd2cd289776d5ca457c4f51a2af" - integrity sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ== - dependencies: - minipass "^3.1.1" - stack-utils@^2.0.3: version "2.0.6" resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.6.tgz#aaf0748169c02fc33c8232abccf933f54a1cc34f" @@ -12452,7 +12307,7 @@ tar@^4.4.13: safe-buffer "^5.2.1" yallist "^3.1.1" -tar@^6.0.2, tar@^6.1.11, tar@^6.1.2: +tar@^6.1.11, tar@^6.1.2: version "6.1.13" resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.13.tgz#46e22529000f612180601a6fe0680e7da508847b" integrity sha512-jdIBIN6LTIe2jqzay/2vtYLlBHa3JF42ot3h1dW8Q0PaAG4v8rm0cvpVePtau5C6OKXGGcgO9q2AMNSWxiLqKw== @@ -12643,10 +12498,10 @@ trim-newlines@^3.0.0: resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-3.0.1.tgz#260a5d962d8b752425b32f3a7db0dcacd176c144" integrity sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw== -ts-jest@^29.0.5: - version "29.1.0" - resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-29.1.0.tgz#4a9db4104a49b76d2b368ea775b6c9535c603891" - integrity sha512-ZhNr7Z4PcYa+JjMl62ir+zPiNJfXJN6E8hSLnaUKhOgqcn8vb3e537cpkd0FuAfRK3sR1LSqM1MOhliXNgOFPA== +ts-jest@^29.1.2: + version "29.1.2" + resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-29.1.2.tgz#7613d8c81c43c8cb312c6904027257e814c40e09" + integrity sha512-br6GJoH/WUX4pu7FbZXuWGKGNDuU7b8Uj77g/Sp7puZV6EXzuByl6JrECvm0MzVzSTkSHWTihsXt+5XYER5b+g== dependencies: bs-logger "0.x" fast-json-stable-stringify "2.x" @@ -12654,7 +12509,7 @@ ts-jest@^29.0.5: json5 "^2.2.3" lodash.memoize "4.x" make-error "1.x" - semver "7.x" + semver "^7.5.3" yargs-parser "^21.0.1" ts-node@^10.0.0, ts-node@^10.4.0: @@ -12958,13 +12813,6 @@ union-value@^1.0.0: is-extendable "^0.1.1" set-value "^2.0.1" -unique-filename@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.1.tgz#1d69769369ada0583103a1e6ae87681b56573230" - integrity sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ== - dependencies: - unique-slug "^2.0.0" - unique-filename@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-2.0.1.tgz#e785f8675a9a7589e0ac77e0b5c34d2eaeac6da2" @@ -12979,13 +12827,6 @@ unique-filename@^3.0.0: dependencies: unique-slug "^4.0.0" -unique-slug@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-2.0.2.tgz#baabce91083fc64e945b0f3ad613e264f7cd4e6c" - integrity sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w== - dependencies: - imurmurhash "^0.1.4" - unique-slug@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-3.0.0.tgz#6d347cf57c8a7a7a6044aabd0e2d74e4d76dc7c9"