├── .git-blame-ignore-revs ├── .github ├── CODEOWNERS ├── ISSUE_TEMPLATE.md ├── ISSUE_TEMPLATE │ ├── 1-bug-report.yaml │ ├── 2-feature-request.yaml │ └── config.yml ├── PULL_REQUEST_TEMPLATE.md ├── actions │ └── aggregate-test-reports │ │ └── action.yml ├── labeler.yml └── workflows │ ├── auto-merge.yml │ ├── build.yml │ ├── integration-tests.yml │ ├── lint.yml │ ├── oasdiff.yml │ ├── performance-tests.yml │ ├── pr-lint.yml │ ├── release-clients.yml │ ├── release.yml │ ├── sbt-dependency-submission.yml │ ├── scala-steward.yml │ ├── unit-tests.yml │ └── update-oas.yml ├── .gitignore ├── .mega-linter.yml ├── .pre-commit-config.yaml ├── .protolintrc.yml ├── .sbtopts ├── .scala-steward.conf ├── .scalafix.conf ├── .scalafmt.conf ├── .yamllint.yml ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── DCO.md ├── DEPENDENCIES.md ├── LICENSE ├── MAINTAINERS.md ├── README.md ├── SECURITY.md ├── build.sbt ├── castor ├── CHANGELOG.md ├── README.md └── src │ ├── main │ └── scala │ │ └── org │ │ └── hyperledger │ │ └── identus │ │ └── castor │ │ └── core │ │ ├── model │ │ ├── ProtoModelHelper.scala │ │ ├── did │ │ │ ├── DID.scala │ │ │ ├── DIDData.scala │ │ │ ├── DIDUrl.scala │ │ │ ├── EllipticCurve.scala │ │ │ ├── PrismDID.scala │ │ │ ├── PrismDIDOperation.scala │ │ │ ├── PublicKey.scala │ │ │ ├── Service.scala │ │ │ ├── ServiceEndpoint.scala │ │ │ ├── ServiceType.scala │ │ │ ├── VerificationRelationship.scala │ │ │ └── w3c │ │ │ │ ├── DIDDocumentRepr.scala │ │ │ │ ├── DIDMetadata.scala │ │ │ │ ├── W3CModelHelper.scala │ │ │ │ └── package.scala │ │ └── error │ │ │ └── package.scala │ │ ├── repository │ │ └── DIDOperationRepository.scala │ │ ├── service │ │ └── DIDService.scala │ │ └── util │ │ ├── DIDOperationValidator.scala │ │ ├── Prelude.scala │ │ └── UriUtils.scala │ └── test │ └── scala │ └── org │ └── hyperledger │ └── identus │ └── castor │ └── core │ ├── model │ ├── ProtoModelHelperSpec.scala │ └── did │ │ ├── DIDSpec.scala │ │ ├── DIDUrlSpec.scala │ │ ├── PrismDIDSpec.scala │ │ ├── ServiceEndpointSpec.scala │ │ ├── ServiceTypeSpec.scala │ │ └── w3c │ │ └── W3CModelHelperSpec.scala │ ├── service │ ├── DIDServiceSpec.scala │ └── MockDIDService.scala │ └── util │ ├── DIDOperationValidatorSpec.scala │ └── GenUtils.scala ├── cloud-agent ├── client │ ├── .gitignore │ ├── README.md │ ├── generator │ │ ├── clean.sh │ │ ├── generate-clients.sh │ │ ├── openapitools.json │ │ ├── package.json │ │ ├── publish-clients.sh │ │ └── yarn.lock │ ├── kotlin │ │ ├── .openapi-generator-ignore │ │ ├── build.gradle.kts │ │ ├── gradle.properties │ │ ├── gradle │ │ │ └── wrapper │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ ├── gradlew │ │ ├── gradlew.bat │ │ ├── settings.gradle │ │ └── src │ │ │ └── main │ │ │ └── kotlin │ │ │ └── org │ │ │ └── hyperledger │ │ │ └── identus │ │ │ └── client │ │ │ ├── adapters │ │ │ └── StringOrStringArrayAdapter.kt │ │ │ └── models │ │ │ ├── CredentialSubject.kt │ │ │ ├── DateTimeParameter.kt │ │ │ ├── DidParameter.kt │ │ │ ├── Service.kt │ │ │ ├── UpdateManagedDIDServiceAction.kt │ │ │ └── VcVerificationParameter.kt │ ├── python │ │ ├── .openapi-generator-ignore │ │ └── setup.py │ └── typescript │ │ ├── .openapi-generator-ignore │ │ ├── models │ │ ├── CredentialRequest.ts │ │ ├── Proof2.ts │ │ ├── Service.ts │ │ └── UpdateManagedDIDServiceAction.ts │ │ └── package.json └── service │ ├── CHANGELOG.md │ ├── README.md │ ├── api │ └── http │ │ └── cloud-agent-openapi-spec.yaml │ ├── server │ └── src │ │ ├── main │ │ ├── resources │ │ │ ├── application.conf │ │ │ └── logback.xml │ │ └── scala │ │ │ └── org │ │ │ └── hyperledger │ │ │ └── identus │ │ │ ├── LogUtils.scala │ │ │ ├── agent │ │ │ ├── notification │ │ │ │ ├── JsonEventEncoders.scala │ │ │ │ ├── WebhookPublisher.scala │ │ │ │ └── WebhookPublisherError.scala │ │ │ └── server │ │ │ │ ├── CloudAgentApp.scala │ │ │ │ ├── ControllerHelper.scala │ │ │ │ ├── DidCommHttpServer.scala │ │ │ │ ├── DidCommHttpServerError.scala │ │ │ │ ├── MainApp.scala │ │ │ │ ├── Modules.scala │ │ │ │ ├── config │ │ │ │ └── AppConfig.scala │ │ │ │ ├── http │ │ │ │ ├── CustomServerInterceptors.scala │ │ │ │ ├── DocModels.scala │ │ │ │ ├── ZHttp4sBlazeServer.scala │ │ │ │ ├── ZHttpEndpoints.scala │ │ │ │ └── ZioHttpClient.scala │ │ │ │ ├── jobs │ │ │ │ ├── BackgroundJobError.scala │ │ │ │ ├── BackgroundJobsHelper.scala │ │ │ │ ├── ConnectBackgroundJobs.scala │ │ │ │ ├── DIDStateSyncBackgroundJobs.scala │ │ │ │ ├── IssueBackgroundJobs.scala │ │ │ │ ├── PresentBackgroundJobs.scala │ │ │ │ └── StatusListJobs.scala │ │ │ │ └── sql │ │ │ │ └── Migrations.scala │ │ │ ├── api │ │ │ ├── http │ │ │ │ ├── EndpointOutputs.scala │ │ │ │ ├── ErrorResponse.scala │ │ │ │ ├── RequestContext.scala │ │ │ │ ├── codec │ │ │ │ │ ├── CustomMediaTypes.scala │ │ │ │ │ ├── DIDCodec.scala │ │ │ │ │ ├── DidCommIDCodec.scala │ │ │ │ │ └── OrderCodec.scala │ │ │ │ ├── model │ │ │ │ │ ├── CollectionStats.scala │ │ │ │ │ ├── Order.scala │ │ │ │ │ └── PaginationInput.scala │ │ │ │ └── package.scala │ │ │ └── util │ │ │ │ └── PaginationUtils.scala │ │ │ ├── castor │ │ │ └── controller │ │ │ │ ├── DIDController.scala │ │ │ │ ├── DIDEndpoints.scala │ │ │ │ ├── DIDRegistrarController.scala │ │ │ │ ├── DIDRegistrarEndpoints.scala │ │ │ │ ├── DIDRegistrarServerEndpoints.scala │ │ │ │ ├── DIDServerEndpoints.scala │ │ │ │ └── http │ │ │ │ ├── DIDDocument.scala │ │ │ │ ├── DIDDocumentMetadata.scala │ │ │ │ ├── DIDInput.scala │ │ │ │ ├── DIDResolutionMetadata.scala │ │ │ │ ├── DIDResolutionResult.scala │ │ │ │ ├── ManagedDID.scala │ │ │ │ ├── PublicKeyJwk.scala │ │ │ │ ├── ScheduledOperation.scala │ │ │ │ ├── Service.scala │ │ │ │ ├── UpdateManagedDID.scala │ │ │ │ └── VerificationMethod.scala │ │ │ ├── connect │ │ │ └── controller │ │ │ │ ├── ConnectionController.scala │ │ │ │ ├── ConnectionControllerImpl.scala │ │ │ │ ├── ConnectionEndpoints.scala │ │ │ │ ├── ConnectionServerEndpoints.scala │ │ │ │ └── http │ │ │ │ ├── AcceptConnectionInvitationRequest.scala │ │ │ │ ├── Connection.scala │ │ │ │ ├── ConnectionInvitation.scala │ │ │ │ ├── ConnectionsPage.scala │ │ │ │ └── CreateConnectionRequest.scala │ │ │ ├── credentialstatus │ │ │ └── controller │ │ │ │ ├── CredentialStatusController.scala │ │ │ │ ├── CredentialStatusControllerImpl.scala │ │ │ │ ├── CredentialStatusEndpoints.scala │ │ │ │ ├── CredentialStatusServiceEndpoints.scala │ │ │ │ └── http │ │ │ │ └── StatusListCredential.scala │ │ │ ├── didcomm │ │ │ └── controller │ │ │ │ ├── DIDCommController.scala │ │ │ │ ├── DIDCommControllerError.scala │ │ │ │ ├── DIDCommControllerImpl.scala │ │ │ │ ├── DIDCommEndpoints.scala │ │ │ │ ├── DIDCommServerEndpoints.scala │ │ │ │ └── http │ │ │ │ ├── DIDCommMessage.scala │ │ │ │ ├── Header.scala │ │ │ │ └── Recipient.scala │ │ │ ├── event │ │ │ └── controller │ │ │ │ ├── EventController.scala │ │ │ │ ├── EventEndpoints.scala │ │ │ │ ├── EventServerEndpoints.scala │ │ │ │ └── http │ │ │ │ ├── CreateWebhookNotification.scala │ │ │ │ └── WebhookNotification.scala │ │ │ ├── iam │ │ │ ├── authentication │ │ │ │ ├── AuthenticationConfig.scala │ │ │ │ ├── Authenticator.scala │ │ │ │ ├── DefaultAuthenticator.scala │ │ │ │ ├── Oid4vciAuthenticator.scala │ │ │ │ ├── SecurityLogic.scala │ │ │ │ ├── admin │ │ │ │ │ ├── AdminApiKeyAuthenticator.scala │ │ │ │ │ ├── AdminApiKeyAuthenticatorImpl.scala │ │ │ │ │ ├── AdminApiKeyCredentials.scala │ │ │ │ │ ├── AdminApiKeySecurityLogic.scala │ │ │ │ │ └── AdminConfig.scala │ │ │ │ ├── apikey │ │ │ │ │ ├── ApiKeyAuthenticator.scala │ │ │ │ │ ├── ApiKeyAuthenticatorImpl.scala │ │ │ │ │ ├── ApiKeyConfig.scala │ │ │ │ │ ├── ApiKeyEndpointSecurityLogic.scala │ │ │ │ │ ├── AuthenticationRepository.scala │ │ │ │ │ ├── JdbcAuthenticationRepository.scala │ │ │ │ │ └── package.scala │ │ │ │ └── oidc │ │ │ │ │ ├── JwtCredentials.scala │ │ │ │ │ ├── JwtSecurityLogic.scala │ │ │ │ │ ├── KeycloakAuthenticator.scala │ │ │ │ │ ├── KeycloakAuthenticatorImpl.scala │ │ │ │ │ ├── KeycloakClient.scala │ │ │ │ │ ├── KeycloakConfig.scala │ │ │ │ │ └── Oauth2TokenIntrospector.scala │ │ │ ├── authorization │ │ │ │ ├── DefaultPermissionManagementService.scala │ │ │ │ ├── core │ │ │ │ │ ├── EntityPermissionManagementService.scala │ │ │ │ │ ├── PermissionManagement.scala │ │ │ │ │ ├── PermissionManagementService.scala │ │ │ │ │ └── PermissionManagementServiceError.scala │ │ │ │ └── keycloak │ │ │ │ │ └── admin │ │ │ │ │ └── KeycloakPermissionManagementService.scala │ │ │ ├── entity │ │ │ │ └── http │ │ │ │ │ ├── EntityEndpoints.scala │ │ │ │ │ ├── EntityServerEndpoints.scala │ │ │ │ │ ├── controller │ │ │ │ │ ├── EntityController.scala │ │ │ │ │ └── EntityControllerImpl.scala │ │ │ │ │ └── model │ │ │ │ │ ├── ApiKeyAuthenticationRequest.scala │ │ │ │ │ ├── CreateEntityRequest.scala │ │ │ │ │ ├── EntityResponse.scala │ │ │ │ │ ├── EntityResponsePage.scala │ │ │ │ │ ├── UpdateEntityNameRequest.scala │ │ │ │ │ └── UpdateEntityWalletIdRequest.scala │ │ │ └── wallet │ │ │ │ └── http │ │ │ │ ├── WalletManagementEndpoints.scala │ │ │ │ ├── WalletManagementServerEndpoints.scala │ │ │ │ ├── controller │ │ │ │ └── WalletManagementController.scala │ │ │ │ └── model │ │ │ │ ├── CreateWalletRequest.scala │ │ │ │ ├── CreateWalletUmaPermissionRequest.scala │ │ │ │ └── WalletDetail.scala │ │ │ ├── issue │ │ │ └── controller │ │ │ │ ├── CredentialSchemaReferenceParsingLogic.scala │ │ │ │ ├── IssueController.scala │ │ │ │ ├── IssueControllerImpl.scala │ │ │ │ ├── IssueEndpoints.scala │ │ │ │ ├── IssueServerEndpoints.scala │ │ │ │ └── http │ │ │ │ ├── AcceptCredentialOfferInvitation.scala │ │ │ │ ├── AcceptCredentialOfferRequest.scala │ │ │ │ ├── CreateIssueCredentialRecordRequest.scala │ │ │ │ ├── IssueCredentialOfferInvitation.scala │ │ │ │ ├── IssueCredentialRecord.scala │ │ │ │ └── IssueCredentialRecordPage.scala │ │ │ ├── oid4vci │ │ │ ├── CredentialIssuerEndpoints.scala │ │ │ ├── CredentialIssuerServerEndpoints.scala │ │ │ ├── controller │ │ │ │ └── CredentialIssuerController.scala │ │ │ ├── domain │ │ │ │ ├── IssuanceSession.scala │ │ │ │ └── Openid4VCIProofJwtOps.scala │ │ │ ├── http │ │ │ │ ├── CredentialConfiguration.scala │ │ │ │ ├── CredentialErrorResponse.scala │ │ │ │ ├── CredentialIssuer.scala │ │ │ │ ├── CredentialOffer.scala │ │ │ │ ├── CredentialOfferRequest.scala │ │ │ │ ├── CredentialRequest.scala │ │ │ │ ├── CredentialResponse.scala │ │ │ │ ├── IssuerMetadata.scala │ │ │ │ ├── NonceRequest.scala │ │ │ │ └── NonceResponse.scala │ │ │ ├── service │ │ │ │ └── OIDCCredentialIssuerService.scala │ │ │ └── storage │ │ │ │ └── IssuanceSessionStorage.scala │ │ │ ├── pollux │ │ │ ├── PrismEnvelopeResponse.scala │ │ │ ├── credentialdefinition │ │ │ │ ├── CredentialDefinitionRegistryEndpoints.scala │ │ │ │ ├── CredentialDefinitionRegistryServerEndpoints.scala │ │ │ │ ├── controller │ │ │ │ │ ├── CredentialDefinitionController.scala │ │ │ │ │ ├── CredentialDefinitionControllerImpl.scala │ │ │ │ │ └── CredentialDefinitionControllerLogic.scala │ │ │ │ └── http │ │ │ │ │ ├── CredentialDefinitionDidUrlResponse.scala │ │ │ │ │ ├── CredentialDefinitionDidUrlResponsePage.scala │ │ │ │ │ ├── CredentialDefinitionInput.scala │ │ │ │ │ ├── CredentialDefinitionResponse.scala │ │ │ │ │ ├── CredentialDefinitionResponsePage.scala │ │ │ │ │ ├── FilterInput.scala │ │ │ │ │ └── Proof.scala │ │ │ ├── credentialschema │ │ │ │ ├── SchemaRegistryEndpoints.scala │ │ │ │ ├── SchemaRegistryServerEndpoints.scala │ │ │ │ ├── VerificationPolicyEndpoints.scala │ │ │ │ ├── VerificationPolicyServerEndpoints.scala │ │ │ │ ├── controller │ │ │ │ │ ├── CredentialSchemaController.scala │ │ │ │ │ ├── CredentialSchemaControllerImpl.scala │ │ │ │ │ ├── CredentialSchemaControllerLogic.scala │ │ │ │ │ ├── VerificationPolicyController.scala │ │ │ │ │ ├── VerificationPolicyControllerImpl.scala │ │ │ │ │ └── VerificationPolicyPageRequestLogic.scala │ │ │ │ └── http │ │ │ │ │ ├── CredentialSchemaDidUrlResponse.scala │ │ │ │ │ ├── CredentialSchemaDidUrlResponsePage.scala │ │ │ │ │ ├── CredentialSchemaInput.scala │ │ │ │ │ ├── CredentialSchemaResponse.scala │ │ │ │ │ ├── CredentialSchemaResponsePage.scala │ │ │ │ │ ├── FilterInput.scala │ │ │ │ │ ├── Proof.scala │ │ │ │ │ └── VerificationPolicyResponse.scala │ │ │ └── prex │ │ │ │ ├── PresentationExchangeEndpoints.scala │ │ │ │ ├── PresentationExchangeServerEndpoints.scala │ │ │ │ ├── controller │ │ │ │ └── PresentationExchangeController.scala │ │ │ │ └── http │ │ │ │ ├── PresentationDefinition.scala │ │ │ │ └── PresentationExchangeTapirSchemas.scala │ │ │ ├── presentproof │ │ │ └── controller │ │ │ │ ├── PresentProofController.scala │ │ │ │ ├── PresentProofControllerImpl.scala │ │ │ │ ├── PresentProofEndpoints.scala │ │ │ │ ├── PresentProofServerEndpoints.scala │ │ │ │ └── http │ │ │ │ ├── AcceptRequestPresentationInvitation.scala │ │ │ │ ├── OOBPresentationInvitation.scala │ │ │ │ ├── Options.scala │ │ │ │ ├── PresentationStatus.scala │ │ │ │ ├── PresentationStatusPage.scala │ │ │ │ ├── ProofRequestAux.scala │ │ │ │ ├── RequestPresentationAction.scala │ │ │ │ └── RequestPresentationInput.scala │ │ │ ├── system │ │ │ └── controller │ │ │ │ ├── SystemController.scala │ │ │ │ ├── SystemControllerImpl.scala │ │ │ │ ├── SystemEndpoints.scala │ │ │ │ ├── SystemServerEndpoints.scala │ │ │ │ └── http │ │ │ │ └── HealthInfo.scala │ │ │ └── verification │ │ │ └── controller │ │ │ ├── VcVerificationController.scala │ │ │ ├── VcVerificationControllerImpl.scala │ │ │ ├── VcVerificationEndpoints.scala │ │ │ ├── VcVerificationServerEndpoints.scala │ │ │ └── http │ │ │ ├── ParameterizableVcVerification.scala │ │ │ ├── VcVerification.scala │ │ │ ├── VcVerificationParameter.scala │ │ │ ├── VcVerificationRequest.scala │ │ │ ├── VcVerificationResponse.scala │ │ │ └── VcVerificationResult.scala │ │ └── test │ │ ├── resources │ │ ├── anoncred-schema-example.json │ │ ├── logback.xml │ │ └── vc-schema-example.json │ │ └── scala │ │ └── org │ │ └── hyperledger │ │ └── identus │ │ ├── ZioHttpTest.scala │ │ ├── agent │ │ └── server │ │ │ ├── AgentInitializationSpec.scala │ │ │ └── config │ │ │ └── AppConfigSpec.scala │ │ ├── api │ │ └── util │ │ │ ├── PaginationUtilsSpec.scala │ │ │ └── Tapir2StaticOAS.scala │ │ ├── container │ │ └── util │ │ │ └── MigrationAspect.scala │ │ ├── iam │ │ ├── authentication │ │ │ ├── SecurityLogicSpec.scala │ │ │ ├── apikey │ │ │ │ ├── ApiKeyAuthenticatorSpec.scala │ │ │ │ └── JdbcAuthenticationRepositorySpec.scala │ │ │ └── oidc │ │ │ │ └── KeycloakAuthenticatorSpec.scala │ │ └── authorization │ │ │ ├── core │ │ │ └── EntityPermissionManagementSpec.scala │ │ │ └── keycloak │ │ │ └── admin │ │ │ ├── KeycloakAdmin.scala │ │ │ ├── KeycloakAdminSpec.scala │ │ │ ├── KeycloakConfigUtils.scala │ │ │ └── KeycloakPermissionManagementServiceSpec.scala │ │ ├── issue │ │ └── controller │ │ │ ├── CredentialSchemaReferenceParsingLogicSpec.scala │ │ │ ├── IssueControllerImplSpec.scala │ │ │ └── IssueControllerTestTools.scala │ │ ├── oid4vci │ │ └── domain │ │ │ └── OIDCCredentialIssuerServiceSpec.scala │ │ ├── pollux │ │ ├── credentialdefinition │ │ │ ├── CredentialDefinitionBasicSpec.scala │ │ │ ├── CredentialDefinitionFailureSpec.scala │ │ │ ├── CredentialDefinitionLookupAndPaginationSpec.scala │ │ │ └── CredentialDefinitionTestTools.scala │ │ └── schema │ │ │ ├── CredentialSchemaAnoncredSpec.scala │ │ │ ├── CredentialSchemaBasicSpec.scala │ │ │ ├── CredentialSchemaFailureSpec.scala │ │ │ ├── CredentialSchemaLookupAndPaginationSpec.scala │ │ │ ├── CredentialSchemaMultiTenancySpec.scala │ │ │ └── CredentialSchemaTestTools.scala │ │ ├── system │ │ └── controller │ │ │ ├── SystemControllerImplSpec.scala │ │ │ └── SystemControllerTestTools.scala │ │ └── verification │ │ └── controller │ │ ├── VcVerificationControllerImplSpec.scala │ │ └── VcVerificationControllerTestTools.scala │ └── wallet-api │ └── src │ ├── main │ ├── resources │ │ └── sql │ │ │ └── agent │ │ │ ├── V10__create_peer_did_table.sql │ │ │ ├── V11__wallet_seed_digest.sql │ │ │ ├── V12__generic_secret.sql │ │ │ ├── V13__apikey_authentication_improvements.sql │ │ │ ├── V14__multiple_did_key_types.sql │ │ │ ├── V15__add_did_index_table.sql │ │ │ ├── V1__init_tables.sql │ │ │ ├── V2__did_nonsecret_storage.sql │ │ │ ├── V3__did_update_state.sql │ │ │ ├── V4__did_hd_key.sql │ │ │ ├── V5__remove_did_rand_key.sql │ │ │ ├── V6__add_schema_id_to_secret_table.sql │ │ │ ├── V7__mutitenant_wallet.sql │ │ │ ├── V8__init_entity_repository_tables.sql │ │ │ └── V9__init_authentication_repository_tables.sql │ └── scala │ │ └── org │ │ └── hyperledger │ │ └── identus │ │ └── agent │ │ └── walletapi │ │ ├── model │ │ ├── Entity.scala │ │ ├── KeyManagement.scala │ │ ├── ManagedDID.scala │ │ ├── ManagedDIDTemplate.scala │ │ ├── PeerDIDRecord.scala │ │ ├── Wallet.scala │ │ └── error │ │ │ ├── CreateManagedDIDError.scala │ │ │ ├── DIDSecretStorageError.scala │ │ │ ├── EntityServiceError.scala │ │ │ ├── GetManagedDIDError.scala │ │ │ ├── PublishManagedDIDError.scala │ │ │ ├── UpdateManagedDIDError.scala │ │ │ └── package.scala │ │ ├── service │ │ ├── EntityService.scala │ │ ├── EntityServiceImpl.scala │ │ ├── ManagedDIDService.scala │ │ ├── ManagedDIDServiceImpl.scala │ │ ├── ManagedDIDServiceWithEventNotificationImpl.scala │ │ ├── WalletManagementService.scala │ │ ├── WalletManagementServiceImpl.scala │ │ └── handler │ │ │ ├── DIDCreateHandler.scala │ │ │ ├── DIDUpdateHandler.scala │ │ │ └── PublicationHandler.scala │ │ ├── sql │ │ ├── EntityRepository.scala │ │ ├── JdbcDIDNonSecretStorage.scala │ │ ├── JdbcDIDSecretStorage.scala │ │ ├── JdbcEntityRepository.scala │ │ ├── JdbcGenericSecretStorage.scala │ │ ├── JdbcWalletNonSecretStorage.scala │ │ ├── JdbcWalletSecretStorage.scala │ │ ├── model │ │ │ ├── GenericSecret.scala │ │ │ ├── Wallet.scala │ │ │ └── package.scala │ │ └── package.scala │ │ ├── storage │ │ ├── DIDNonSecretStorage.scala │ │ ├── DIDSecretStorage.scala │ │ ├── GenericSecretStorage.scala │ │ ├── WalletNonSecretStorage.scala │ │ └── WalletSecretStorage.scala │ │ ├── util │ │ ├── KeyResolver.scala │ │ ├── ManagedDIDTemplateValidator.scala │ │ ├── OperationFactory.scala │ │ └── UpdateManagedDIDActionValidator.scala │ │ └── vault │ │ ├── VaultClient.scala │ │ ├── VaultDIDSecretStorage.scala │ │ ├── VaultGenericSecretStorage.scala │ │ ├── VaultWalletSecretStorage.scala │ │ └── package.scala │ └── test │ ├── resources │ └── logback.xml │ └── scala │ └── org │ └── hyperledger │ └── identus │ ├── agent │ └── walletapi │ │ ├── benchmark │ │ └── KeyDerivation.scala │ │ ├── memory │ │ ├── GenericSecretStorageInMemory.scala │ │ └── WalletSecretStorageInMemory.scala │ │ ├── service │ │ ├── ManagedDIDServiceSpec.scala │ │ ├── MockManagedDIDService.scala │ │ └── WalletManagementServiceSpec.scala │ │ ├── storage │ │ ├── DIDSecretStorageSpec.scala │ │ ├── GenericSecretStorageSpec.scala │ │ ├── JdbcEntityRepositorySpec.scala │ │ ├── JdbcWalletNonSecretStorageSpec.scala │ │ ├── MockDIDNonSecretStorage.scala │ │ ├── StorageSpecHelper.scala │ │ └── WalletSecretStorageSpec.scala │ │ └── util │ │ ├── ManagedDIDTemplateValidatorSpec.scala │ │ ├── OperationFactorySpec.scala │ │ └── UpdateManagedDIDActionValidatorSpec.scala │ └── test │ └── container │ ├── DBTestUtils.scala │ ├── VaultLayer.scala │ └── VaultTestContainerSupport.scala ├── connect ├── CHANGELOG.md ├── README.md ├── connect-protocol-state.md ├── core │ └── src │ │ ├── main │ │ └── scala │ │ │ └── org │ │ │ └── hyperledger │ │ │ └── identus │ │ │ └── connect │ │ │ └── core │ │ │ ├── model │ │ │ ├── ConnectionRecord.scala │ │ │ ├── WalletIdAndRecordId.scala │ │ │ └── error │ │ │ │ └── ConnectionServiceError.scala │ │ │ ├── repository │ │ │ └── ConnectionRepository.scala │ │ │ └── service │ │ │ ├── ConnectionService.scala │ │ │ ├── ConnectionServiceImpl.scala │ │ │ └── ConnectionServiceNotifier.scala │ │ └── test │ │ └── scala │ │ └── org │ │ └── hyperledger │ │ └── identus │ │ └── connect │ │ └── core │ │ ├── repository │ │ ├── ConnectionRepositoryInMemory.scala │ │ ├── ConnectionRepositoryInMemorySpec.scala │ │ └── ConnectionRepositorySpecSuite.scala │ │ └── service │ │ ├── ConnectionServiceImplSpec.scala │ │ ├── ConnectionServiceNotifierSpec.scala │ │ └── MockConnectionService.scala └── sql-doobie │ └── src │ ├── main │ ├── resources │ │ └── sql │ │ │ └── connect │ │ │ ├── V1__init_tables.sql │ │ │ ├── V2__add_thid_unique_constraint.sql │ │ │ ├── V3__add_meta_retries_and_meta_last_failure.sql │ │ │ ├── V4__create_protocol_state_index.sql │ │ │ ├── V5__add_meta_next_retry.sql │ │ │ ├── V6__add_rls_policy.sql │ │ │ ├── V7__add_goal_and_goal_code.sql │ │ │ └── V8__clear_content_of_meta_last_failure.sql │ └── scala │ │ └── org │ │ └── hyperledger │ │ └── identus │ │ └── connect │ │ └── sql │ │ └── repository │ │ ├── JdbcConnectionRepository.scala │ │ └── Migrations.scala │ └── test │ ├── resources │ └── logback.xml │ └── scala │ └── org │ └── hyperledger │ └── identus │ ├── connect │ └── sql │ │ └── repository │ │ └── JdbcConnectionRepositorySpec.scala │ └── test │ └── container │ └── PostgresTestContainer.scala ├── docs ├── .gitkeep ├── README.md ├── docker-compose.yml ├── docusaurus │ ├── connections │ │ ├── connection-flow.png │ │ ├── connection-flow.puml │ │ └── connection.md │ ├── credentialdefinition │ │ ├── create.md │ │ ├── credential-definition.md │ │ └── delete.md │ ├── credentials │ │ ├── connectionless │ │ │ ├── issue.md │ │ │ └── present-proof.md │ │ ├── didcomm │ │ │ ├── anoncreds-setup.png │ │ │ ├── anoncreds-setup.puml │ │ │ ├── issue-flow.anoncreds.png │ │ │ ├── issue-flow.anoncreds.puml │ │ │ ├── issue-flow.jwt.png │ │ │ ├── issue-flow.jwt.puml │ │ │ ├── issue.md │ │ │ ├── present-proof-flow.anoncreds.png │ │ │ ├── present-proof-flow.anoncreds.puml │ │ │ ├── present-proof-flow.jwt.png │ │ │ ├── present-proof-flow.jwt.puml │ │ │ └── present-proof.md │ │ ├── oid4vci │ │ │ └── issue.md │ │ └── revocation.md │ ├── dids │ │ ├── create.md │ │ ├── deactivate.md │ │ ├── publish.md │ │ └── update.md │ ├── index.md │ ├── multitenancy │ │ ├── access-control.md │ │ ├── account-management.md │ │ ├── admin-authz-ext-iam.md │ │ ├── create_client_role.png │ │ ├── tenant-migration.md │ │ ├── tenant-onboarding-ext-iam.md │ │ ├── tenant-onboarding-self-service.md │ │ └── tenant-onboarding.md │ ├── schemas │ │ ├── create.md │ │ ├── credential-schema.md │ │ ├── delete.md │ │ └── update.md │ ├── secrets │ │ ├── operation.md │ │ ├── secret-storage.md │ │ ├── seed-generation.md │ │ └── sequence-diagrams.md │ ├── sidebars.js │ └── webhooks │ │ └── webhook.md ├── general │ ├── authserver-oid4vci-contract.md │ └── key-derivation-benchmark.md ├── guides │ ├── linting.md │ └── signing-commits.md └── images │ ├── dco.png │ ├── identus-architecture-dark.png │ ├── identus-architecture-light.png │ ├── identus-cloud-agent-architecture-dark.png │ ├── identus-cloud-agent-architecture-light.png │ └── logos │ ├── identus-logo.png │ └── identus-logo.svg ├── event-notification └── src │ ├── main │ └── scala │ │ └── org │ │ └── hyperledger │ │ └── identus │ │ └── event │ │ └── notification │ │ ├── Event.scala │ │ ├── EventConsumer.scala │ │ ├── EventNotificationConfig.scala │ │ ├── EventNotificationService.scala │ │ ├── EventNotificationServiceError.scala │ │ ├── EventNotificationServiceImpl.scala │ │ └── EventProducer.scala │ └── test │ └── scala │ └── org │ └── hyperledger │ └── identus │ ├── event │ └── notification │ │ └── EventNotificationServiceImplSpec.scala │ └── messaging │ ├── MessagingServiceTest.scala │ └── kafka │ └── InMemoryMessagingServiceSpec.scala ├── examples ├── .nickel │ ├── agent.ncl │ ├── bootstrap.ncl │ ├── build.sh │ ├── caddy.ncl │ ├── db.ncl │ ├── keycloak.ncl │ ├── node.ncl │ ├── root.ncl │ ├── stack.ncl │ ├── vault.ncl │ └── versions.ncl ├── .shared │ ├── hurl │ │ └── simple_realm │ │ │ └── 01_init_realm.hurl │ └── postgres │ │ ├── init-script.sh │ │ └── max_conns.sql ├── README.md ├── mt-keycloak-vault │ ├── README.md │ ├── compose.yaml │ └── hurl │ │ ├── 01_create_users.hurl │ │ ├── 02_jwt_flow.hurl │ │ └── local ├── mt-keycloak │ ├── README.md │ ├── compose.yaml │ └── hurl │ │ ├── 01_create_users.hurl │ │ ├── 02_jwt_flow.hurl │ │ └── local ├── mt │ ├── README.md │ └── compose.yaml ├── st-multi │ ├── README.md │ ├── compose.yaml │ └── hurl │ │ ├── 01_jwt_flow.hurl │ │ └── local ├── st-oid4vci │ ├── README.md │ ├── bootstrap │ │ └── 01_init_realm.hurl │ ├── compose.yaml │ └── demo │ │ ├── Dockerfile │ │ ├── main.py │ │ └── requirements.txt ├── st-vault │ ├── README.md │ └── compose.yaml └── st │ ├── README.md │ └── compose.yaml ├── infrastructure ├── charts │ └── agent │ │ ├── .helmignore │ │ ├── Chart.lock │ │ ├── Chart.yaml │ │ ├── templates │ │ ├── _helpers.tpl │ │ ├── apisixconsumer.yaml │ │ ├── apisixroute.yaml │ │ ├── apisixtls.yaml │ │ ├── certificate.yaml │ │ ├── configmap.yaml │ │ ├── deployment.yaml │ │ ├── externalsecret.yaml │ │ ├── podmonitor-postgresql.yaml │ │ ├── postgresql.yaml │ │ ├── service.yaml │ │ ├── stringsecret-agent-admin-token.yaml │ │ ├── stringsecret-agent-api-key-salt.yaml │ │ ├── stringsecret-agent-keycloak-secret.yaml │ │ ├── stringsecret-agent-wallet-seed.yaml │ │ ├── stringsecret.yaml │ │ └── vault-unseal.yaml │ │ └── values.yaml ├── dev │ ├── README.md │ ├── build.sh │ ├── clean.sh │ ├── full.sh │ ├── get-versions.sh │ ├── run.sh │ └── stop.sh ├── local │ ├── .env │ ├── README.md │ ├── run-e2e-tests-local.sh │ ├── run.sh │ ├── stop.sh │ └── update_env.sh ├── multi │ ├── .env │ ├── README.md │ ├── run-e2e-tests-local.sh │ ├── run-e2e-tests-remote.sh │ ├── run.sh │ └── stop.sh ├── shared │ ├── apisix │ │ └── conf │ │ │ ├── apisix-holder.yaml │ │ │ ├── apisix-issuer.yaml │ │ │ ├── apisix-verifier.yaml │ │ │ ├── apisix.yaml │ │ │ └── config.yaml │ ├── docker-compose-combined.yml │ ├── docker-compose-demo.yml │ ├── docker-compose-mt-keycloak.yml │ ├── docker-compose-with-kafka.yml │ ├── docker-compose.yml │ ├── keycloak │ │ └── init-script.sh │ ├── nginx │ │ └── nginx.conf │ └── postgres │ │ ├── init-script.sh │ │ └── max_conns.sql ├── single-tenant-testing-stack │ ├── .env │ ├── apisix │ │ └── conf │ │ │ ├── apisix.yaml │ │ │ └── config.yaml │ ├── dashboards │ │ ├── ica-k6-detail.json │ │ └── ica-k8s-overview.json │ ├── docker-compose.yml │ ├── postgres │ │ ├── init-script.sh │ │ └── max_conns.sql │ ├── run-e2e-tests-local.sh │ └── run-performance-tests-local.sh └── utils │ └── python │ └── github-helpers │ ├── .gitignore │ ├── github_helpers │ ├── __init__.py │ ├── api.py │ ├── cli.py │ └── test_cli.py │ └── setup.py ├── logging.md ├── mercury ├── CHANGELOG.md ├── QuickStart.md ├── README.md ├── UseCases.md ├── agent-didcommx │ └── src │ │ ├── main │ │ └── scala │ │ │ └── org │ │ │ └── hyperledger │ │ │ └── identus │ │ │ └── mercury │ │ │ ├── AgentPeerService.scala │ │ │ ├── DidCommX.scala │ │ │ ├── MessagingService.scala │ │ │ ├── PeerDID.scala │ │ │ ├── model │ │ │ ├── Conversions.scala │ │ │ ├── JsonUtilsForDidCommx.scala │ │ │ └── package.scala │ │ │ └── resolvers │ │ │ ├── AliceSecretResolver.scala │ │ │ └── BobSecretResolver.scala │ │ └── test │ │ └── scala │ │ └── org │ │ └── hyperledger │ │ └── identus │ │ └── mercury │ │ ├── PeerDIDSpec.scala │ │ └── model │ │ └── UnpackMessageImpSpec.scala ├── agent │ └── src │ │ └── main │ │ └── scala │ │ └── org │ │ └── hyperledger │ │ └── identus │ │ └── mercury │ │ ├── Agent.scala │ │ ├── CoordinateMediationPrograms.scala │ │ ├── HttpClient.scala │ │ ├── InvitationPrograms.scala │ │ └── OutOfBandLoginPrograms.scala ├── models │ └── src │ │ └── main │ │ └── scala │ │ └── org │ │ └── hyperledger │ │ └── identus │ │ └── mercury │ │ ├── DidAgent.scala │ │ ├── DidOps.scala │ │ ├── MediaTypes.scala │ │ └── model │ │ ├── AttachmentDescriptor.scala │ │ ├── DidId.scala │ │ ├── EncryptedMessage.scala │ │ ├── Message.scala │ │ ├── SignedMesage.scala │ │ ├── UnpackResult.scala │ │ └── error │ │ └── package.scala ├── protocol-connection │ ├── Connection-Protocol.md │ └── src │ │ ├── main │ │ └── scala │ │ │ └── org │ │ │ └── hyperledger │ │ │ └── identus │ │ │ └── mercury │ │ │ └── protocol │ │ │ └── connection │ │ │ ├── ConnectionInvitation.scala │ │ │ ├── ConnectionRequest.scala │ │ │ └── ConnectionResponse.scala │ │ └── test │ │ └── scala │ │ └── org │ │ └── hyperledger │ │ └── identus │ │ └── mercury │ │ └── protocol │ │ └── connection │ │ └── ConnectionSpec.scala ├── protocol-coordinate-mediation │ ├── Coordinate-Mediation-Protocol.md │ └── src │ │ ├── main │ │ └── scala │ │ │ └── org │ │ │ └── hyperledger │ │ │ └── identus │ │ │ └── mercury │ │ │ └── protocol │ │ │ └── coordinatemediation │ │ │ └── CoordinateMediation.scala │ │ └── test │ │ └── scala │ │ └── org │ │ └── hyperledger │ │ └── identus │ │ └── mercury │ │ └── protocol │ │ └── coordinatemediation │ │ └── CoordinateMediationSpec.scala ├── protocol-did-exchange │ ├── DidExchange-Protocol.md │ └── src │ │ └── main │ │ └── scala │ │ └── org │ │ └── hyperledger │ │ └── identus │ │ └── mercury │ │ └── protocol │ │ └── didexchange │ │ └── v1 │ │ └── DidExchangeRequest.scala ├── protocol-invitation │ ├── Invitation-Protocol.md │ └── src │ │ ├── main │ │ └── scala │ │ │ └── org │ │ │ └── hyperledger │ │ │ └── identus │ │ │ └── mercury │ │ │ └── protocol │ │ │ └── invitation │ │ │ ├── OutOfBand.scala │ │ │ ├── ServiceType.scala │ │ │ ├── package.scala │ │ │ ├── v1 │ │ │ └── Invitation.scala │ │ │ └── v2 │ │ │ └── Invitation.scala │ │ └── test │ │ └── scala │ │ └── org │ │ └── hyperledger │ │ └── identus │ │ └── mercury │ │ └── protocol │ │ └── invitation │ │ ├── v1 │ │ └── InvitationV1Spec.scala │ │ └── v2 │ │ └── OutOfBandSpec.scala ├── protocol-issue-credential │ ├── Issue-Credential-Protocol.md │ └── src │ │ ├── main │ │ └── scala │ │ │ └── org │ │ │ └── hyperledger │ │ │ └── identus │ │ │ └── mercury │ │ │ └── protocol │ │ │ └── issuecredential │ │ │ ├── CredentialPreview.scala │ │ │ ├── IssueCredential.scala │ │ │ ├── IssueCredentialInvitation.scala │ │ │ ├── IssueFormats.scala │ │ │ ├── OfferCredential.scala │ │ │ ├── ProposeCredential.scala │ │ │ ├── RequestCredential.scala │ │ │ └── Utils.scala │ │ └── test │ │ └── scala │ │ └── org │ │ └── hyperledger │ │ └── identus │ │ └── mercury │ │ └── protocol │ │ ├── anotherclasspath │ │ └── UtilsCredentialSpec.scala │ │ └── issuecredential │ │ ├── IssueCredentialSpec.scala │ │ ├── OfferCredentialSpec.scala │ │ ├── ProposeCredentialSpec.scala │ │ └── RequestCredentialSpec.scala ├── protocol-outofband-login │ ├── OutOfBand-Login-Protocol.md │ └── src │ │ └── main │ │ └── scala │ │ └── org │ │ └── hyperledger │ │ └── identus │ │ └── mercury │ │ └── protocol │ │ └── outofbandlogin │ │ ├── OutOfBandLogin.scala │ │ └── Utils.scala ├── protocol-present-proof │ ├── Present-Proof-Protocol.md │ └── src │ │ ├── main │ │ └── scala │ │ │ └── org │ │ │ └── hyperledger │ │ │ └── identus │ │ │ └── mercury │ │ │ └── protocol │ │ │ └── presentproof │ │ │ ├── PresentFormats.scala │ │ │ ├── PresentProofInvitation.scala │ │ │ ├── Presentation.scala │ │ │ ├── ProofType.scala │ │ │ ├── ProposePresentation.scala │ │ │ └── RequestPresentation.scala │ │ └── test │ │ └── scala │ │ └── org │ │ └── hyperledger │ │ └── identus │ │ └── mercury │ │ └── protocol │ │ └── presentproof │ │ ├── PresentationSpec.scala │ │ ├── ProposePresentationProofSpec.scala │ │ └── RequestPresentationSpec.scala ├── protocol-report-problem │ ├── Report-Problem-Protocol.md │ └── src │ │ ├── main │ │ └── scala │ │ │ └── org │ │ │ └── hyperledger │ │ │ └── identus │ │ │ └── mercury │ │ │ └── protocol │ │ │ └── reportproblem │ │ │ ├── v1 │ │ │ └── ReportProblem.scala │ │ │ └── v2 │ │ │ └── ReportProblem.scala │ │ └── test │ │ └── scala │ │ └── org │ │ └── hyperledger │ │ └── identus │ │ └── mercury │ │ └── protocol │ │ └── reportproblem │ │ └── v2 │ │ └── ReportProblemSpec.scala ├── protocol-revocation-notification │ ├── Revocation-notification-protocol.md │ └── src │ │ └── main │ │ └── scala │ │ └── org │ │ └── hyperledger │ │ └── identus │ │ └── mercury │ │ └── protocol │ │ └── revocationnotificaiton │ │ └── RevocationNotification.scala ├── protocol-routing │ ├── Routing-Protocol.md │ └── src │ │ └── main │ │ └── scala │ │ └── org │ │ └── hyperledger │ │ └── identus │ │ └── mercury │ │ └── protocol │ │ └── routing │ │ └── ForwardMessage.scala ├── protocol-trust-ping │ └── src │ │ └── main │ │ └── scala │ │ └── org │ │ └── hyperledger │ │ └── identus │ │ └── mercury │ │ └── protocol │ │ └── trustping │ │ ├── TrustPing.scala │ │ └── TrustPingResponse.scala ├── resolver │ └── src │ │ ├── main │ │ └── scala │ │ │ └── org │ │ │ └── hyperledger │ │ │ └── identus │ │ │ └── resolvers │ │ │ ├── DidValidator.scala │ │ │ ├── PeerDidResolver.scala │ │ │ └── UniversalDidResolver.scala │ │ └── test │ │ └── scala │ │ └── org │ │ └── hyperledger │ │ └── identus │ │ └── resolvers │ │ ├── AliceDidDoc.scala │ │ ├── BobDidDoc.scala │ │ ├── DidValidatorSpec.scala │ │ ├── MediatorDidDoc.scala │ │ └── PeerDidResolverSpec.scala └── vc │ └── src │ └── main │ └── scala │ └── io │ └── iohk │ └── atala │ └── mercury │ └── vc │ ├── anoncreds │ ├── CredentialFilterFormat.scala │ ├── CredentialFormat.scala │ ├── CredentialOfferFormat.scala │ ├── CredentialRequestFormat.scala │ ├── ProofFormat.scala │ └── ProofRequestFormat.scala │ ├── dif │ └── ProposeCredential.scala │ └── jwt │ └── ProposeCredential.scala ├── package-lock.json ├── package.json ├── pollux ├── CHANGELOG.md ├── README.md ├── anoncreds │ ├── README_anoncreds.md │ ├── anoncreds-jvm-1.0-SNAPSHOT.jar │ ├── native-lib │ │ ├── NATIVE │ │ │ ├── darwin-aarch64 │ │ │ │ └── libuniffi_anoncreds_wrapper.dylib │ │ │ ├── darwin-x86-64 │ │ │ │ └── libuniffi_anoncreds_wrapper.dylib │ │ │ ├── linux-aarch64 │ │ │ │ └── libuniffi_anoncreds_wrapper.so │ │ │ └── linux-x86-64 │ │ │ │ └── libuniffi_anoncreds_wrapper.so │ │ └── helper_script_to_update.sh │ └── src │ │ └── main │ │ └── scala │ │ └── org │ │ └── hyperledger │ │ └── identus │ │ └── pollux │ │ └── anoncreds │ │ ├── AnoncredLib.scala │ │ └── Models.scala ├── anoncredsTest │ └── src │ │ └── test │ │ └── scala │ │ ├── Uniffy.scala │ │ └── org │ │ └── hyperledger │ │ └── identus │ │ └── pollux │ │ └── anoncreds │ │ └── PoCNewLib.scala ├── core │ └── src │ │ ├── main │ │ └── scala │ │ │ └── org │ │ │ └── hyperledger │ │ │ └── identus │ │ │ └── pollux │ │ │ └── core │ │ │ ├── model │ │ │ ├── CredentialFormat.scala │ │ │ ├── CredentialOfferAttachment.scala │ │ │ ├── CredentialStatusList.scala │ │ │ ├── DidCommID.scala │ │ │ ├── IssueCredentialRecord.scala │ │ │ ├── PresentationRecord.scala │ │ │ ├── ResourceResolutionMethod.scala │ │ │ ├── VerificationPolicy.scala │ │ │ ├── error │ │ │ │ ├── CredentialDefinitionServiceError.scala │ │ │ │ ├── CredentialSchemaError.scala │ │ │ │ ├── CredentialSchemaServiceError.scala │ │ │ │ ├── CredentialServiceError.scala │ │ │ │ ├── CredentialStatusListServiceError.scala │ │ │ │ ├── LinkSecretError.scala │ │ │ │ ├── PresentationError.scala │ │ │ │ └── VerificationPolicyError.scala │ │ │ ├── oid4vci │ │ │ │ ├── CredentialConfiguration.scala │ │ │ │ └── CredentialIssuer.scala │ │ │ ├── presentation │ │ │ │ └── PresentationAttachment.scala │ │ │ ├── primitives │ │ │ │ ├── UriString.scala │ │ │ │ └── UrlString.scala │ │ │ ├── schema │ │ │ │ ├── CredentialDefinition.scala │ │ │ │ ├── CredentialSchema.scala │ │ │ │ ├── CredentialSchemaRef.scala │ │ │ │ └── type │ │ │ │ │ ├── AnoncredSchemaType.scala │ │ │ │ │ ├── CredentialJsonSchemaSerDesV1.scala │ │ │ │ │ ├── CredentialJsonSchemaType.scala │ │ │ │ │ ├── CredentialSchemaType.scala │ │ │ │ │ └── anoncred │ │ │ │ │ └── AnoncredSchemaSerDesV1.scala │ │ │ └── secret │ │ │ │ └── CredentialDefinitionSecret.scala │ │ │ ├── repository │ │ │ ├── CredentialDefinitionRepository.scala │ │ │ ├── CredentialRepository.scala │ │ │ ├── CredentialSchemaRepository.scala │ │ │ ├── CredentialStatusListRepository.scala │ │ │ ├── OID4VCIIssuerMetadataRepository.scala │ │ │ ├── PresentationExchangeRepository.scala │ │ │ ├── PresentationRepository.scala │ │ │ ├── VerificationPolicyRepository.scala │ │ │ └── repository.scala │ │ │ └── service │ │ │ ├── CredentialDefinitionService.scala │ │ │ ├── CredentialDefinitionServiceImpl.scala │ │ │ ├── CredentialSchemaService.scala │ │ │ ├── CredentialSchemaServiceImpl.scala │ │ │ ├── CredentialService.scala │ │ │ ├── CredentialServiceImpl.scala │ │ │ ├── CredentialServiceNotifier.scala │ │ │ ├── CredentialStatusListService.scala │ │ │ ├── CredentialStatusListServiceImpl.scala │ │ │ ├── GenericUriResolverImpl.scala │ │ │ ├── LinkSecretService.scala │ │ │ ├── LinkSecretServiceImpl.scala │ │ │ ├── OID4VCIIssuerMetadataService.scala │ │ │ ├── PresentationExchangeService.scala │ │ │ ├── PresentationExchangeServiceImpl.scala │ │ │ ├── PresentationService.scala │ │ │ ├── PresentationServiceImpl.scala │ │ │ ├── PresentationServiceNotifier.scala │ │ │ ├── VerificationPolicyService.scala │ │ │ ├── VerificationPolicyServiceImpl.scala │ │ │ ├── serdes │ │ │ ├── AnoncredCredentialProofsV1.scala │ │ │ ├── AnoncredPresentationRequestV1.scala │ │ │ ├── AnoncredPresentationV1.scala │ │ │ ├── PrivateCredentialDefinitionSchemaSerDesV1.scala │ │ │ ├── ProofKeyCredentialDefinitionSchemaSerDesV1.scala │ │ │ ├── PublicCredentialDefinitionSchemaSerDesV1.scala │ │ │ └── SDJwtPresentationRequest.scala │ │ │ ├── uriResolvers │ │ │ ├── DidUrlResolver.scala │ │ │ ├── HttpUrlResolver.scala │ │ │ └── ResourceUrlResolver.scala │ │ │ └── verification │ │ │ ├── VcVerification.scala │ │ │ ├── VcVerificationService.scala │ │ │ ├── VcVerificationServiceError.scala │ │ │ └── VcVerificationServiceImpl.scala │ │ └── test │ │ ├── resources │ │ ├── anoncred-presentation-schema-example.json │ │ ├── anoncred-schema-example.json │ │ ├── logback.xml │ │ ├── vc-schema-driver-license.json │ │ ├── vc-schema-example.json │ │ └── vc-schema-personal.json │ │ └── scala │ │ └── org │ │ └── hyperledger │ │ └── identus │ │ └── pollux │ │ └── core │ │ ├── model │ │ ├── presentation │ │ │ └── PresentationAttachmentSpec.scala │ │ └── schema │ │ │ ├── AnoncredSchemaTypeSpec.scala │ │ │ └── CredentialSchemaSpec.scala │ │ ├── repository │ │ ├── CredentialDefinitionRepositoryInMemory.scala │ │ ├── CredentialRepositoryInMemory.scala │ │ ├── CredentialRepositoryInMemorySpec.scala │ │ ├── CredentialRepositorySpecSuite.scala │ │ ├── CredentialStatusListRepositoryInMemory.scala │ │ ├── OID4VCIIssuerMetadataRepositorySpecSuite.scala │ │ ├── PresentationExchangeRepositorySpecSuite.scala │ │ ├── PresentationRepositoryInMemory.scala │ │ ├── PresentationRepositoryInMemorySpec.scala │ │ └── PresentationRepositorySpecSuite.scala │ │ └── service │ │ ├── CredentialDefinitionServiceImplSpec.scala │ │ ├── CredentialDefinitionServiceSpecHelper.scala │ │ ├── CredentialServiceImplSpec.scala │ │ ├── CredentialServiceNotifierSpec.scala │ │ ├── CredentialServiceSpecHelper.scala │ │ ├── LinkSecretServiceImplSpec.scala │ │ ├── MockCredentialService.scala │ │ ├── MockOID4VCIIssuerMetadataService.scala │ │ ├── MockPresentationService.scala │ │ ├── OID4VCIIssuerMetadataServiceSpecSuite.scala │ │ ├── PresentationServiceNotifierSpec.scala │ │ ├── PresentationServiceSpec.scala │ │ ├── PresentationServiceSpecHelper.scala │ │ ├── serdes │ │ ├── AnoncredPresentationRequestSpec.scala │ │ ├── AnoncredPresentationSpec.scala │ │ └── PublicCredentialDefinitionSchemaSerDesSpec.scala │ │ ├── uriResolvers │ │ └── DidUrlResolverSpec.scala │ │ └── verification │ │ ├── VcVerificationServiceImplSpec.scala │ │ └── VcVerificationServiceSpecHelper.scala ├── docs │ └── verification-policy.md ├── issue-protocol-state.md ├── prex │ └── src │ │ ├── main │ │ └── scala │ │ │ └── org │ │ │ └── hyperledger │ │ │ └── identus │ │ │ └── pollux │ │ │ └── prex │ │ │ ├── PresentationDefinition.scala │ │ │ ├── PresentationDefinitionValidator.scala │ │ │ ├── PresentationSubmission.scala │ │ │ └── PresentationSubmissionVerification.scala │ │ └── test │ │ ├── resources │ │ ├── pd │ │ │ ├── filter_by_cred_type.json │ │ │ ├── minimal_example.json │ │ │ ├── single_group.json │ │ │ └── two_filters_simplified.json │ │ └── ps │ │ │ ├── basic_presentation.json │ │ │ └── nested_presentation.json │ │ └── scala │ │ └── org │ │ └── hyperledger │ │ └── identus │ │ └── pollux │ │ └── prex │ │ ├── PresentationDefinitionValidatorSpec.scala │ │ ├── PresentationSubmissionSpec.scala │ │ └── PresentationSubmissionVerificationSpec.scala ├── sd-jwt │ └── src │ │ ├── main │ │ └── scala │ │ │ └── org │ │ │ └── hyperledger │ │ │ └── identus │ │ │ └── pollux │ │ │ └── sdjwt │ │ │ ├── CompactFormat.scala │ │ │ ├── CrytoUtils.scala │ │ │ ├── Models.scala │ │ │ ├── ModelsExtensionMethods.scala │ │ │ ├── QueryUtils.scala │ │ │ └── SDJWT.scala │ │ └── test │ │ └── scala │ │ └── org │ │ └── hyperledger │ │ └── identus │ │ └── pollux │ │ └── sdjwt │ │ ├── SDJWTSpec.scala │ │ └── ValidClaimsSpec.scala ├── sql-doobie │ └── src │ │ ├── main │ │ ├── resources │ │ │ └── sql │ │ │ │ └── pollux │ │ │ │ ├── V10__presentation_records_add_thid_unique_constraint.sql │ │ │ │ ├── V11__issue_credential_extend_schema_id.sql │ │ │ │ ├── V12__verification_policies_reset_nonce.sql │ │ │ │ ├── V13__credential_schema_tables.sql │ │ │ │ ├── V14__add_rls_policy.sql │ │ │ │ ├── V15__add_anoncreds_columns.sql │ │ │ │ ├── V16__revocation_status_lists_table_and_columns.sql │ │ │ │ ├── V17__add_anoncred_credentials_to_use_columns.sql │ │ │ │ ├── V18__issue_credential_rename_schema_id.sql │ │ │ │ ├── V19__update_revocation_status_list_table_and_columns.sql │ │ │ │ ├── V1__init_tables.sql │ │ │ │ ├── V20__add_sdjwt_claims_to_disclose_columns.sql │ │ │ │ ├── V21__add_issuer_metadata.sql │ │ │ │ ├── V22__add_keyId_column_issue_credential_record.sql │ │ │ │ ├── V23__clear_content_of_meta_last_failure.sql │ │ │ │ ├── V24__add_invitation_column_presentation_record.sql │ │ │ │ ├── V25__add_invitation_column_invitation_record.sql │ │ │ │ ├── V26__remove_subject_id_column_presentation_record.sql │ │ │ │ ├── V27__presentation_definition_table.sql │ │ │ │ ├── V28__support_multiple_credential_schema.sql │ │ │ │ ├── V29__add_resolution_method_to_schema_and_cred_definition.sql │ │ │ │ ├── V30__add_sdjwt_disclosed_claims_columns.sql │ │ │ │ ├── V3__schema_registry_tables.sql │ │ │ │ ├── V5__create_protocol_state_index.sql │ │ │ │ ├── V6__verification_policy_tables.sql │ │ │ │ ├── V8__credential_schema_tables.sql │ │ │ │ └── V9__issue_credential_drop_subjectId_not_null.sql │ │ └── scala │ │ │ └── org │ │ │ └── hyperledger │ │ │ └── identus │ │ │ └── pollux │ │ │ └── sql │ │ │ ├── model │ │ │ ├── JWTCredentialRow.scala │ │ │ └── db │ │ │ │ ├── CredentialDefinition.scala │ │ │ │ ├── CredentialSchema.scala │ │ │ │ ├── PresentationDefinition.scala │ │ │ │ ├── VerificationPolicy.scala │ │ │ │ └── package.scala │ │ │ └── repository │ │ │ ├── Implicits.scala │ │ │ ├── JdbcCredentialDefinitionRepository.scala │ │ │ ├── JdbcCredentialRepository.scala │ │ │ ├── JdbcCredentialSchemaRepository.scala │ │ │ ├── JdbcCredentialStatusListRepository.scala │ │ │ ├── JdbcOID4VCIIssuerMetadataRepository.scala │ │ │ ├── JdbcPresentationExchangeRepository.scala │ │ │ ├── JdbcPresentationRepository.scala │ │ │ ├── JdbcVerificationPolicyRepository.scala │ │ │ └── Migrations.scala │ │ └── test │ │ ├── resources │ │ └── data │ │ │ ├── verifiableCredentialClaims.csv │ │ │ └── verifiableCredentialTypes.csv │ │ └── scala │ │ └── org │ │ └── hyperledger │ │ └── identus │ │ ├── pollux │ │ ├── core │ │ │ └── service │ │ │ │ └── OID4VCIIssuerMetadataServiceSpec.scala │ │ └── sql │ │ │ ├── CredentialDefinitionSqlIntegrationSpec.scala │ │ │ ├── CredentialSchemaSqlIntegrationSpec.scala │ │ │ ├── VerificationPolicySqlIntegrationSpec.scala │ │ │ └── repository │ │ │ ├── JdbcCredentialRepositorySpec.scala │ │ │ ├── JdbcOID4VCIIssuerMetadataRepositorySpec.scala │ │ │ ├── JdbcPresentationExchangeRepositorySpec.scala │ │ │ └── JdbcPresentationRepositorySpec.scala │ │ └── test │ │ └── container │ │ └── MigrationAspect.scala └── vc-jwt │ └── src │ ├── main │ └── scala │ │ └── org │ │ └── hyperledger │ │ └── identus │ │ └── pollux │ │ └── vc │ │ └── jwt │ │ ├── CredentialSchemaAndTrustedIssuersConstraint.scala │ │ ├── DidJWT.scala │ │ ├── DidResolver.scala │ │ ├── EcdsaSecp256k1VerificationKey2019.scala │ │ ├── JWTVerification.scala │ │ ├── JsonEncoders.scala │ │ ├── JsonWebKey.scala │ │ ├── MultiBaseString.scala │ │ ├── MultiKey.scala │ │ ├── Proof.scala │ │ ├── ValidationUtils.scala │ │ ├── Verifiable.scala │ │ ├── VerifiableCredentialPayload.scala │ │ ├── VerifiablePresentationPayload.scala │ │ └── revocation │ │ ├── BitString.scala │ │ └── VCStatusList2021.scala │ └── test │ └── scala │ └── org │ └── hyperledger │ └── identus │ └── pollux │ └── vc │ └── jwt │ ├── ECDSAVerifierTest.scala │ ├── ES256KSignerTest.scala │ ├── JWTVerificationTest.scala │ ├── JwtPresentationTest.scala │ └── revocation │ ├── BitStringSpec.scala │ └── VCStatusList2021Spec.scala ├── prism-node └── client │ └── scala-client │ ├── CHANGELOG.md │ ├── README.md │ ├── api │ └── grpc │ │ ├── common_models.proto │ │ ├── connector_api.proto │ │ ├── connector_models.proto │ │ ├── console_api.proto │ │ ├── console_models.proto │ │ ├── credential_models.proto │ │ ├── cviews_api.proto │ │ ├── cviews_models.proto │ │ ├── health.proto │ │ ├── intdemo │ │ ├── intdemo_api.proto │ │ └── intdemo_models.proto │ │ ├── node_api.proto │ │ ├── node_internal.proto │ │ ├── node_models.proto │ │ ├── package.json │ │ ├── resources │ │ └── markdown.tmpl │ │ └── status.proto │ └── src │ └── main │ └── resources │ └── package.proto ├── project ├── LicenseReport.scala ├── build.properties ├── build.sbt └── plugins.sbt ├── release.config.mjs ├── shared ├── README.md ├── core │ └── src │ │ └── main │ │ └── scala │ │ └── org │ │ └── hyperledger │ │ └── identus │ │ └── shared │ │ ├── db │ │ ├── ContextAwareTask.scala │ │ ├── DbConfig.scala │ │ └── TransactorLayer.scala │ │ ├── http │ │ ├── DataUrlResolver.scala │ │ └── GenericUriResolver.scala │ │ ├── messaging │ │ ├── MessagingService.scala │ │ ├── MessagingServiceConfig.scala │ │ ├── Serde.scala │ │ ├── WalletIdAndRecordId.scala │ │ └── kafka │ │ │ ├── InMemoryMessagingService.scala │ │ │ └── ZKafkaMessagingServiceImpl.scala │ │ ├── models │ │ ├── Base64UrlString.scala │ │ ├── Failure.scala │ │ ├── HexString.scala │ │ ├── KeyId.scala │ │ ├── MultiTenancy.scala │ │ └── PrismEnvelope.scala │ │ ├── utils │ │ ├── Base64Utils.scala │ │ ├── BytesOps.scala │ │ ├── DurationOps.scala │ │ ├── Traverse.scala │ │ ├── aspects │ │ │ └── CustomMetricsAspect.scala │ │ └── proto │ │ │ ├── Path.scala │ │ │ ├── ValidationError.scala │ │ │ └── package.scala │ │ └── validation │ │ └── ValidationUtils.scala ├── crypto │ └── src │ │ ├── main │ │ └── scala │ │ │ └── org │ │ │ └── hyperledger │ │ │ └── identus │ │ │ └── shared │ │ │ └── crypto │ │ │ ├── Apollo.scala │ │ │ ├── KmpApollo.scala │ │ │ ├── Sha256.scala │ │ │ └── jwk │ │ │ └── JWK.scala │ │ └── test │ │ └── scala │ │ └── org │ │ └── hyperledger │ │ └── identus │ │ └── shared │ │ └── crypto │ │ ├── ApolloSpec.scala │ │ └── ApolloSpecHelper.scala ├── json │ └── src │ │ ├── main │ │ ├── resources │ │ │ └── json-schema │ │ │ │ └── draft-07.json │ │ └── scala │ │ │ └── org │ │ │ └── hyperledger │ │ │ └── identus │ │ │ └── shared │ │ │ └── json │ │ │ ├── Json.scala │ │ │ ├── JsonOps.scala │ │ │ ├── JsonPath.scala │ │ │ └── JsonSchema.scala │ │ └── test │ │ └── scala │ │ └── org │ │ └── hyperledger │ │ └── identus │ │ └── shared │ │ └── json │ │ ├── JsonLdLoadSpec.scala │ │ └── JsonPathSpec.scala ├── predef │ └── src │ │ └── main │ │ └── scala │ │ └── org │ │ └── hyperledger │ │ └── identus │ │ └── Predef.scala └── test │ └── src │ └── test │ └── scala │ └── org │ └── hyperledger │ └── identus │ └── sharedtest │ └── containers │ ├── KeycloakContainerCustom.scala │ ├── KeycloakTestContainer.scala │ ├── KeycloakTestContainerSupport.scala │ ├── KeycloakTestContainerSupportSpec.scala │ ├── PostgreSQLContainerCustom.scala │ ├── PostgresLayer.scala │ ├── PostgresTestContainer.scala │ ├── PostgresTestContainerSupport.scala │ ├── VaultContainerCustom.scala │ └── VaultTestContainer.scala ├── tests ├── didcomm-tests │ ├── docker │ │ ├── docker-compose.yml │ │ ├── initdb.js │ │ ├── postgres │ │ │ ├── init-script.sh │ │ │ └── max_conns.sql │ │ ├── run.sh │ │ └── stop.sh │ └── package.json ├── integration-tests │ ├── .editorconfig │ ├── .gitignore │ ├── CONTRIBUTING.md │ ├── README.md │ ├── build.gradle.kts │ ├── docs │ │ └── static │ │ │ ├── functional_coverage.png │ │ │ ├── intellij.png │ │ │ ├── logs.png │ │ │ ├── report_summary.png │ │ │ ├── rest_requests.png │ │ │ ├── screenplay.png │ │ │ ├── serenity_context.png │ │ │ └── system_under_test.png │ ├── gradle.properties │ ├── gradle │ │ └── wrapper │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ ├── gradlew │ ├── gradlew.bat │ ├── hosts_test │ ├── serenity.properties │ ├── settings.gradle.kts │ └── src │ │ └── test │ │ ├── kotlin │ │ ├── IntegrationTestsRunner.kt │ │ ├── abilities │ │ │ └── ListenToEvents.kt │ │ ├── common │ │ │ ├── CreateCredentialOfferAPIVersion.kt │ │ │ ├── CredentialClaims.kt │ │ │ ├── CredentialSchema.kt │ │ │ ├── CredentialType.kt │ │ │ ├── DidDocumentTemplate.kt │ │ │ ├── DidType.kt │ │ │ ├── TestConstants.kt │ │ │ ├── VerifiableJwt.kt │ │ │ └── errors │ │ │ │ ├── CredentialOfferError.kt │ │ │ │ ├── JwtCredentialError.kt │ │ │ │ └── SchemaTemplateError.kt │ │ ├── config │ │ │ ├── AgentRole.kt │ │ │ ├── Config.kt │ │ │ ├── Role.kt │ │ │ ├── VaultAuthType.kt │ │ │ ├── Webhook.kt │ │ │ └── services │ │ │ │ ├── Agent.kt │ │ │ │ ├── Keycloak.kt │ │ │ │ ├── Service.kt │ │ │ │ ├── ServiceBase.kt │ │ │ │ ├── Vault.kt │ │ │ │ └── VerifiableDataRegistry.kt │ │ ├── eu │ │ │ └── europa │ │ │ │ └── ec │ │ │ │ └── eudi │ │ │ │ └── openid4vci │ │ │ │ └── HttpsUrl.kt │ │ ├── interactions │ │ │ ├── AuthRestExtensions.kt │ │ │ ├── AuthRestInteraction.kt │ │ │ ├── Delete.kt │ │ │ ├── Get.kt │ │ │ ├── Patch.kt │ │ │ ├── Post.kt │ │ │ └── Put.kt │ │ ├── models │ │ │ ├── AnoncredsSchema.kt │ │ │ ├── Events.kt │ │ │ ├── JsonSchema.kt │ │ │ ├── JsonSchemaProperty.kt │ │ │ ├── JwtCredential.kt │ │ │ └── SdJwtClaim.kt │ │ └── steps │ │ │ ├── Setup.kt │ │ │ ├── common │ │ │ ├── CommonSteps.kt │ │ │ └── ParameterSteps.kt │ │ │ ├── connection │ │ │ └── ConnectionSteps.kt │ │ │ ├── connectionless │ │ │ └── ConnectionLessSteps.kt │ │ │ ├── credentials │ │ │ ├── AnoncredSteps.kt │ │ │ ├── CredentialSteps.kt │ │ │ ├── JwtCredentialSteps.kt │ │ │ ├── RevokeCredentialSteps.kt │ │ │ └── SdJwtCredentialSteps.kt │ │ │ ├── did │ │ │ ├── CreateDidSteps.kt │ │ │ ├── DeactivateDidSteps.kt │ │ │ ├── ManageDidSteps.kt │ │ │ └── UpdateDidSteps.kt │ │ │ ├── multitenancy │ │ │ ├── EntitySteps.kt │ │ │ ├── EventsSteps.kt │ │ │ └── WalletsSteps.kt │ │ │ ├── oid4vci │ │ │ ├── IssueCredentialSteps.kt │ │ │ ├── ManageCredentialConfigSteps.kt │ │ │ └── ManageIssuerSteps.kt │ │ │ ├── proofs │ │ │ ├── AnoncredProofSteps.kt │ │ │ ├── HolderProofSteps.kt │ │ │ ├── JwtProofSteps.kt │ │ │ ├── SdJwtProofSteps.kt │ │ │ └── VerifierProofSteps.kt │ │ │ ├── schemas │ │ │ ├── AnoncredCredentialSchemaSteps.kt │ │ │ └── CredentialSchemasSteps.kt │ │ │ ├── system │ │ │ └── SystemSteps.kt │ │ │ ├── verification │ │ │ └── VcVerificationSteps.kt │ │ │ └── verificationpolicies │ │ │ └── VerificationPoliciesSteps.kt │ │ └── resources │ │ ├── configs │ │ ├── basic.conf │ │ ├── mt_keycloak.conf │ │ ├── mt_keycloak_agent_role.conf │ │ ├── mt_keycloak_vault.conf │ │ ├── mt_vault_approle.conf │ │ ├── mt_vault_token.conf │ │ ├── two_agents_basic.conf │ │ └── two_agents_sharing_keycloak.conf │ │ ├── containers │ │ ├── agent.yml │ │ ├── keycloak-oid4vci.yml │ │ ├── keycloak.yml │ │ ├── postgres │ │ │ ├── init-script.sh │ │ │ └── max_conns.sql │ │ ├── vault.yml │ │ └── vdr.yml │ │ ├── features │ │ ├── connection │ │ │ └── connection.feature │ │ ├── credential │ │ │ ├── anoncred │ │ │ │ ├── issuance-refactoring.feature │ │ │ │ ├── issuance.feature │ │ │ │ └── present_proof.feature │ │ │ ├── jwt │ │ │ │ ├── issuance-refactoring.feature │ │ │ │ ├── issuance.feature │ │ │ │ ├── present_proof.feature │ │ │ │ └── revocation.feature │ │ │ └── sdjwt │ │ │ │ ├── issuance-refactoring.feature │ │ │ │ ├── issuance.feature │ │ │ │ └── present_proof.feature │ │ ├── did │ │ │ ├── create_did.feature │ │ │ ├── deactivate_did.feature │ │ │ ├── listing_did.feature │ │ │ └── update_did.feature │ │ ├── multitenancy │ │ │ └── wallets.feature │ │ ├── oid4vci │ │ │ ├── issue_jwt.feature │ │ │ ├── manage_credential_config.feature │ │ │ └── manage_issuer.feature │ │ ├── schemas │ │ │ └── credential_schemas.feature │ │ ├── system │ │ │ ├── health_endpoint.feature │ │ │ └── metrics_endpoint.feature │ │ ├── verificationapi │ │ │ └── vc_verification.feature │ │ └── verificationpolicies │ │ │ └── verification_policies.feature │ │ └── logback-test.xml └── performance-tests │ ├── agent-performance-tests-k6 │ ├── .babelrc │ ├── .env │ ├── .gitignore │ ├── .npmrc │ ├── .yarnrc │ ├── README.md │ ├── package.json │ ├── run.sh │ ├── src │ │ ├── actors │ │ │ ├── Actor.ts │ │ │ ├── Holder.ts │ │ │ ├── Issuer.ts │ │ │ ├── Verifier.ts │ │ │ └── index.ts │ │ ├── common │ │ │ ├── Config.ts │ │ │ ├── ConnectionService.ts │ │ │ ├── CredentialsService.ts │ │ │ ├── DidService.ts │ │ │ ├── HttpService.ts │ │ │ └── ProofsService.ts │ │ ├── k6chaijs.js │ │ ├── scenarios │ │ │ └── default.ts │ │ └── tests │ │ │ ├── common.ts │ │ │ ├── credentials │ │ │ ├── credential-definition-test.ts │ │ │ ├── credential-offer-test.ts │ │ │ └── credential-schema-test.ts │ │ │ ├── dids │ │ │ ├── create-prism-did-test.ts │ │ │ └── did-publishing-test.ts │ │ │ └── flows │ │ │ ├── connection-flow-test.ts │ │ │ ├── issuance-flow-test.ts │ │ │ └── present-proof-flow-test.ts │ ├── tsconfig.json │ ├── webpack.config.js │ └── yarn.lock │ └── agent-performance-tests │ ├── .gitignore │ ├── README.md │ ├── bin │ └── gatling │ │ ├── common │ │ ├── Configuration.kt │ │ └── Utils.kt │ │ ├── gatling.conf │ │ ├── simulations │ │ ├── ConnectionSimulation.kt │ │ └── IssuanceSimulation.kt │ │ └── steps │ │ ├── ConnectionSteps.kt │ │ └── IssuanceSteps.kt │ ├── build.gradle.kts │ ├── gradle.properties │ ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties │ ├── gradlew │ ├── gradlew.bat │ ├── settings.gradle.kts │ └── src │ └── gatling │ ├── kotlin │ ├── common │ │ ├── Configuration.kt │ │ └── Utils.kt │ ├── simulations │ │ ├── ConnectionSimulation.kt │ │ └── IssuanceSimulation.kt │ └── steps │ │ ├── ConnectionSteps.kt │ │ └── IssuanceSteps.kt │ └── resources │ └── gatling.conf └── version.sbt /.git-blame-ignore-revs: -------------------------------------------------------------------------------- 1 | # Scala Steward: Reformat with scalafmt 3.7.17 2 | 343e8a9fc72b5bb036ff5de7d78e4ca661d3daeb 3 | 4 | # Scala Steward: Reformat with scalafmt 3.8.3 5 | a9110aafdb5e6d26522ee297ab8cb357601ff091 6 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @hyperledger-identus/identus-maintainers 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | To submit a new issue, please, use one of the following templates: 2 | 3 | 4 | 5 | Thank you! 6 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/1-bug-report.yaml: -------------------------------------------------------------------------------- 1 | name: Bug Report 2 | description: Report a bug in the Identus Cloud Agent 3 | 4 | body: 5 | - type: dropdown 6 | id: is-regression 7 | attributes: 8 | label: Is this a regression? 9 | options: 10 | - "Yes" 11 | - "No" 12 | validations: 13 | required: true 14 | 15 | - type: textarea 16 | id: description 17 | attributes: 18 | label: Description 19 | validations: 20 | required: true 21 | 22 | - type: textarea 23 | id: exception-or-error 24 | attributes: 25 | label: Please provide the exception or error you saw 26 | render: "Markdown" 27 | 28 | - type: textarea 29 | id: environment 30 | attributes: 31 | label: Please provide the environment you discovered this bug in 32 | render: "Markdown" 33 | 34 | - type: textarea 35 | id: other 36 | attributes: 37 | label: Anything else? 38 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/2-feature-request.yaml: -------------------------------------------------------------------------------- 1 | name: 'Feature Request' 2 | description: Suggest a new feature for Identus Cloud Agent 3 | 4 | body: 5 | - type: textarea 6 | id: proposed-feature 7 | attributes: 8 | label: Proposed feature 9 | validations: 10 | required: true 11 | 12 | - type: textarea 13 | id: description 14 | attributes: 15 | label: Feature description 16 | validations: 17 | required: true 18 | 19 | - type: textarea 20 | id: other 21 | attributes: 22 | label: Anything else? 23 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | -------------------------------------------------------------------------------- /.github/actions/aggregate-test-reports/action.yml: -------------------------------------------------------------------------------- 1 | name: "Aggregate test reports" 2 | description: "Aggregates all TEST-*.xml reports for all subprojects in one directory" 3 | inputs: 4 | tests-dir: 5 | description: "Top-level directory to search for reports. Defaults to current dir." 6 | required: false 7 | default: "." 8 | reports-dir: 9 | description: "Name of the directory that contains test reports" 10 | required: false 11 | default: "test-reports" 12 | runs: 13 | using: "composite" 14 | steps: 15 | - name: "Aggregate reports" 16 | shell: bash 17 | run: | 18 | for REPORTS in $(find ${{ inputs.tests-dir }} -name ${{ inputs.reports-dir }} ); do 19 | PROJECT="${REPORTS%/target/*}" 20 | DEST="${{ inputs.tests-dir }}/target/${{ inputs.reports-dir }}/${PROJECT}" 21 | mkdir -p ${DEST} 22 | cp -r "${REPORTS}" "${DEST}" 23 | done 24 | -------------------------------------------------------------------------------- /.github/workflows/pr-lint.yml: -------------------------------------------------------------------------------- 1 | name: "Validate PR Title" 2 | 3 | on: 4 | pull_request_target: 5 | types: 6 | - opened 7 | - edited 8 | - synchronize 9 | 10 | permissions: 11 | pull-requests: read 12 | 13 | jobs: 14 | main: 15 | name: Validate PR Title 16 | runs-on: ubuntu-latest 17 | steps: 18 | - uses: amannn/action-semantic-pull-request@v5 19 | env: 20 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | report 3 | megalinter-reports/ 4 | .vscode 5 | .bloop 6 | .bsp 7 | .jvmopts 8 | .metals 9 | sbt-launch.jar 10 | **/project/metals.sbt 11 | target 12 | **/.DS_Store 13 | shell.nix 14 | .envrc 15 | node_modules/ 16 | package-lock.json 17 | .dotty-ide-disabled 18 | **/.docker-volumes/* 19 | target/ 20 | **.env.* 21 | workspace.json 22 | docs/architecture/structurizr/.structurizr/ 23 | cloud-agent/client/typescript 24 | cloud-agent/client/kotlin/src/main/kotlin/ 25 | !cloud-agent/client/kotlin/src/main/kotlin/org/hyperledger/identus/client/models/CredentialSubject.kt 26 | !cloud-agent/client/kotlin/src/main/kotlin/org/hyperledger/identus/client/models/Service.kt 27 | !cloud-agent/client/kotlin/src/main/kotlin/org/hyperledger/identus/client/models/UpdateManagedDIDServiceAction.kt 28 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # See https://pre-commit.com for more information 3 | # See https://pre-commit.com/hooks.html for more hooks 4 | repos: 5 | - repo: https://github.com/pre-commit/pre-commit-hooks 6 | rev: v3.2.0 7 | hooks: 8 | - id: trailing-whitespace 9 | - id: end-of-file-fixer 10 | - id: check-added-large-files 11 | - repo: https://github.com/compilerla/conventional-pre-commit 12 | rev: v1.4.0 13 | hooks: 14 | - id: conventional-pre-commit 15 | stages: [commit-msg] 16 | - repo: https://github.com/oxsecurity/megalinter 17 | rev: v6.18.0 # Git tag specifying the hook, not mega-linter-runner, version 18 | hooks: 19 | - id: megalinter-incremental # Faster, less thorough 20 | stages: 21 | - commit 22 | - id: megalinter-full # Slower, more thorough 23 | stages: 24 | - push 25 | -------------------------------------------------------------------------------- /.protolintrc.yml: -------------------------------------------------------------------------------- 1 | lint: 2 | rules: 3 | # include all default rules 4 | no_default: false 5 | 6 | # disable some specific rules 7 | remove: 8 | - REPEATED_FIELD_NAMES_PLURALIZED 9 | - ENUM_FIELD_NAMES_PREFIX 10 | - ENUM_FIELD_NAMES_ZERO_VALUE_END_WITH 11 | - FIELD_NAMES_LOWER_SNAKE_CASE 12 | -------------------------------------------------------------------------------- /.sbtopts: -------------------------------------------------------------------------------- 1 | -Dquill.macro.log=false 2 | -J-Xmx4G 3 | -J-XX:+UseG1GC 4 | -------------------------------------------------------------------------------- /.scalafix.conf: -------------------------------------------------------------------------------- 1 | rules = [ OrganizeImports ] 2 | 3 | OrganizeImports.groupedImports = Merge 4 | OrganizeImports.removeUnused = false 5 | OrganizeImports.targetDialect = Scala3 6 | -------------------------------------------------------------------------------- /.scalafmt.conf: -------------------------------------------------------------------------------- 1 | version = 3.9.6 2 | runner.dialect = scala3 3 | 4 | maxColumn = 120 5 | trailingCommas = preserve 6 | 7 | rewrite.rules = [Imports] 8 | rewrite.imports.expand = false 9 | rewrite.imports.sort = original 10 | rewrite.imports.groups = [ 11 | [".*"], 12 | ["java\\..*", "scala\\..*"] 13 | ] 14 | -------------------------------------------------------------------------------- /.yamllint.yml: -------------------------------------------------------------------------------- 1 | ########################################### 2 | # These are the rules used for # 3 | # linting all the yaml files in the stack # 4 | # NOTE: # 5 | # You can disable line with: # 6 | # # yamllint disable-line # 7 | ########################################### 8 | extends: default 9 | rules: 10 | new-lines: 11 | level: warning 12 | type: unix 13 | line-length: 14 | max: 600 15 | comments: 16 | min-spaces-from-content: 1 # Used to follow prettier standard: https://github.com/prettier/prettier/pull/10926 17 | level: warning 18 | document-start: disable 19 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | Code of Conduct 2 | =============== 3 | 4 | Identus follows Hyperledger [Code of Conduct](https://wiki.hyperledger.org/community/hyperledger-project-code-of-conduct). 5 | 6 | Please, read before contributing to the project. 7 | -------------------------------------------------------------------------------- /castor/README.md: -------------------------------------------------------------------------------- 1 | # Castor 2 | 3 | ## Project structure 4 | ### core 5 | Core library with models and `did:prism` method implementation 6 | 7 | ### sql-doobie 8 | Data access library of Castor. Contain flyway migrations, `dto` objects and CRUD operations -------------------------------------------------------------------------------- /castor/src/main/scala/org/hyperledger/identus/castor/core/model/did/DIDData.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.castor.core.model.did 2 | 3 | import java.time.Instant 4 | import scala.collection.immutable.ArraySeq 5 | 6 | final case class DIDData( 7 | id: CanonicalPrismDID, 8 | publicKeys: Seq[PublicKey], 9 | services: Seq[Service], 10 | internalKeys: Seq[InternalPublicKey], 11 | context: Seq[String] 12 | ) 13 | 14 | final case class DIDMetadata( 15 | lastOperationHash: ArraySeq[Byte], 16 | canonicalId: Option[CanonicalPrismDID], 17 | deactivated: Boolean, 18 | created: Option[Instant], 19 | updated: Option[Instant] 20 | ) 21 | -------------------------------------------------------------------------------- /castor/src/main/scala/org/hyperledger/identus/castor/core/model/did/EllipticCurve.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.castor.core.model.did 2 | 3 | // EC Name is used in JWK https://w3c-ccg.github.io/security-vocab/#publicKeyJwk 4 | // It MUST match the curve name in https://www.iana.org/assignments/jose/jose.xhtml 5 | // in the "JSON Web Key Elliptic Curve" section 6 | enum EllipticCurve(val name: String) { 7 | case SECP256K1 extends EllipticCurve("secp256k1") 8 | case ED25519 extends EllipticCurve("Ed25519") 9 | case X25519 extends EllipticCurve("X25519") 10 | } 11 | 12 | object EllipticCurve { 13 | 14 | private val lookup = EllipticCurve.values.map(i => i.name -> i).toMap 15 | 16 | def parseString(s: String): Option[EllipticCurve] = lookup.get(s) 17 | 18 | } 19 | -------------------------------------------------------------------------------- /castor/src/main/scala/org/hyperledger/identus/castor/core/model/did/PublicKey.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.castor.core.model.did 2 | 3 | import org.hyperledger.identus.shared.models.{Base64UrlString, KeyId} 4 | 5 | final case class PublicKey( 6 | id: KeyId, 7 | purpose: VerificationRelationship, 8 | publicKeyData: PublicKeyData 9 | ) 10 | 11 | enum InternalKeyPurpose { 12 | case Master extends InternalKeyPurpose 13 | case Revocation extends InternalKeyPurpose 14 | } 15 | 16 | final case class InternalPublicKey( 17 | id: KeyId, 18 | purpose: InternalKeyPurpose, 19 | publicKeyData: PublicKeyData 20 | ) 21 | 22 | sealed trait PublicKeyData { 23 | def crv: EllipticCurve 24 | } 25 | 26 | object PublicKeyData { 27 | final case class ECKeyData(crv: EllipticCurve, x: Base64UrlString, y: Base64UrlString) extends PublicKeyData 28 | final case class ECCompressedKeyData(crv: EllipticCurve, data: Base64UrlString) extends PublicKeyData 29 | } 30 | -------------------------------------------------------------------------------- /castor/src/main/scala/org/hyperledger/identus/castor/core/model/did/Service.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.castor.core.model.did 2 | 3 | final case class Service( 4 | id: String, 5 | `type`: ServiceType, 6 | serviceEndpoint: ServiceEndpoint 7 | ) { 8 | 9 | def normalizeServiceEndpoint(): Service = copy(serviceEndpoint = serviceEndpoint.normalize()) 10 | 11 | } 12 | -------------------------------------------------------------------------------- /castor/src/main/scala/org/hyperledger/identus/castor/core/model/did/ServiceType.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.castor.core.model.did 2 | 3 | sealed trait ServiceType 4 | 5 | object ServiceType { 6 | 7 | opaque type Name = String 8 | 9 | object Name { 10 | def fromStringUnsafe(name: String): Name = name 11 | 12 | def fromString(name: String): Either[String, Name] = { 13 | val pattern = """^[A-Za-z0-9\-_]+(\s*[A-Za-z0-9\-_])*$""".r 14 | pattern 15 | .findFirstIn(name) 16 | .toRight( 17 | s"The service type '$name' is not a valid value." 18 | ) 19 | } 20 | } 21 | 22 | extension (name: Name) { 23 | def value: String = name 24 | } 25 | 26 | final case class Single(value: Name) extends ServiceType 27 | final case class Multiple(head: Name, tail: Seq[Name]) extends ServiceType { 28 | def values: Seq[Name] = head +: tail 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /castor/src/main/scala/org/hyperledger/identus/castor/core/model/did/VerificationRelationship.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.castor.core.model.did 2 | 3 | enum VerificationRelationship(val name: String) { 4 | case Authentication extends VerificationRelationship("authentication") 5 | case AssertionMethod extends VerificationRelationship("assertionMethod") 6 | case KeyAgreement extends VerificationRelationship("keyAgreement") 7 | case CapabilityInvocation extends VerificationRelationship("capabilityInvocation") 8 | case CapabilityDelegation extends VerificationRelationship("capabilityDelegation") 9 | } 10 | 11 | object VerificationRelationship { 12 | 13 | private val lookup = VerificationRelationship.values.map(i => i.name -> i).toMap 14 | 15 | def parseString(s: String): Option[VerificationRelationship] = lookup.get(s) 16 | 17 | } 18 | -------------------------------------------------------------------------------- /castor/src/main/scala/org/hyperledger/identus/castor/core/repository/DIDOperationRepository.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.castor.core.repository 2 | 3 | import org.hyperledger.identus.castor.core.model.did.PrismDID 4 | 5 | trait DIDOperationRepository[F[_]] { 6 | def getConfirmedPublishedDIDOperations(did: PrismDID): F[Unit] 7 | } 8 | -------------------------------------------------------------------------------- /castor/src/main/scala/org/hyperledger/identus/castor/core/util/Prelude.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.castor.core.util 2 | 3 | // consider moving this to shared library 4 | object Prelude { 5 | 6 | extension [T](xs: Seq[T]) { 7 | def isUnique: Boolean = xs.length == xs.distinct.length 8 | } 9 | 10 | } 11 | -------------------------------------------------------------------------------- /cloud-agent/client/.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | build/ 3 | !gradle/wrapper/gradle-wrapper.jar 4 | !**/src/main/**/build/ 5 | !**/src/test/**/build/ 6 | target 7 | node_modules/ 8 | 9 | ### IntelliJ IDEA ### 10 | .idea/modules.xml 11 | .idea/jarRepositories.xml 12 | .idea/compiler.xml 13 | .idea/libraries/ 14 | *.iws 15 | *.iml 16 | *.ipr 17 | out/ 18 | !**/src/main/**/out/ 19 | !**/src/test/**/out/ 20 | .idea 21 | 22 | ### Eclipse ### 23 | .apt_generated 24 | .classpath 25 | .factorypath 26 | .project 27 | .settings 28 | .springBeans 29 | .sts4-cache 30 | bin/ 31 | !**/src/main/**/bin/ 32 | !**/src/test/**/bin/ 33 | 34 | ### NetBeans ### 35 | /nbproject/private/ 36 | /nbbuild/ 37 | /dist/ 38 | /nbdist/ 39 | /.nb-gradle/ 40 | 41 | ### VS Code ### 42 | .vscode/ 43 | 44 | ### Mac OS ### 45 | .DS_Store -------------------------------------------------------------------------------- /cloud-agent/client/README.md: -------------------------------------------------------------------------------- 1 | # Cloud-agent client generator 2 | 3 | This project goal is to generate the models based on the OpenAPI Specification. 4 | 5 | ## Generating models 6 | 7 | Then run the generator scripts: 8 | 9 | ```bash 10 | cd generator 11 | yarn generate 12 | ``` 13 | 14 | To publish the clients: 15 | 16 | ```bash 17 | cd generator 18 | yarn publish:clients 19 | ``` 20 | 21 | ## Cloud-agent lifecycle 22 | 23 | `identus-client-generator` creates the clients after the `cloud-agent-v*` tag is created. 24 | 25 | ## Supported clients 26 | 27 | 1. Kotlin 28 | 2. Typescript 29 | 30 | ### Work in progress 31 | 32 | 1. Python 33 | 34 | # Caution note 35 | 36 | Some of the OAS3 schema types are not fully supported. 37 | 38 | The generated files that are not supported were fixed manually and ignored from the generation, in the `.openapi-generator-ignore` file, therefore it requires a diligence work to keep them updated. 39 | -------------------------------------------------------------------------------- /cloud-agent/client/generator/clean.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | git clean -dfx ../kotlin 5 | git clean -dfx ../python 6 | git clean -dfx ../typescript 7 | -------------------------------------------------------------------------------- /cloud-agent/client/generator/generate-clients.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | # generate kotlin models 5 | yarn openapi-generator-cli generate \ 6 | -g kotlin \ 7 | -i ../../service/api/http/cloud-agent-openapi-spec.yaml \ 8 | -o ../kotlin \ 9 | --ignore-file-override ../kotlin/.openapi-generator-ignore \ 10 | --additional-properties=packageName=org.hyperledger.identus.client,serializationLibrary=gson,enumPropertyNaming=UPPERCASE 11 | 12 | # generate typescript models 13 | yarn openapi-generator-cli generate \ 14 | -g typescript \ 15 | -i ../../service/api/http/cloud-agent-openapi-spec.yaml \ 16 | -o ../typescript \ 17 | --ignore-file-override ../typescript/.openapi-generator-ignore 18 | 19 | # generate python models 20 | # yarn openapi-generator-cli generate -g python -i oas.yml --skip-validate-spec -o ../python --ignore-file-override ../python/.openapi-generator-ignore 21 | -------------------------------------------------------------------------------- /cloud-agent/client/generator/openapitools.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@openapitools/openapi-generator-cli/config.schema.json", 3 | "spaces": 2, 4 | "generator-cli": { 5 | "version": "7.7.0" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /cloud-agent/client/generator/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cloud-agent-clients-generator", 3 | "version": "1.0.0", 4 | "description": "Generates the clients based on the OAS for many languages", 5 | "author": "Allain Magyar", 6 | "license": "Apache-2.0", 7 | "private": true, 8 | "type": "module", 9 | "scripts": { 10 | "generate": "npm-run-all clean:all generate:all", 11 | "generate:all": "./generate-clients.sh", 12 | "clean:all": "./clean.sh", 13 | "publish:clients": "./publish-clients.sh" 14 | }, 15 | "dependencies": { 16 | "@openapitools/openapi-generator-cli": "2.13.13", 17 | "npm-run-all": "^4.1.5" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /cloud-agent/client/kotlin/gradle.properties: -------------------------------------------------------------------------------- 1 | version=0.0.1-SNAPSHOT 2 | -------------------------------------------------------------------------------- /cloud-agent/client/kotlin/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperledger-identus/cloud-agent/96f97f680d80f11399770a65100e0a915bca41d8/cloud-agent/client/kotlin/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /cloud-agent/client/kotlin/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-all.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /cloud-agent/client/kotlin/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'cloud-agent-client' 2 | -------------------------------------------------------------------------------- /cloud-agent/client/python/.openapi-generator-ignore: -------------------------------------------------------------------------------- 1 | setup.py 2 | -------------------------------------------------------------------------------- /cloud-agent/client/typescript/.openapi-generator-ignore: -------------------------------------------------------------------------------- 1 | package.json 2 | docs 3 | 4 | # ignore broken files 5 | models/CredentialRequest.ts 6 | models/Proof2.ts 7 | models/Service.ts 8 | models/UpdateManagedDIDServiceAction.ts 9 | -------------------------------------------------------------------------------- /cloud-agent/service/server/src/main/scala/org/hyperledger/identus/agent/notification/WebhookPublisherError.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.agent.notification 2 | 3 | sealed trait WebhookPublisherError 4 | 5 | object WebhookPublisherError { 6 | case class InvalidWebhookURL(msg: String) extends WebhookPublisherError 7 | case class UnexpectedError(msg: String) extends WebhookPublisherError 8 | } 9 | -------------------------------------------------------------------------------- /cloud-agent/service/server/src/main/scala/org/hyperledger/identus/agent/server/DidCommHttpServer.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.agent.server 2 | 3 | import org.hyperledger.identus.agent.server.config.AppConfig 4 | import org.hyperledger.identus.agent.server.http.ZHttp4sBlazeServer 5 | import org.hyperledger.identus.didcomm.controller.DIDCommServerEndpoints 6 | import zio.* 7 | 8 | object DidCommHttpServer { 9 | 10 | def run = for { 11 | allEndpoints <- DIDCommServerEndpoints.all 12 | server <- ZHttp4sBlazeServer.make("didcomm") 13 | appConfig <- ZIO.service[AppConfig] 14 | didCommServicePort = appConfig.agent.didCommEndpoint.http.port 15 | _ <- ZIO.logInfo(s"Running DIDComm Server on port '$didCommServicePort''") 16 | _ <- server.start(allEndpoints, didCommServicePort).debug 17 | } yield () 18 | 19 | } 20 | -------------------------------------------------------------------------------- /cloud-agent/service/server/src/main/scala/org/hyperledger/identus/agent/server/DidCommHttpServerError.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.agent.server 2 | 3 | sealed trait DidCommHttpServerError 4 | 5 | object DidCommHttpServerError { 6 | case class InvalidContentTypeError(error: String) extends DidCommHttpServerError 7 | case class RequestBodyParsingError(error: String) extends DidCommHttpServerError 8 | case class DIDCommMessageParsingError(error: String) extends DidCommHttpServerError 9 | } 10 | -------------------------------------------------------------------------------- /cloud-agent/service/server/src/main/scala/org/hyperledger/identus/api/http/RequestContext.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.api.http 2 | 3 | import sttp.tapir.model.ServerRequest 4 | 5 | case class RequestContext(request: ServerRequest) 6 | -------------------------------------------------------------------------------- /cloud-agent/service/server/src/main/scala/org/hyperledger/identus/api/http/codec/CustomMediaTypes.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.api.http.codec 2 | 3 | import sttp.model.MediaType 4 | 5 | object CustomMediaTypes { 6 | 7 | val `application/did+ld+json`: MediaType = MediaType( 8 | mainType = "application", 9 | subType = "did+ld+json", 10 | ) 11 | 12 | val `application/ld+json;did-resolution`: MediaType = MediaType( 13 | mainType = "application", 14 | subType = "ld+json", 15 | otherParameters = Map("profile" -> "https://w3id.org/did-resolution") 16 | ) 17 | 18 | } 19 | -------------------------------------------------------------------------------- /cloud-agent/service/server/src/main/scala/org/hyperledger/identus/api/http/codec/DidCommIDCodec.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.api.http.codec 2 | 3 | import org.hyperledger.identus.pollux.core.model.DidCommID 4 | import sttp.tapir.* 5 | import sttp.tapir.Codec.PlainCodec 6 | import sttp.tapir.DecodeResult.* 7 | 8 | object DidCommIDCodec { 9 | given didCommIDCodec: PlainCodec[DidCommID] = 10 | Codec.string.mapDecode { s => 11 | if s.nonEmpty && s.length < 64 then Value(DidCommID(s)) 12 | else 13 | Error( 14 | "DidComId must be less then 64 characters long", 15 | new Throwable("DidComId must be less then 64 characters long") 16 | ) 17 | }(didCommID => didCommID.value) 18 | 19 | } 20 | -------------------------------------------------------------------------------- /cloud-agent/service/server/src/main/scala/org/hyperledger/identus/api/http/model/CollectionStats.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.api.http.model 2 | 3 | case class CollectionStats(totalCount: Long, filteredCount: Long) 4 | -------------------------------------------------------------------------------- /cloud-agent/service/server/src/main/scala/org/hyperledger/identus/api/http/model/Order.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.api.http.model 2 | 3 | import scala.annotation.unused 4 | 5 | case class Order(field: String, direction: Option[Order.Direction] = None) 6 | 7 | object Order { 8 | val DefaultDirection: Direction = Direction.Ascending 9 | val empty: Order = Order("") 10 | 11 | enum Direction(@unused kind: String): 12 | case Ascending extends Direction("asc") 13 | case Descending extends Direction("desc") 14 | } 15 | -------------------------------------------------------------------------------- /cloud-agent/service/server/src/main/scala/org/hyperledger/identus/api/http/package.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.api 2 | 3 | import sttp.tapir.Validator 4 | 5 | package object http { 6 | case class Annotation[E](description: String, example: E, validator: Validator[E] = Validator.pass[E]) 7 | 8 | val DIDRefRegex = """^did:(?[a-z0-9]+(:[a-z0-9]+)*)\:(?[^#?]*)$""" 9 | val DIDRegex = """^did:(?[a-z0-9]+(:[a-z0-9]+)*)\:(?[^#?]*)?(?\?[^#]*)?(?\#.*)?$""" 10 | val SemVerRegex = 11 | """^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$""" 12 | } 13 | -------------------------------------------------------------------------------- /cloud-agent/service/server/src/main/scala/org/hyperledger/identus/castor/controller/DIDServerEndpoints.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.castor.controller 2 | 3 | import org.hyperledger.identus.LogUtils.* 4 | import sttp.tapir.ztapir.* 5 | import zio.* 6 | 7 | class DIDServerEndpoints(didController: DIDController) { 8 | 9 | private val getDIDServerEndpoint: ZServerEndpoint[Any, Any] = 10 | DIDEndpoints.getDID.zServerLogic { case (ctx, didRef) => 11 | didController 12 | .getDID(didRef) 13 | .logTrace(ctx) 14 | } 15 | 16 | val all: List[ZServerEndpoint[Any, Any]] = List( 17 | getDIDServerEndpoint 18 | ) 19 | 20 | } 21 | 22 | object DIDServerEndpoints { 23 | def all: URIO[DIDController, List[ZServerEndpoint[Any, Any]]] = { 24 | for { 25 | didController <- ZIO.service[DIDController] 26 | didEndpoints = new DIDServerEndpoints(didController) 27 | } yield didEndpoints.all 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /cloud-agent/service/server/src/main/scala/org/hyperledger/identus/castor/controller/http/DIDInput.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.castor.controller.http 2 | 3 | import sttp.tapir.* 4 | 5 | object DIDInput { 6 | 7 | val didRefPathSegment = path[String]("didRef") 8 | .description( 9 | "Prism DID according to [the Prism DID method syntax](https://github.com/input-output-hk/prism-did-method-spec/blob/main/w3c-spec/PRISM-method.md#prism-did-method-syntax)" 10 | ) 11 | .example("did:prism:4a5b5cf0a513e83b598bbea25cd6196746747f361a73ef77068268bc9bd732ff") 12 | 13 | } 14 | -------------------------------------------------------------------------------- /cloud-agent/service/server/src/main/scala/org/hyperledger/identus/castor/controller/http/DIDResolutionResult.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.castor.controller.http 2 | 3 | import sttp.tapir.Schema 4 | import zio.json.{DeriveJsonDecoder, DeriveJsonEncoder, JsonDecoder, JsonEncoder} 5 | 6 | final case class DIDResolutionResult( 7 | `@context`: Context, 8 | didDocument: Option[DIDDocument] = None, 9 | didDocumentMetadata: DIDDocumentMetadata, 10 | didResolutionMetadata: DIDResolutionMetadata 11 | ) 12 | 13 | object DIDResolutionResult { 14 | given encoder: JsonEncoder[DIDResolutionResult] = DeriveJsonEncoder.gen[DIDResolutionResult] 15 | given decoder: JsonDecoder[DIDResolutionResult] = DeriveJsonDecoder.gen[DIDResolutionResult] 16 | given schema: Schema[DIDResolutionResult] = Schema.derived 17 | } 18 | -------------------------------------------------------------------------------- /cloud-agent/service/server/src/main/scala/org/hyperledger/identus/credentialstatus/controller/CredentialStatusController.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.credentialstatus.controller 2 | 3 | import org.hyperledger.identus.api.http.{ErrorResponse, RequestContext} 4 | import org.hyperledger.identus.credentialstatus.controller.http.StatusListCredential 5 | import org.hyperledger.identus.pollux.core.model.DidCommID 6 | import org.hyperledger.identus.shared.models.WalletAccessContext 7 | import zio.* 8 | 9 | import java.util.UUID 10 | 11 | trait CredentialStatusController { 12 | def getStatusListCredentialById(id: UUID)(implicit 13 | rc: RequestContext 14 | ): IO[ErrorResponse, StatusListCredential] 15 | 16 | def revokeCredentialById(id: DidCommID)(implicit 17 | rc: RequestContext 18 | ): ZIO[WalletAccessContext, ErrorResponse, Unit] 19 | 20 | } 21 | -------------------------------------------------------------------------------- /cloud-agent/service/server/src/main/scala/org/hyperledger/identus/didcomm/controller/DIDCommController.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.didcomm.controller 2 | 3 | import org.hyperledger.identus.api.http.{ErrorResponse, RequestContext} 4 | import org.hyperledger.identus.didcomm.controller.http.DIDCommMessage 5 | import zio.IO 6 | 7 | trait DIDCommController { 8 | def handleDIDCommMessage(msg: DIDCommMessage)(using rc: RequestContext): IO[ErrorResponse, Unit] 9 | } 10 | -------------------------------------------------------------------------------- /cloud-agent/service/server/src/main/scala/org/hyperledger/identus/didcomm/controller/DIDCommEndpoints.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.didcomm.controller 2 | 3 | import org.hyperledger.identus.api.http.{ErrorResponse, RequestContext} 4 | import org.hyperledger.identus.api.http.EndpointOutputs.{basicFailuresWith, FailureVariant} 5 | import org.hyperledger.identus.didcomm.controller.http.DIDCommMessage 6 | import sttp.tapir.* 7 | import sttp.tapir.json.zio.jsonBody 8 | 9 | object DIDCommEndpoints { 10 | val handleDIDCommMessage: PublicEndpoint[ 11 | (RequestContext, DIDCommMessage), 12 | ErrorResponse, 13 | Unit, 14 | Any 15 | ] = endpoint.post 16 | .in(extractFromRequest[RequestContext](RequestContext.apply)) 17 | .in(jsonBody[DIDCommMessage]) 18 | .in("") 19 | .out(emptyOutput) 20 | .errorOut(basicFailuresWith(FailureVariant.unprocessableEntity, FailureVariant.notFound)) 21 | } 22 | -------------------------------------------------------------------------------- /cloud-agent/service/server/src/main/scala/org/hyperledger/identus/didcomm/controller/http/DIDCommMessage.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.didcomm.controller.http 2 | 3 | import sttp.tapir.Schema 4 | import zio.json.{DeriveJsonDecoder, DeriveJsonEncoder, JsonDecoder, JsonEncoder} 5 | 6 | final case class DIDCommMessage( 7 | ciphertext: String, 8 | `protected`: String, 9 | recipients: List[Recipient], 10 | tag: String, 11 | iv: String 12 | ) 13 | 14 | object DIDCommMessage { 15 | given encoder: JsonEncoder[DIDCommMessage] = DeriveJsonEncoder.gen[DIDCommMessage] 16 | given decoder: JsonDecoder[DIDCommMessage] = DeriveJsonDecoder.gen[DIDCommMessage] 17 | given schema: Schema[DIDCommMessage] = Schema.derived 18 | } 19 | -------------------------------------------------------------------------------- /cloud-agent/service/server/src/main/scala/org/hyperledger/identus/didcomm/controller/http/Header.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.didcomm.controller.http 2 | 3 | import sttp.tapir.Schema 4 | import zio.json.{DeriveJsonDecoder, DeriveJsonEncoder, JsonDecoder, JsonEncoder} 5 | 6 | case class Header(kid: String) 7 | 8 | object Header { 9 | given encoder: JsonEncoder[Header] = DeriveJsonEncoder.gen[Header] 10 | given decoder: JsonDecoder[Header] = DeriveJsonDecoder.gen[Header] 11 | given schema: Schema[Header] = Schema.derived 12 | } 13 | -------------------------------------------------------------------------------- /cloud-agent/service/server/src/main/scala/org/hyperledger/identus/didcomm/controller/http/Recipient.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.didcomm.controller.http 2 | 3 | import sttp.tapir.Schema 4 | import zio.json.{DeriveJsonDecoder, DeriveJsonEncoder, JsonDecoder, JsonEncoder} 5 | 6 | case class Recipient(encrypted_key: String, header: Header) 7 | 8 | object Recipient { 9 | given encoder: JsonEncoder[Recipient] = DeriveJsonEncoder.gen[Recipient] 10 | given decoder: JsonDecoder[Recipient] = DeriveJsonDecoder.gen[Recipient] 11 | given schema: Schema[Recipient] = Schema.derived 12 | } 13 | -------------------------------------------------------------------------------- /cloud-agent/service/server/src/main/scala/org/hyperledger/identus/iam/authentication/AuthenticationConfig.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.iam.authentication 2 | 3 | import org.hyperledger.identus.iam.authentication.admin.AdminConfig 4 | import org.hyperledger.identus.iam.authentication.apikey.ApiKeyConfig 5 | import org.hyperledger.identus.iam.authentication.oidc.KeycloakConfig 6 | 7 | final case class AuthenticationConfig( 8 | admin: AdminConfig, 9 | apiKey: ApiKeyConfig, 10 | keycloak: KeycloakConfig 11 | ) { 12 | 13 | /** Return true if at least 1 authentication method is enabled (excluding admin auth method) */ 14 | def isEnabledAny: Boolean = apiKey.enabled || keycloak.enabled 15 | 16 | } 17 | -------------------------------------------------------------------------------- /cloud-agent/service/server/src/main/scala/org/hyperledger/identus/iam/authentication/admin/AdminApiKeyCredentials.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.iam.authentication.admin 2 | 3 | import org.hyperledger.identus.iam.authentication.{AuthenticationError, Credentials} 4 | import org.hyperledger.identus.shared.models.StatusCode 5 | 6 | case class AdminApiKeyAuthenticationError(message: String) 7 | extends AuthenticationError( 8 | StatusCode.Unauthorized, 9 | message 10 | ) 11 | 12 | object AdminApiKeyAuthenticationError { 13 | val invalidAdminApiKey = AdminApiKeyAuthenticationError("Invalid Admin API key in header `x-admin-api-key`") 14 | val emptyAdminApiKey = AdminApiKeyAuthenticationError("Empty `x-admin-api-key` header provided") 15 | } 16 | 17 | case class AdminApiKeyCredentials(apiKey: Option[String]) extends Credentials 18 | -------------------------------------------------------------------------------- /cloud-agent/service/server/src/main/scala/org/hyperledger/identus/iam/authentication/admin/AdminApiKeySecurityLogic.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.iam.authentication.admin 2 | 3 | import sttp.tapir.ztapir.* 4 | import sttp.tapir.EndpointIO 5 | import sttp.tapir.EndpointInput.Auth 6 | import sttp.tapir.EndpointInput.AuthType.ApiKey 7 | 8 | object AdminApiKeySecurityLogic { 9 | 10 | val adminApiKeyHeader: Auth[AdminApiKeyCredentials, ApiKey] = auth 11 | .apiKey( 12 | header[Option[String]]("x-admin-api-key") 13 | .mapTo[AdminApiKeyCredentials] 14 | .description("Admin API Key") 15 | ) 16 | .securitySchemeName("adminApiKeyAuth") 17 | 18 | } 19 | -------------------------------------------------------------------------------- /cloud-agent/service/server/src/main/scala/org/hyperledger/identus/iam/authentication/admin/AdminConfig.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.iam.authentication.admin 2 | 3 | import org.hyperledger.identus.agent.server.config.AppConfig 4 | import zio.{URLayer, ZLayer} 5 | 6 | final case class AdminConfig(token: String) 7 | 8 | //TODO: after moving the classes to separated package, derive the adminConfig from the authenticationConfig 9 | object AdminConfig { 10 | val layer: URLayer[AppConfig, AdminConfig] = ZLayer.fromFunction((conf: AppConfig) => conf.agent.authentication.admin) 11 | } 12 | -------------------------------------------------------------------------------- /cloud-agent/service/server/src/main/scala/org/hyperledger/identus/iam/authentication/apikey/ApiKeyConfig.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.iam.authentication.apikey 2 | 3 | import org.hyperledger.identus.agent.server.config.AppConfig 4 | import zio.* 5 | 6 | case class ApiKeyConfig(salt: String, enabled: Boolean, authenticateAsDefaultUser: Boolean, autoProvisioning: Boolean) 7 | 8 | object ApiKeyConfig { 9 | val layer: URLayer[AppConfig, ApiKeyConfig] = 10 | ZLayer.fromFunction((conf: AppConfig) => conf.agent.authentication.apiKey) 11 | } 12 | -------------------------------------------------------------------------------- /cloud-agent/service/server/src/main/scala/org/hyperledger/identus/iam/authentication/apikey/ApiKeyEndpointSecurityLogic.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.iam.authentication.apikey 2 | 3 | import sttp.tapir.ztapir.* 4 | import sttp.tapir.EndpointIO 5 | import sttp.tapir.EndpointInput.Auth 6 | import sttp.tapir.EndpointInput.AuthType.ApiKey 7 | 8 | object ApiKeyEndpointSecurityLogic { 9 | val apiKeyHeader: Auth[ApiKeyCredentials, ApiKey] = auth 10 | .apiKey( 11 | header[Option[String]]("apikey") 12 | .mapTo[ApiKeyCredentials] 13 | .description("API key") 14 | ) 15 | .securitySchemeName("apiKeyAuth") 16 | } 17 | -------------------------------------------------------------------------------- /cloud-agent/service/server/src/main/scala/org/hyperledger/identus/iam/authentication/apikey/package.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.iam.authentication 2 | 3 | import org.hyperledger.identus.shared.models.StatusCode 4 | 5 | package object apikey { 6 | case class ApiKeyCredentials(apiKey: Option[String]) extends Credentials 7 | 8 | case class ApiKeyAuthenticationError(message: String) 9 | extends AuthenticationError( 10 | StatusCode.Unauthorized, 11 | message 12 | ) 13 | 14 | object ApiKeyAuthenticationError { 15 | val invalidApiKey = ApiKeyAuthenticationError("Invalid `apikey` header provided") 16 | val emptyApiKey = ApiKeyAuthenticationError("Empty `apikey` header provided") 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /cloud-agent/service/server/src/main/scala/org/hyperledger/identus/iam/authentication/oidc/JwtCredentials.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.iam.authentication.oidc 2 | 3 | import org.hyperledger.identus.iam.authentication.{AuthenticationError, Credentials} 4 | import org.hyperledger.identus.shared.models.StatusCode 5 | 6 | final case class JwtCredentials(token: Option[String]) extends Credentials 7 | 8 | final case class JwtAuthenticationError(message: String) 9 | extends AuthenticationError( 10 | StatusCode.Unauthorized, 11 | message 12 | ) 13 | 14 | object JwtAuthenticationError { 15 | val emptyToken = JwtAuthenticationError("Empty bearer token header provided") 16 | } 17 | -------------------------------------------------------------------------------- /cloud-agent/service/server/src/main/scala/org/hyperledger/identus/iam/authentication/oidc/JwtSecurityLogic.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.iam.authentication.oidc 2 | 3 | import sttp.tapir.ztapir.* 4 | import sttp.tapir.EndpointInput.Auth 5 | import sttp.tapir.EndpointInput.AuthType.Http 6 | 7 | object JwtSecurityLogic { 8 | val jwtAuthHeader: Auth[JwtCredentials, Http] = auth 9 | .bearer[Option[String]]() 10 | .mapTo[JwtCredentials] 11 | .securitySchemeName("jwtAuth") 12 | } 13 | -------------------------------------------------------------------------------- /cloud-agent/service/server/src/main/scala/org/hyperledger/identus/iam/authentication/oidc/KeycloakConfig.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.iam.authentication.oidc 2 | 3 | import org.hyperledger.identus.agent.server.config.AppConfig 4 | import zio.* 5 | 6 | import java.net.URL 7 | 8 | final case class KeycloakConfig( 9 | enabled: Boolean, 10 | keycloakUrl: URL, 11 | realmName: String, 12 | clientId: String, 13 | clientSecret: String, 14 | autoUpgradeToRPT: Boolean, 15 | rolesClaimPath: String, 16 | ) { 17 | val rolesClaimPathSegments: Seq[String] = rolesClaimPath.split('.').toSeq 18 | } 19 | 20 | object KeycloakConfig { 21 | val layer: URLayer[AppConfig, KeycloakConfig] = 22 | ZLayer.fromFunction((conf: AppConfig) => conf.agent.authentication.keycloak) 23 | } 24 | -------------------------------------------------------------------------------- /cloud-agent/service/server/src/main/scala/org/hyperledger/identus/iam/authorization/core/PermissionManagement.scala: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /cloud-agent/service/server/src/main/scala/org/hyperledger/identus/iam/authorization/core/PermissionManagementService.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.iam.authorization.core 2 | 3 | import org.hyperledger.identus.agent.walletapi.model.BaseEntity 4 | import org.hyperledger.identus.shared.models.{WalletAdministrationContext, WalletId} 5 | import zio.* 6 | 7 | trait PermissionManagementService[E <: BaseEntity] { 8 | def grantWalletToUser( 9 | walletId: WalletId, 10 | entity: E 11 | ): ZIO[WalletAdministrationContext, PermissionManagementServiceError, Unit] 12 | def revokeWalletFromUser( 13 | walletId: WalletId, 14 | entity: E 15 | ): ZIO[WalletAdministrationContext, PermissionManagementServiceError, Unit] 16 | def listWalletPermissions( 17 | entity: E 18 | ): ZIO[WalletAdministrationContext, PermissionManagementServiceError, Seq[WalletId]] 19 | } 20 | -------------------------------------------------------------------------------- /cloud-agent/service/server/src/main/scala/org/hyperledger/identus/oid4vci/domain/IssuanceSession.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.oid4vci.domain 2 | 3 | import org.hyperledger.identus.castor.core.model.did.{DID, PrismDID} 4 | 5 | import java.util.UUID 6 | 7 | case class IssuanceSession( 8 | id: UUID, 9 | issuerId: UUID, 10 | nonce: String, 11 | issuerState: String, 12 | schemaId: Option[String], 13 | claims: zio.json.ast.Json, 14 | subjectDid: Option[DID], 15 | issuingDid: PrismDID, 16 | ) { 17 | def withSchemaId(schemaId: String): IssuanceSession = copy(schemaId = Some(schemaId)) 18 | def withSubjectDid(subjectDid: DID): IssuanceSession = copy(subjectDid = Some(subjectDid)) 19 | } 20 | -------------------------------------------------------------------------------- /cloud-agent/service/server/src/main/scala/org/hyperledger/identus/oid4vci/http/NonceRequest.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.oid4vci.http 2 | 3 | import sttp.tapir.Schema 4 | import zio.json.{DeriveJsonDecoder, DeriveJsonEncoder, JsonDecoder, JsonEncoder} 5 | 6 | case class NonceRequest(issuerState: String) 7 | 8 | object NonceRequest { 9 | given schema: Schema[NonceRequest] = Schema.derived 10 | given encoder: JsonEncoder[NonceRequest] = DeriveJsonEncoder.gen 11 | given decoder: JsonDecoder[NonceRequest] = DeriveJsonDecoder.gen 12 | } 13 | -------------------------------------------------------------------------------- /cloud-agent/service/server/src/main/scala/org/hyperledger/identus/oid4vci/http/NonceResponse.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.oid4vci.http 2 | 3 | import sttp.tapir.Schema 4 | import sttp.tapir.Schema.annotations.encodedName 5 | import zio.json.{DeriveJsonDecoder, DeriveJsonEncoder, JsonDecoder, JsonEncoder} 6 | 7 | case class NonceResponse( 8 | nonce: String, 9 | nonceExpiresIn: Long = 86400 10 | ) { 11 | require(nonce.nonEmpty, "nonce must not be empty") 12 | require(nonceExpiresIn > 0, "nonceExpiresIn must be greater than 0") 13 | } 14 | 15 | object NonceResponse { 16 | given schema: Schema[NonceResponse] = Schema.derived 17 | given encoder: JsonEncoder[NonceResponse] = DeriveJsonEncoder.gen 18 | given decoder: JsonDecoder[NonceResponse] = DeriveJsonDecoder.gen 19 | } 20 | -------------------------------------------------------------------------------- /cloud-agent/service/server/src/main/scala/org/hyperledger/identus/system/controller/SystemController.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.system.controller 2 | 3 | import org.hyperledger.identus.api.http.{ErrorResponse, RequestContext} 4 | import org.hyperledger.identus.system.controller.http.HealthInfo 5 | import zio.* 6 | 7 | trait SystemController { 8 | 9 | def health()(implicit rc: RequestContext): IO[ErrorResponse, HealthInfo] 10 | 11 | def metrics()(implicit rc: RequestContext): IO[ErrorResponse, String] 12 | 13 | } 14 | -------------------------------------------------------------------------------- /cloud-agent/service/server/src/main/scala/org/hyperledger/identus/verification/controller/VcVerificationController.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.verification.controller 2 | 3 | import org.hyperledger.identus.api.http.{ErrorResponse, RequestContext} 4 | import org.hyperledger.identus.pollux.core.service.verification.VcVerificationServiceError 5 | import org.hyperledger.identus.verification.controller 6 | import zio.* 7 | 8 | trait VcVerificationController { 9 | 10 | def verify(request: List[controller.http.VcVerificationRequest])(implicit 11 | rc: RequestContext 12 | ): IO[ErrorResponse, List[controller.http.VcVerificationResponse]] 13 | } 14 | 15 | object VcVerificationController { 16 | def toHttpError(error: VcVerificationServiceError): ErrorResponse = 17 | error match 18 | case VcVerificationServiceError.UnexpectedError(error) => 19 | ErrorResponse.badRequest(detail = Some(s"VC Verification Failed: $error")) 20 | 21 | } 22 | -------------------------------------------------------------------------------- /cloud-agent/service/server/src/test/resources/anoncred-schema-example.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Driving licence Anoncred Schema", 3 | "version": "1.0", 4 | "attrNames": [ 5 | "emailAddress", 6 | "familyName", 7 | "dateOfIssuance", 8 | "drivingLicenseID", 9 | "drivingClass" 10 | ], 11 | "issuerId": "http://www.example.com/issuer" 12 | } -------------------------------------------------------------------------------- /cloud-agent/service/server/src/test/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | [%level] %logger{15} - %message%n%rEx%xException{10} 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /cloud-agent/service/wallet-api/src/main/resources/sql/agent/V11__wallet_seed_digest.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE public.wallet 2 | ADD COLUMN "seed_digest" BYTEA; 3 | 4 | -- Fill the seed digest with a dummy value just to make it unique 5 | UPDATE public.wallet 6 | SET "seed_digest" = decode(replace("wallet_id"::text, '-', ''), 'hex') 7 | WHERE "seed_digest" IS NULL; 8 | 9 | ALTER TABLE public.wallet 10 | ALTER COLUMN "seed_digest" SET NOT NULL; 11 | 12 | ALTER TABLE public.wallet 13 | ADD CONSTRAINT wallet_seed_digest UNIQUE ("seed_digest"); 14 | -------------------------------------------------------------------------------- /cloud-agent/service/wallet-api/src/main/resources/sql/agent/V12__generic_secret.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE public.peer_did_rand_key DROP COLUMN "schema_id"; 2 | 3 | CREATE TABLE public.generic_secret ( 4 | "key" TEXT NOT NULL, 5 | "payload" TEXT NOT NULL, 6 | "created_at" TIMESTAMP WITH TIME ZONE NOT NULL, 7 | "wallet_id" UUID REFERENCES public.wallet ("wallet_id") NOT NULL, 8 | CONSTRAINT unique_key_wallet UNIQUE ("key", "wallet_id") 9 | ); 10 | 11 | ALTER TABLE public.generic_secret ENABLE ROW LEVEL SECURITY; 12 | 13 | CREATE POLICY generic_secret_wallet_isolation 14 | ON public.generic_secret 15 | USING (wallet_id = current_setting('app.current_wallet_id')::UUID); 16 | -------------------------------------------------------------------------------- /cloud-agent/service/wallet-api/src/main/resources/sql/agent/V13__apikey_authentication_improvements.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE public.authentication_method 2 | DROP COLUMN id; 3 | 4 | ALTER TABLE public.authentication_method 5 | ADD COLUMN created_at TIMESTAMPTZ NOT NULL DEFAULT now(); 6 | 7 | ALTER TABLE public.authentication_method 8 | ADD COLUMN deleted_at TIMESTAMPTZ DEFAULT NULL; 9 | 10 | ALTER TABLE public.authentication_method 11 | ADD CONSTRAINT unique_type_secret_constraint UNIQUE (type, secret); -------------------------------------------------------------------------------- /cloud-agent/service/wallet-api/src/main/resources/sql/agent/V15__add_did_index_table.sql: -------------------------------------------------------------------------------- 1 | -- Last used DID Index per wallet (solving race condition) 2 | CREATE TABLE public.last_did_index_per_wallet 3 | ( 4 | "wallet_id" UUID REFERENCES public.wallet ("wallet_id") NOT NULL PRIMARY KEY, 5 | "last_used_index" INT NOT NULL 6 | ); 7 | 8 | ALTER TABLE public.last_did_index_per_wallet 9 | ENABLE ROW LEVEL SECURITY; 10 | 11 | CREATE 12 | POLICY last_did_index_per_wallet_wallet_isolation 13 | ON public.last_did_index_per_wallet 14 | USING (wallet_id = current_setting('app.current_wallet_id')::UUID); 15 | 16 | INSERT INTO public.last_did_index_per_wallet(wallet_id, last_used_index) 17 | SELECT wallet_id, MAX(did_index) 18 | FROM public.prism_did_wallet_state 19 | GROUP BY wallet_id; -------------------------------------------------------------------------------- /cloud-agent/service/wallet-api/src/main/resources/sql/agent/V1__init_tables.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE public.did_secret_storage( 2 | "did" TEXT NOT NULL, 3 | "created_at" BIGINT NOT NULL, 4 | "updated_at" BIGINT, 5 | "key_id" TEXT NOT NULL, 6 | "key_pair" TEXT NOT NULL, 7 | PRIMARY KEY("did", "key_id") 8 | ); -------------------------------------------------------------------------------- /cloud-agent/service/wallet-api/src/main/resources/sql/agent/V2__did_nonsecret_storage.sql: -------------------------------------------------------------------------------- 1 | CREATE TYPE public.did_publication_status AS ENUM( 2 | 'CREATED', 3 | 'PUBLICATION_PENDING', 4 | 'PUBLISHED' 5 | ); 6 | 7 | CREATE TABLE public.did_publication_state( 8 | "did" TEXT NOT NULL PRIMARY KEY, 9 | "publication_status" did_publication_status NOT NULL, 10 | "atala_operation_content" BYTEA NOT NULL, 11 | "publish_operation_id" BYTEA 12 | ); 13 | -------------------------------------------------------------------------------- /cloud-agent/service/wallet-api/src/main/resources/sql/agent/V5__remove_did_rand_key.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE public.prism_did_secret_storage; 2 | 3 | DELETE FROM public.prism_did_update_lineage 4 | WHERE did in ( 5 | SELECT did 6 | FROM public.prism_did_wallet_state 7 | WHERE key_mode = 'RANDOM' 8 | ); 9 | 10 | DELETE FROM public.prism_did_wallet_state 11 | WHERE key_mode = 'RANDOM'; 12 | 13 | ALTER TABLE public.prism_did_wallet_state 14 | ALTER COLUMN "did_index" SET NOT NULL; 15 | -------------------------------------------------------------------------------- /cloud-agent/service/wallet-api/src/main/resources/sql/agent/V6__add_schema_id_to_secret_table.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE public.did_secret_storage 2 | ADD COLUMN "schema_id" VARCHAR(50) DEFAULT 'jwk' NOT NULL; -------------------------------------------------------------------------------- /cloud-agent/service/wallet-api/src/main/resources/sql/agent/V8__init_entity_repository_tables.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE public.entity 2 | ( 3 | id UUID PRIMARY KEY default gen_random_uuid(), 4 | name VARCHAR(128) NOT NULL, 5 | wallet_id UUID REFERENCES public.wallet ("wallet_id") NOT NULL, 6 | created_at TIMESTAMP WITH TIME ZONE NOT NULL, 7 | updated_at TIMESTAMP WITH TIME ZONE NOT NULL 8 | ); 9 | 10 | CREATE INDEX entity_wallet_id_index ON public.entity (wallet_id); 11 | CREATE INDEX entity_name_index ON public.entity (name); 12 | -------------------------------------------------------------------------------- /cloud-agent/service/wallet-api/src/main/resources/sql/agent/V9__init_authentication_repository_tables.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE public.authentication_method 2 | ( 3 | id UUID PRIMARY KEY default gen_random_uuid(), 4 | type VARCHAR(128) NOT NULL, 5 | entity_id UUID NOT NULL, 6 | secret VARCHAR(256) NOT NULL 7 | ); 8 | 9 | CREATE INDEX authentication_method_secret_idx ON public.authentication_method(secret); 10 | CREATE INDEX authentication_method_type_idx ON public.authentication_method(type); 11 | CREATE INDEX authentication_method_type_and_secret_idx ON public.authentication_method(type, secret); 12 | -------------------------------------------------------------------------------- /cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/model/PeerDIDRecord.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.agent.walletapi.model 2 | 3 | import org.hyperledger.identus.mercury.model.DidId 4 | import org.hyperledger.identus.shared.models.WalletId 5 | 6 | import java.time.Instant 7 | 8 | case class PeerDIDRecord(did: DidId, createdAt: Instant, walletId: WalletId) 9 | -------------------------------------------------------------------------------- /cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/model/error/CreateManagedDIDError.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.agent.walletapi.model.error 2 | 3 | import org.hyperledger.identus.castor.core.model.error.OperationValidationError 4 | import org.hyperledger.identus.castor.core.model.error as castor 5 | 6 | sealed trait CreateManagedDIDError extends Throwable 7 | 8 | object CreateManagedDIDError { 9 | final case class InvalidArgument(msg: String) extends CreateManagedDIDError 10 | final case class WalletStorageError(cause: Throwable) extends CreateManagedDIDError 11 | final case class InvalidOperation(cause: castor.OperationValidationError) extends CreateManagedDIDError 12 | } 13 | -------------------------------------------------------------------------------- /cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/model/error/DIDSecretStorageError.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.agent.walletapi.model.error 2 | 3 | import org.hyperledger.identus.mercury.model.DidId 4 | import org.hyperledger.identus.shared.models.* 5 | 6 | sealed trait DIDSecretStorageError( 7 | override val statusCode: StatusCode, 8 | override val userFacingMessage: String 9 | ) extends Failure { 10 | override val namespace: String = "DIDSecretStorageError" 11 | } 12 | 13 | object DIDSecretStorageError { 14 | case class KeyNotFoundError(didId: DidId, keyId: KeyId) 15 | extends DIDSecretStorageError( 16 | StatusCode.NotFound, 17 | s"The not found: keyId='$keyId', didId='$didId'" 18 | ) 19 | case class WalletNotFoundError(didId: DidId) 20 | extends DIDSecretStorageError( 21 | StatusCode.NotFound, 22 | s"The DID not Found in Wallet: didId='$didId'" 23 | ) 24 | } 25 | -------------------------------------------------------------------------------- /cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/model/error/EntityServiceError.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.agent.walletapi.model.error 2 | 3 | import org.hyperledger.identus.shared.models.{Failure, StatusCode} 4 | 5 | import java.util.UUID 6 | 7 | sealed trait EntityServiceError( 8 | val statusCode: StatusCode, 9 | val userFacingMessage: String 10 | ) extends Failure { 11 | override val namespace: String = "EntityServiceError" 12 | } 13 | 14 | object EntityServiceError { 15 | final case class EntityNotFound(id: UUID) 16 | extends EntityServiceError( 17 | StatusCode.NotFound, 18 | s"There is no entity matching the given identifier: id=$id" 19 | ) 20 | 21 | final case class WalletNotFound(walletId: UUID) 22 | extends EntityServiceError( 23 | StatusCode.NotFound, 24 | s"There is no wallet matching the given identifier: walletId:$walletId" 25 | ) 26 | } 27 | -------------------------------------------------------------------------------- /cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/model/error/GetManagedDIDError.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.agent.walletapi.model.error 2 | 3 | import org.hyperledger.identus.castor.core.model.error.DIDOperationError 4 | 5 | sealed trait GetManagedDIDError 6 | 7 | object GetManagedDIDError { 8 | final case class WalletStorageError(cause: Throwable) extends GetManagedDIDError // TODO override def toString 9 | final case class OperationError(cause: DIDOperationError) extends GetManagedDIDError 10 | } 11 | -------------------------------------------------------------------------------- /cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/model/error/PublishManagedDIDError.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.agent.walletapi.model.error 2 | 3 | import org.hyperledger.identus.castor.core.model.did.PrismDID 4 | import org.hyperledger.identus.castor.core.model.error.DIDOperationError 5 | 6 | sealed trait PublishManagedDIDError 7 | 8 | object PublishManagedDIDError { 9 | final case class DIDNotFound(did: PrismDID) extends PublishManagedDIDError 10 | final case class WalletStorageError(cause: Throwable) extends PublishManagedDIDError 11 | final case class OperationError(cause: DIDOperationError) extends PublishManagedDIDError 12 | final case class CryptographyError(cause: Throwable) extends PublishManagedDIDError 13 | } 14 | -------------------------------------------------------------------------------- /cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/service/EntityService.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.agent.walletapi.service 2 | 3 | import org.hyperledger.identus.agent.walletapi.model.error.EntityServiceError 4 | import org.hyperledger.identus.agent.walletapi.model.error.EntityServiceError.{EntityNotFound, WalletNotFound} 5 | import org.hyperledger.identus.agent.walletapi.model.Entity 6 | import zio.{IO, UIO} 7 | 8 | import java.util.UUID 9 | 10 | trait EntityService { 11 | def create(entity: Entity): IO[WalletNotFound, Entity] 12 | 13 | def getById(entityId: UUID): IO[EntityNotFound, Entity] 14 | 15 | def getAll(offset: Option[Int], limit: Option[Int]): UIO[Seq[Entity]] 16 | 17 | def deleteById(entityId: UUID): IO[EntityNotFound, Unit] 18 | 19 | def updateName(entityId: UUID, name: String): IO[EntityNotFound, Unit] 20 | 21 | def assignWallet(entityId: UUID, walletId: UUID): IO[EntityNotFound | WalletNotFound, Unit] 22 | } 23 | -------------------------------------------------------------------------------- /cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/sql/model/GenericSecret.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.agent.walletapi.sql.model 2 | 3 | import io.getquill.{SnakeCase, *} 4 | import io.getquill.context.json.PostgresJsonExtensions 5 | import io.getquill.doobie.DoobieContext 6 | import org.hyperledger.identus.shared.models.WalletId 7 | import zio.json.ast.Json 8 | 9 | import java.time.Instant 10 | 11 | final case class GenericSecret( 12 | key: String, 13 | payload: JsonValue[Json], 14 | createdAt: Instant, 15 | walletId: WalletId 16 | ) 17 | 18 | object GenericSecretSql extends DoobieContext.Postgres(SnakeCase), PostgresJsonExtensions { 19 | def insert(secret: GenericSecret) = run { 20 | quote( 21 | query[GenericSecret].insertValue(lift(secret)) 22 | ) 23 | } 24 | 25 | def findByKey(key: String) = run { 26 | quote( 27 | query[GenericSecret].filter(_.key == lift(key)).take(1) 28 | ) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/sql/model/package.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.agent.walletapi.sql 2 | 3 | import io.getquill.MappedEncoding 4 | import org.hyperledger.identus.shared.models.WalletId 5 | 6 | import java.net.{URI, URL} 7 | import java.util.UUID 8 | 9 | package object model { 10 | given MappedEncoding[WalletId, UUID] = MappedEncoding[WalletId, UUID](_.toUUID) 11 | given MappedEncoding[UUID, WalletId] = MappedEncoding[UUID, WalletId](WalletId.fromUUID) 12 | 13 | given MappedEncoding[URL, String] = MappedEncoding[URL, String](_.toString) 14 | given MappedEncoding[String, URL] = MappedEncoding[String, URL](URI(_).toURL) 15 | } 16 | -------------------------------------------------------------------------------- /cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/storage/GenericSecretStorage.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.agent.walletapi.storage 2 | 3 | import org.hyperledger.identus.shared.models.WalletAccessContext 4 | import zio.* 5 | import zio.json.ast.Json 6 | 7 | import scala.util.Try 8 | 9 | trait GenericSecretStorage { 10 | def set[K, V](key: K, secret: V)(implicit ev: GenericSecret[K, V]): RIO[WalletAccessContext, Unit] 11 | def get[K, V](key: K)(implicit ev: GenericSecret[K, V]): RIO[WalletAccessContext, Option[V]] 12 | } 13 | 14 | trait GenericSecret[K, V] { 15 | def keyPath(id: K): String 16 | def encodeValue(secret: V): Json 17 | def decodeValue(json: Json): Try[V] 18 | } 19 | -------------------------------------------------------------------------------- /cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/storage/WalletSecretStorage.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.agent.walletapi.storage 2 | 3 | import org.hyperledger.identus.agent.walletapi.model.WalletSeed 4 | import org.hyperledger.identus.shared.models.WalletAccessContext 5 | import zio.* 6 | 7 | trait WalletSecretStorage { 8 | def setWalletSeed(seed: WalletSeed): URIO[WalletAccessContext, Unit] 9 | def findWalletSeed: URIO[WalletAccessContext, Option[WalletSeed]] 10 | } 11 | -------------------------------------------------------------------------------- /cloud-agent/service/wallet-api/src/test/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | [%level] %logger{15} - %message%n%rEx%xException{10} 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /cloud-agent/service/wallet-api/src/test/scala/org/hyperledger/identus/test/container/VaultLayer.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.test.container 2 | 3 | import org.hyperledger.identus.sharedtest.containers.{VaultContainerCustom, VaultTestContainer} 4 | import zio.* 5 | 6 | object VaultLayer { 7 | 8 | def vaultLayer(vaultToken: String, useFileBackend: Boolean): TaskLayer[VaultContainerCustom] = { 9 | ZLayer 10 | .scoped { 11 | ZIO 12 | .acquireRelease(ZIO.attemptBlocking { 13 | VaultTestContainer.vaultContainer(vaultToken = Some(vaultToken), useFileBackend = useFileBackend) 14 | })(container => ZIO.attemptBlocking(container.stop()).orDie) 15 | // Start the container outside the aquireRelease as this might fail 16 | // to ensure contianer.stop() is added to the finalizer 17 | .tap(container => ZIO.attemptBlocking(container.start())) 18 | } 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /connect/README.md: -------------------------------------------------------------------------------- 1 | ## sbt project compiled with Scala 3 2 | 3 | ### Usage 4 | 5 | This is a normal sbt project. You can compile code with `sbt compile`, run it with `sbt run`, and `sbt console` will start a Scala 3 REPL. 6 | 7 | 8 | For more information on the sbt-dotty plugin, see the 9 | [scala3-example-project](https://github.com/scala/scala3-example-project/blob/main/README.md). 10 | -------------------------------------------------------------------------------- /connect/connect-protocol-state.md: -------------------------------------------------------------------------------- 1 | ```mermaid 2 | --- 3 | title: Inviter Connect State 4 | --- 5 | stateDiagram-v2 6 | [*] --> InvitationGenerated: generate and share new OOB invitation 7 | InvitationGenerated --> ConnectionRequestReceived: receive connection request 8 | ConnectionRequestReceived --> ConnectionResponsePending: accept connection request 9 | ConnectionResponsePending --> ConnectionResponseSent: send connection response (via DIDComm Agent) 10 | ConnectionResponseSent --> [*] 11 | ``` 12 | --- 13 | ```mermaid 14 | --- 15 | title: Invitee Connect State 16 | --- 17 | stateDiagram-v2 18 | [*] --> InvitationReceived: receive OOB invitation 19 | InvitationReceived --> ConnectionRequestPending: accept invitation 20 | ConnectionRequestPending --> ConnectionRequestSent: send connection request (via DIDComm Agent) 21 | ConnectionRequestSent --> ConnectionResponseReceived: receive connection response 22 | ConnectionResponseReceived --> [*] 23 | ``` -------------------------------------------------------------------------------- /connect/core/src/test/scala/org/hyperledger/identus/connect/core/repository/ConnectionRepositoryInMemorySpec.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.connect.core.repository 2 | 3 | import zio.* 4 | import zio.test.* 5 | 6 | object ConnectionRepositoryInMemorySpec extends ZIOSpecDefault { 7 | 8 | override def spec: Spec[TestEnvironment & Scope, Any] = 9 | suite("In Memory Connection Repository test suite")( 10 | ConnectionRepositorySpecSuite.testSuite, 11 | ConnectionRepositorySpecSuite.multitenantTestSuite 12 | ).provide( 13 | ConnectionRepositoryInMemory.layer 14 | ) 15 | 16 | // TODO: not good enough I want to test the SQL queries! 17 | 18 | } 19 | -------------------------------------------------------------------------------- /connect/sql-doobie/src/main/resources/sql/connect/V1__init_tables.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE public.connection_records( 2 | "id" VARCHAR(36) NOT NULL PRIMARY KEY, 3 | "created_at" TIMESTAMP WITH TIME ZONE NOT NULL, 4 | "updated_at" TIMESTAMP WITH TIME ZONE, 5 | "thid" VARCHAR(36), 6 | "label" VARCHAR(255), 7 | "role" VARCHAR(50) NOT NULL, 8 | "protocol_state" VARCHAR(50) NOT NULL, 9 | "invitation" TEXT NOT NULL, 10 | "connection_request" TEXT, 11 | "connection_response" TEXT 12 | ); -------------------------------------------------------------------------------- /connect/sql-doobie/src/main/resources/sql/connect/V2__add_thid_unique_constraint.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE public.connection_records 2 | ADD CONSTRAINT unique_thid UNIQUE (thid); -------------------------------------------------------------------------------- /connect/sql-doobie/src/main/resources/sql/connect/V3__add_meta_retries_and_meta_last_failure.sql: -------------------------------------------------------------------------------- 1 | -- Add the fields: meta_retries; meta_last_failure 2 | ALTER TABLE public.connection_records 3 | ADD meta_retries BIGINT NOT NULL, 4 | ADD meta_last_failure TEXT; -------------------------------------------------------------------------------- /connect/sql-doobie/src/main/resources/sql/connect/V4__create_protocol_state_index.sql: -------------------------------------------------------------------------------- 1 | CREATE INDEX protocol_state_idx 2 | ON public.connection_records (protocol_state); -------------------------------------------------------------------------------- /connect/sql-doobie/src/main/resources/sql/connect/V5__add_meta_next_retry.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE public.connection_records 2 | ADD meta_next_retry TIMESTAMP WITH TIME ZONE; 3 | -------------------------------------------------------------------------------- /connect/sql-doobie/src/main/resources/sql/connect/V6__add_rls_policy.sql: -------------------------------------------------------------------------------- 1 | -- Introduce breaking change given that we do not want to handle 2 | -- migration complexity and it's not used in production instance yet. 3 | DELETE 4 | FROM public.connection_records 5 | WHERE true; 6 | 7 | -- Introduce a concept of wallet 8 | ALTER TABLE public.connection_records 9 | ADD COLUMN "wallet_id" UUID NOT NULL; 10 | 11 | -- Alter unique constraint on 'pthid' 12 | ALTER TABLE public.connection_records 13 | DROP CONSTRAINT unique_thid; 14 | 15 | ALTER TABLE public.connection_records 16 | ADD CONSTRAINT connection_records_unique_thid_per_wallet UNIQUE (wallet_id, thid); 17 | 18 | -- Enforce RLS 19 | ALTER TABLE public.connection_records 20 | ENABLE ROW LEVEL SECURITY; 21 | 22 | CREATE POLICY connection_records_wallet_isolation 23 | ON public.connection_records 24 | USING (wallet_id = current_setting('app.current_wallet_id')::UUID); 25 | -------------------------------------------------------------------------------- /connect/sql-doobie/src/main/resources/sql/connect/V7__add_goal_and_goal_code.sql: -------------------------------------------------------------------------------- 1 | 2 | -- Introduce a goal and goal code for connection 3 | ALTER TABLE public.connection_records 4 | ADD COLUMN "goal_code" TEXT, 5 | ADD COLUMN "goal" TEXT; 6 | -------------------------------------------------------------------------------- /connect/sql-doobie/src/main/resources/sql/connect/V8__clear_content_of_meta_last_failure.sql: -------------------------------------------------------------------------------- 1 | -- Clear content of meta_last_failure 2 | UPDATE public.connection_records SET meta_last_failure=NULL; -------------------------------------------------------------------------------- /connect/sql-doobie/src/test/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | [%level] %logger{15} - %message%n%rEx%xException{10} 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /connect/sql-doobie/src/test/scala/org/hyperledger/identus/test/container/PostgresTestContainer.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.test.container 2 | 3 | import com.dimafeng.testcontainers.PostgreSQLContainer 4 | import org.hyperledger.identus.sharedtest.containers.PostgresTestContainer.postgresContainer 5 | import zio.* 6 | import zio.ZIO.* 7 | 8 | object PostgresLayer { 9 | 10 | def postgresLayer( 11 | imageName: Option[String] = Some("postgres"), 12 | verbose: Boolean = false 13 | ): ZLayer[Any, Nothing, PostgreSQLContainer] = 14 | ZLayer.scoped { 15 | acquireRelease(ZIO.attemptBlockingIO { 16 | val container = postgresContainer(imageName, verbose) 17 | container.start() 18 | container 19 | }.orDie)(container => attemptBlockingIO(container.stop()).orDie) 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /docs/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperledger-identus/cloud-agent/96f97f680d80f11399770a65100e0a915bca41d8/docs/.gitkeep -------------------------------------------------------------------------------- /docs/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | 3 | services: 4 | atala-structurizr-lite: 5 | image: atala-structurizr-lite 6 | ports: 7 | - "8080:8080" 8 | 9 | swagger-ui: 10 | image: swaggerapi/swagger-ui 11 | ports: 12 | - "8081:8080" 13 | volumes: 14 | - ../commons:/usr/share/nginx/html/commons 15 | environment: 16 | URLS: '[ 17 | { name: "Mob Sessions", url: "/commons/atala-openapi.yaml" } 18 | ]' 19 | -------------------------------------------------------------------------------- /docs/docusaurus/connections/connection-flow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperledger-identus/cloud-agent/96f97f680d80f11399770a65100e0a915bca41d8/docs/docusaurus/connections/connection-flow.png -------------------------------------------------------------------------------- /docs/docusaurus/credentialdefinition/delete.md: -------------------------------------------------------------------------------- 1 | # Delete the Credential Definition 2 | 3 | Unfortunately, once published (especially in the [Verifiable Data Registry (VDR)](/home/concepts/glossary#verifiable-data-registry), deleting the credential definition becomes unfeasible. 4 | 5 | In the Identus Platform, credential definitions aren't published to the VDR. This functionality will be incorporated in subsequent versions of the platform. Hence, the platform currently doesn't provide a REST API for deletion. 6 | 7 | If you need to `delete` the credential definition, it's advisable to contact the database administrator or directly remove it from the Postgres instance using its `guid`. 8 | 9 | For example: 10 | 11 | ```sql 12 | DELETE 13 | FROM credential_definition 14 | WHERE guid = '3f86a73f-5b78-39c7-af77-0c16123fa9c2' 15 | -------------------------------------------------------------------------------- /docs/docusaurus/credentials/connectionless/present-proof.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperledger-identus/cloud-agent/96f97f680d80f11399770a65100e0a915bca41d8/docs/docusaurus/credentials/connectionless/present-proof.md -------------------------------------------------------------------------------- /docs/docusaurus/credentials/didcomm/anoncreds-setup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperledger-identus/cloud-agent/96f97f680d80f11399770a65100e0a915bca41d8/docs/docusaurus/credentials/didcomm/anoncreds-setup.png -------------------------------------------------------------------------------- /docs/docusaurus/credentials/didcomm/issue-flow.anoncreds.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperledger-identus/cloud-agent/96f97f680d80f11399770a65100e0a915bca41d8/docs/docusaurus/credentials/didcomm/issue-flow.anoncreds.png -------------------------------------------------------------------------------- /docs/docusaurus/credentials/didcomm/issue-flow.jwt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperledger-identus/cloud-agent/96f97f680d80f11399770a65100e0a915bca41d8/docs/docusaurus/credentials/didcomm/issue-flow.jwt.png -------------------------------------------------------------------------------- /docs/docusaurus/credentials/didcomm/present-proof-flow.anoncreds.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperledger-identus/cloud-agent/96f97f680d80f11399770a65100e0a915bca41d8/docs/docusaurus/credentials/didcomm/present-proof-flow.anoncreds.png -------------------------------------------------------------------------------- /docs/docusaurus/credentials/didcomm/present-proof-flow.jwt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperledger-identus/cloud-agent/96f97f680d80f11399770a65100e0a915bca41d8/docs/docusaurus/credentials/didcomm/present-proof-flow.jwt.png -------------------------------------------------------------------------------- /docs/docusaurus/multitenancy/create_client_role.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperledger-identus/cloud-agent/96f97f680d80f11399770a65100e0a915bca41d8/docs/docusaurus/multitenancy/create_client_role.png -------------------------------------------------------------------------------- /docs/docusaurus/schemas/delete.md: -------------------------------------------------------------------------------- 1 | # Delete the credential schema 2 | 3 | Unfortunately, after publishing (especially in the [Verifiable Data Registry (VDR)](/home/concepts/glossary#verifiable-data-registry), deleting the credential schema is impossible. 4 | 5 | The Identus Platform doesn't publish the credential schema in the VDR. This capability will get implemented in the later version of the platform. That's why the platform does not expose the REST API for deletion. 6 | 7 | If you need to `delete` the credential schema, you can ask the database administrator or delete it from the 8 | Postgres instance by `guid`. 9 | 10 | For example: 11 | 12 | ```sql 13 | DELETE 14 | FROM credential_schema 15 | WHERE guid = '3f86a73f-5b78-39c7-af77-0c16123fa9c2' 16 | ``` 17 | -------------------------------------------------------------------------------- /docs/images/dco.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperledger-identus/cloud-agent/96f97f680d80f11399770a65100e0a915bca41d8/docs/images/dco.png -------------------------------------------------------------------------------- /docs/images/identus-architecture-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperledger-identus/cloud-agent/96f97f680d80f11399770a65100e0a915bca41d8/docs/images/identus-architecture-dark.png -------------------------------------------------------------------------------- /docs/images/identus-architecture-light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperledger-identus/cloud-agent/96f97f680d80f11399770a65100e0a915bca41d8/docs/images/identus-architecture-light.png -------------------------------------------------------------------------------- /docs/images/identus-cloud-agent-architecture-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperledger-identus/cloud-agent/96f97f680d80f11399770a65100e0a915bca41d8/docs/images/identus-cloud-agent-architecture-dark.png -------------------------------------------------------------------------------- /docs/images/identus-cloud-agent-architecture-light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperledger-identus/cloud-agent/96f97f680d80f11399770a65100e0a915bca41d8/docs/images/identus-cloud-agent-architecture-light.png -------------------------------------------------------------------------------- /docs/images/logos/identus-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperledger-identus/cloud-agent/96f97f680d80f11399770a65100e0a915bca41d8/docs/images/logos/identus-logo.png -------------------------------------------------------------------------------- /event-notification/src/main/scala/org/hyperledger/identus/event/notification/Event.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.event.notification 2 | 3 | import org.hyperledger.identus.shared.models.WalletId 4 | 5 | import java.time.Instant 6 | import java.util.UUID 7 | 8 | case class Event[A](`type`: String, id: UUID, ts: Instant, data: A, walletId: WalletId) 9 | 10 | object Event { 11 | def apply[A](`type`: String, data: A, walletId: WalletId): Event[A] = 12 | Event(`type`, UUID.randomUUID(), Instant.now(), data, walletId) 13 | } 14 | -------------------------------------------------------------------------------- /event-notification/src/main/scala/org/hyperledger/identus/event/notification/EventConsumer.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.event.notification 2 | 3 | import zio.IO 4 | 5 | trait EventConsumer[A]: 6 | def poll(count: Int): IO[EventNotificationServiceError, Seq[Event[A]]] 7 | -------------------------------------------------------------------------------- /event-notification/src/main/scala/org/hyperledger/identus/event/notification/EventNotificationService.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.event.notification 2 | 3 | import zio.IO 4 | 5 | trait EventNotificationService: 6 | def consumer[A](topic: String): IO[EventNotificationServiceError, EventConsumer[A]] 7 | def producer[A](topic: String): IO[EventNotificationServiceError, EventProducer[A]] 8 | -------------------------------------------------------------------------------- /event-notification/src/main/scala/org/hyperledger/identus/event/notification/EventNotificationServiceError.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.event.notification 2 | 3 | sealed trait EventNotificationServiceError 4 | 5 | object EventNotificationServiceError { 6 | case class EventSendingFailed(msg: String) extends EventNotificationServiceError 7 | } 8 | -------------------------------------------------------------------------------- /event-notification/src/main/scala/org/hyperledger/identus/event/notification/EventProducer.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.event.notification 2 | 3 | import zio.IO 4 | 5 | trait EventProducer[A]: 6 | def send(event: Event[A]): IO[EventNotificationServiceError, Unit] 7 | -------------------------------------------------------------------------------- /examples/.nickel/bootstrap.ncl: -------------------------------------------------------------------------------- 1 | let HurlBootstrapServiceArgs = { 2 | version | String, 3 | hurlDir | String, 4 | variables 5 | | { _ : String } 6 | | default 7 | = {} 8 | } 9 | in 10 | { 11 | makeHurlBootstrapService | HurlBootstrapServiceArgs -> _ 12 | = fun args => 13 | { 14 | image = "ghcr.io/orange-opensource/hurl:%{args.version}", 15 | volumes = ["%{args.hurlDir}:/hurl"], 16 | command = ["--glob", "/hurl/*.hurl", "--test"], 17 | environment = args.variables, 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /examples/.nickel/build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | find . -name "*.ncl" -print0 | xargs -0 -I _ nickel format _ 4 | 5 | nickel export ./root.ncl -f yaml --field st >../st/compose.yaml 6 | nickel export ./root.ncl -f yaml --field st-vault >../st-vault/compose.yaml 7 | nickel export ./root.ncl -f yaml --field st-multi >../st-multi/compose.yaml 8 | nickel export ./root.ncl -f yaml --field st-oid4vci >../st-oid4vci/compose.yaml 9 | 10 | nickel export ./root.ncl -f yaml --field mt >../mt/compose.yaml 11 | nickel export ./root.ncl -f yaml --field mt-keycloak >../mt-keycloak/compose.yaml 12 | nickel export ./root.ncl -f yaml --field mt-keycloak-vault >../mt-keycloak-vault/compose.yaml 13 | -------------------------------------------------------------------------------- /examples/.nickel/node.ncl: -------------------------------------------------------------------------------- 1 | let DbConfig = { 2 | host 3 | | String, 4 | port 5 | | Number 6 | | default 7 | = 5432, 8 | dbName 9 | | String, 10 | user 11 | | String, 12 | password 13 | | String, 14 | } 15 | in 16 | let NodeServiceArgs = { 17 | version 18 | | String, 19 | db 20 | | DbConfig, 21 | } 22 | in 23 | { 24 | makeNodeService | NodeServiceArgs -> _ 25 | = fun args => 26 | { 27 | image = "ghcr.io/input-output-hk/prism-node:%{args.version}", 28 | restart = "always", 29 | environment = { 30 | NODE_PSQL_HOST = "%{args.db.host}:%{std.to_string args.db.port}", 31 | NODE_PSQL_DATABASE = args.db.dbName, 32 | NODE_PSQL_USERNAME = args.db.user, 33 | NODE_PSQL_PASSWORD = args.db.password, 34 | }, 35 | depends_on = { 36 | "%{args.db.host}" = { 37 | condition = "service_healthy" 38 | } 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /examples/.nickel/vault.ncl: -------------------------------------------------------------------------------- 1 | let VaultServiceArgs = { 2 | version 3 | | String, 4 | hostPort 5 | | Number, 6 | rootToken 7 | | String 8 | | default 9 | = "admin" 10 | } 11 | in 12 | { 13 | makeVaultService | VaultServiceArgs -> _ 14 | = fun args => 15 | { 16 | image = "hashicorp/vault:%{args.version}", 17 | ports = ["%{std.to_string args.hostPort}:8200"], 18 | environment = { 19 | VAULT_ADDR = "http://0.0.0.0:8200", 20 | VAULT_DEV_ROOT_TOKEN_ID = args.rootToken 21 | }, 22 | cap_add = ["IPC_LOCK"], 23 | healthcheck = { 24 | test = ["CMD", "vault", "status"], 25 | interval = "10s", 26 | timeout = "5s", 27 | retries = "5", 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /examples/.nickel/versions.ncl: -------------------------------------------------------------------------------- 1 | { 2 | # identus 3 | agent = "1.38.0", 4 | node = "2.4.0", 5 | identusKeycloak = "0.2.0", 6 | # 3rd party 7 | caddy = "2.7.6-alpine", 8 | mockServer = "5.15.0", 9 | keycloak = "23.0.7", 10 | hurl = "4.2.0", 11 | postgres = "13", 12 | vault = "1.15.6", 13 | } 14 | -------------------------------------------------------------------------------- /examples/.shared/postgres/init-script.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | set -u 5 | 6 | function create_user_and_database() { 7 | local database=$1 8 | local app_user=${database}-application-user 9 | echo " Creating user and database '$database'" 10 | psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" <<-EOSQL 11 | CREATE USER "$app_user" WITH PASSWORD 'password'; 12 | CREATE DATABASE $database; 13 | \c $database 14 | ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO "$app_user"; 15 | EOSQL 16 | } 17 | 18 | if [ -n "$POSTGRES_MULTIPLE_DATABASES" ]; then 19 | echo "Multiple database creation requested: $POSTGRES_MULTIPLE_DATABASES" 20 | for db in $(echo "$POSTGRES_MULTIPLE_DATABASES" | tr ',' ' '); do 21 | create_user_and_database "$db" 22 | done 23 | echo "Multiple databases created" 24 | fi 25 | -------------------------------------------------------------------------------- /examples/.shared/postgres/max_conns.sql: -------------------------------------------------------------------------------- 1 | ALTER SYSTEM SET max_connections = 500; 2 | -------------------------------------------------------------------------------- /examples/mt-keycloak-vault/README.md: -------------------------------------------------------------------------------- 1 | ## Configuration 2 | 3 | | Exposed Service | Description | 4 | |---------------------------------|--------------------------| 5 | | `localhost:8080/cloudagent` | Multi-tenant Cloud Agent | 6 | | `localhost:8080/keycloak/admin` | Keycloak | 7 | | `localhost:8200` | Vault | 8 | 9 | __Keycloak__ 10 | 11 | - Admin user `admin` 12 | - Admin password `admin` 13 | 14 | __Vault__ 15 | 16 | - Root token `admin` 17 | -------------------------------------------------------------------------------- /examples/mt-keycloak-vault/hurl/local: -------------------------------------------------------------------------------- 1 | keycloak_admin_password=admin 2 | keycloak_admin_user=admin 3 | keycloak_base_url=http://localhost:8080/keycloak 4 | keycloak_realm=identus 5 | 6 | agent_url=http://localhost:8080 7 | 8 | issuer_password=1234 9 | issuer_username=alice 10 | 11 | holder_password=1234 12 | holder_username=bob 13 | 14 | verifier_password=1234 15 | verifier_username=john 16 | -------------------------------------------------------------------------------- /examples/mt-keycloak/README.md: -------------------------------------------------------------------------------- 1 | ## Configuration 2 | 3 | | Exposed Service | Description | 4 | |---------------------------------|--------------------------| 5 | | `localhost:8080/cloud-agent` | Multi-tenant Cloud Agent | 6 | | `localhost:8080/keycloak/admin` | Keycloak | 7 | 8 | __Keycloak__ 9 | 10 | - Admin user `admin` 11 | - Admin password `admin` 12 | -------------------------------------------------------------------------------- /examples/mt-keycloak/hurl/local: -------------------------------------------------------------------------------- 1 | keycloak_admin_password=admin 2 | keycloak_admin_user=admin 3 | keycloak_base_url=http://localhost:8080/keycloak 4 | keycloak_realm=identus 5 | 6 | agent_url=http://localhost:8080 7 | 8 | issuer_password=1234 9 | issuer_username=alice 10 | 11 | holder_password=1234 12 | holder_username=bob 13 | 14 | verifier_password=1234 15 | verifier_username=john 16 | -------------------------------------------------------------------------------- /examples/mt/README.md: -------------------------------------------------------------------------------- 1 | ## Configuration 2 | 3 | | Exposed Service | Description | 4 | |------------------------------|--------------------------| 5 | | `localhost:8080/cloud-agent` | Multi-tenant Cloud Agent | 6 | -------------------------------------------------------------------------------- /examples/st-multi/README.md: -------------------------------------------------------------------------------- 1 | ## Configuration 2 | 3 | | Exposed Service | Description | 4 | |------------------------------|----------------------------------------| 5 | | `localhost:8080/cloud-agent` | Single-tenant Cloud Agent#1 (issuer) | 6 | | `localhost:8081/cloud-agent` | Single-tenant Cloud Agent#2 (holder) | 7 | | `localhost:8082/cloud-agent` | Single-tenant Cloud Agent#3 (verifier) | 8 | -------------------------------------------------------------------------------- /examples/st-multi/hurl/local: -------------------------------------------------------------------------------- 1 | holder_url=http://localhost:8081 2 | issuer_url=http://localhost:8080 3 | verifier_url=http://localhost:8082 4 | -------------------------------------------------------------------------------- /examples/st-oid4vci/demo/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.12 2 | WORKDIR /workspace 3 | COPY requirements.txt /workspace/requirements.txt 4 | RUN pip install -r requirements.txt 5 | COPY . /workspace 6 | CMD ["python", "main.py"] 7 | -------------------------------------------------------------------------------- /examples/st-oid4vci/demo/requirements.txt: -------------------------------------------------------------------------------- 1 | certifi==2024.7.4 2 | cffi==1.16.0 3 | charset-normalizer==3.3.2 4 | cryptography==44.0.1 5 | idna==3.7 6 | pycparser==2.22 7 | PyJWT==2.8.0 8 | requests==2.32.3 9 | setuptools==78.1.1 10 | urllib3==2.2.2 11 | wheel==0.43.0 12 | -------------------------------------------------------------------------------- /examples/st-vault/README.md: -------------------------------------------------------------------------------- 1 | ## Configuration 2 | 3 | | Exposed Service | Description | 4 | |------------------------------|---------------------------| 5 | | `localhost:8080/cloud-agent` | Single-tenant Cloud Agent | 6 | | `localhost:8200` | Vault | 7 | 8 | __Vault__ 9 | 10 | - Root token `admin` 11 | -------------------------------------------------------------------------------- /examples/st/README.md: -------------------------------------------------------------------------------- 1 | ## Configuration 2 | 3 | | Exposed Service | Description | 4 | |------------------------------|---------------------------| 5 | | `localhost:8080/cloud-agent` | Single-tenant Cloud Agent | 6 | -------------------------------------------------------------------------------- /infrastructure/charts/agent/.helmignore: -------------------------------------------------------------------------------- 1 | # Patterns to ignore when building packages. 2 | # This supports shell glob matching, relative path matching, and 3 | # negation (prefixed with !). Only one pattern per line. 4 | .DS_Store 5 | # Common VCS dirs 6 | .git/ 7 | .gitignore 8 | .bzr/ 9 | .bzrignore 10 | .hg/ 11 | .hgignore 12 | .svn/ 13 | # Common backup files 14 | *.swp 15 | *.bak 16 | *.tmp 17 | *.orig 18 | *~ 19 | # Various IDEs 20 | .project 21 | .idea/ 22 | *.tmproj 23 | .vscode/ 24 | -------------------------------------------------------------------------------- /infrastructure/charts/agent/Chart.lock: -------------------------------------------------------------------------------- 1 | dependencies: 2 | - name: vault 3 | repository: https://helm.releases.hashicorp.com 4 | version: 0.24.1 5 | - name: keycloak 6 | repository: https://charts.bitnami.com/bitnami 7 | version: 17.2.0 8 | digest: sha256:33f82ebad234a60fd00365d1dcc6ed884beeac1c13ee4cbeca08a1478eded850 9 | generated: "2023-11-16T20:59:38.47688305+07:00" 10 | -------------------------------------------------------------------------------- /infrastructure/charts/agent/templates/apisixtls.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.ingress.enabled }} 2 | apiVersion: apisix.apache.org/v2 3 | kind: ApisixTls 4 | metadata: 5 | name: "{{ include "cloud-agent.name" . }}-base-path-tls" 6 | namespace: "{{ .Release.Namespace }}" 7 | labels: 8 | {{- include "labels.common" . | nindent 4}} 9 | spec: 10 | hosts: 11 | {{- range .Values.ingress.applicationUrls }} 12 | - {{ . }} 13 | {{- end }} 14 | secret: 15 | name: "{{ include "cloud-agent.name" . }}-base-path-secret" 16 | namespace: "{{ .Release.Namespace }}" 17 | {{- end }} 18 | -------------------------------------------------------------------------------- /infrastructure/charts/agent/templates/certificate.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.ingress.enabled }} 2 | apiVersion: cert-manager.io/v1 3 | kind: Certificate 4 | metadata: 5 | name: "{{ include "cloud-agent.name" . }}-base-path-cert" 6 | namespace: "{{ .Release.Namespace }}" 7 | labels: 8 | {{- include "labels.common" . | nindent 4}} 9 | annotations: 10 | argocd.argoproj.io/sync-wave: "-1" 11 | spec: 12 | secretName: "{{ include "cloud-agent.name" . }}-base-path-secret" 13 | duration: 2160h0m0s # 90d 14 | renewBefore: 360h0m0s # 15d 15 | issuerRef: 16 | name: letsencrypt 17 | kind: ClusterIssuer 18 | dnsNames: 19 | {{- range .Values.ingress.applicationUrls }} 20 | - {{ . }} 21 | {{- end }} 22 | {{- end }} 23 | -------------------------------------------------------------------------------- /infrastructure/charts/agent/templates/podmonitor-postgresql.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.database.postgres.metrics.enabled }} 2 | apiVersion: monitoring.coreos.com/v1 3 | kind: PodMonitor 4 | metadata: 5 | name: postgres-metrics 6 | namespace: {{ .Release.Namespace }} 7 | spec: 8 | podMetricsEndpoints: 9 | - path: /metrics 10 | port: exporter 11 | selector: 12 | matchLabels: 13 | application: spilo 14 | {{- end }} 15 | -------------------------------------------------------------------------------- /infrastructure/charts/agent/templates/stringsecret-agent-admin-token.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: "secretgenerator.mittwald.de/v1alpha1" 2 | kind: StringSecret 3 | metadata: 4 | name: "agent-admin-token" 5 | namespace: {{ .Release.Namespace }} 6 | labels: 7 | {{- include "labels.common" . | nindent 4 }} 8 | spec: 9 | forceRegenerate: false 10 | fields: 11 | - fieldName: "token" 12 | encoding: "base64" 13 | length: "32" 14 | -------------------------------------------------------------------------------- /infrastructure/charts/agent/templates/stringsecret-agent-api-key-salt.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: "secretgenerator.mittwald.de/v1alpha1" 2 | kind: StringSecret 3 | metadata: 4 | name: "agent-api-key-salt" 5 | namespace: {{ .Release.Namespace }} 6 | labels: 7 | {{- include "labels.common" . | nindent 4 }} 8 | spec: 9 | forceRegenerate: false 10 | fields: 11 | - fieldName: "salt" 12 | encoding: "base64" 13 | length: "16" 14 | -------------------------------------------------------------------------------- /infrastructure/charts/agent/templates/stringsecret-agent-keycloak-secret.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: "secretgenerator.mittwald.de/v1alpha1" 2 | kind: StringSecret 3 | metadata: 4 | name: "agent-keycloak-client-secret" 5 | namespace: {{ .Release.Namespace }} 6 | labels: 7 | {{- include "labels.common" . | nindent 4 }} 8 | spec: 9 | forceRegenerate: false 10 | fields: 11 | - fieldName: "secret" 12 | encoding: "base64" 13 | length: "16" 14 | 15 | --- 16 | 17 | apiVersion: "secretgenerator.mittwald.de/v1alpha1" 18 | kind: StringSecret 19 | metadata: 20 | name: "keycloak-admin-secret" 21 | namespace: {{ .Release.Namespace }} 22 | labels: 23 | {{- include "labels.common" . | nindent 4 }} 24 | spec: 25 | forceRegenerate: false 26 | fields: 27 | - fieldName: "password" 28 | encoding: "base64" 29 | length: "32" 30 | - fieldName: "postgres-password" 31 | encoding: "base64" 32 | length: "32" 33 | -------------------------------------------------------------------------------- /infrastructure/charts/agent/templates/stringsecret-agent-wallet-seed.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: "secretgenerator.mittwald.de/v1alpha1" 2 | kind: StringSecret 3 | metadata: 4 | name: "agent-wallet-seed" 5 | namespace: {{ .Release.Namespace }} 6 | labels: 7 | {{- include "labels.common" . | nindent 4 }} 8 | spec: 9 | forceRegenerate: false 10 | fields: 11 | - fieldName: "seed" 12 | encoding: "hex" 13 | length: "128" 14 | -------------------------------------------------------------------------------- /infrastructure/charts/agent/templates/stringsecret.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.ingress.enabled }} 2 | {{- $root := . -}} 3 | {{- range $consumer := .Values.ingress.auth.consumers }} 4 | apiVersion: "secretgenerator.mittwald.de/v1alpha1" 5 | kind: StringSecret 6 | metadata: 7 | name: "{{ $root.Release.Namespace }}-{{ $consumer | lower }}" 8 | namespace: {{ $root.Release.Namespace }} 9 | labels: 10 | {{- include "labels.common" $root | nindent 4 }} 11 | spec: 12 | forceRegenerate: false 13 | data: 14 | username: {{ $consumer | lower }} 15 | fields: 16 | - fieldName: "key" 17 | encoding: "base64" 18 | length: "32" 19 | --- 20 | {{- end }} 21 | {{- end }} 22 | -------------------------------------------------------------------------------- /infrastructure/dev/build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd) 6 | 7 | REPO_HOME="${SCRIPT_DIR}/../.." 8 | 9 | echo "--------------------------------------" 10 | echo "Building service docker images" 11 | echo "--------------------------------------" 12 | 13 | cd ${REPO_HOME} 14 | sbt "clean; docker:publishLocal" 15 | -------------------------------------------------------------------------------- /infrastructure/dev/clean.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd) 6 | 7 | # Set working directory 8 | cd ${SCRIPT_DIR} 9 | cd ../../ 10 | sbt "clean;cleanFiles" 11 | -------------------------------------------------------------------------------- /infrastructure/dev/full.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) 6 | 7 | # Set working directory 8 | cd ${SCRIPT_DIR} 9 | 10 | ./build.sh 11 | ./run.sh 12 | -------------------------------------------------------------------------------- /infrastructure/dev/get-versions.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd) 4 | 5 | # Set working directory 6 | cd ${SCRIPT_DIR} 7 | 8 | export AGENT_VERSION=$(cd ../../ && sbt "project agent" -Dsbt.supershell=false -error "print version") 9 | echo "prism-agent server version: ${AGENT_VERSION}" 10 | 11 | export PRISM_NODE_VERSION=v2.1.1 12 | echo "prism node version: ${PRISM_NODE_VERSION}" 13 | -------------------------------------------------------------------------------- /infrastructure/local/.env: -------------------------------------------------------------------------------- 1 | AGENT_VERSION=2.0.0 2 | PRISM_NODE_VERSION=2.5.0 3 | VAULT_DEV_ROOT_TOKEN_ID=root 4 | -------------------------------------------------------------------------------- /infrastructure/local/update_env.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) 4 | ENV_FILE="${SCRIPT_DIR}/.env" 5 | 6 | pip install ${SCRIPT_DIR}/../utils/python/github-helpers > /dev/null 2>&1 7 | 8 | AGENT_VERSION=$(github get-latest-package-version --package prism-agent --package-type container) 9 | 10 | sed -i.bak "s/AGENT_VERSION=.*/AGENT_VERSION=${AGENT_VERSION}/" ${ENV_FILE} && rm -f ${ENV_FILE}.bak 11 | -------------------------------------------------------------------------------- /infrastructure/multi/.env: -------------------------------------------------------------------------------- 1 | MERCURY_MEDIATOR_VERSION=0.2.0 2 | AGENT_VERSION=0.6.0 3 | -------------------------------------------------------------------------------- /infrastructure/multi/run-e2e-tests-remote.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd) 6 | 7 | echo "--------------------------------------" 8 | echo "Run e2e tests" 9 | echo "--------------------------------------" 10 | 11 | export ACME_AGENT_URL=https://agent-df56h.atalaprism.io/cloud-agent 12 | export BOB_AGENT_URL=https://agent-kj46b.atalaprism.io/cloud-agent 13 | export MALLORY_AGENT_URL=https://agent-sd98k.atalaprism.io/cloud-agent 14 | 15 | ( 16 | cd "${SCRIPT_DIR}"/../../tests/e2e-tests/ 17 | AGENT_AUTH_REQUIRED=true ./gradlew test reports 18 | ) 19 | -------------------------------------------------------------------------------- /infrastructure/multi/run.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) 6 | 7 | # Set working directory 8 | cd ${SCRIPT_DIR} 9 | 10 | echo "--------------------------------------" 11 | echo "Starting issuer using local/run.sh" 12 | echo "--------------------------------------" 13 | 14 | ../local/run.sh -p 8080 -n issuer -b 15 | 16 | echo "--------------------------------------" 17 | echo "Starting holder using local/run.sh" 18 | echo "--------------------------------------" 19 | 20 | ../local/run.sh -p 8090 -n holder -b 21 | 22 | echo "--------------------------------------" 23 | echo "Starting verifier using local/run.sh" 24 | echo "--------------------------------------" 25 | 26 | ../local/run.sh -p 9000 -n verifier -b 27 | -------------------------------------------------------------------------------- /infrastructure/shared/postgres/max_conns.sql: -------------------------------------------------------------------------------- 1 | ALTER SYSTEM SET max_connections = 500; 2 | -------------------------------------------------------------------------------- /infrastructure/single-tenant-testing-stack/.env: -------------------------------------------------------------------------------- 1 | AGENT_VERSION=1.25.0 2 | PRISM_NODE_VERSION=2.5.0 3 | VAULT_DEV_ROOT_TOKEN_ID=root 4 | -------------------------------------------------------------------------------- /infrastructure/single-tenant-testing-stack/postgres/init-script.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | set -u 5 | 6 | function create_user_and_database() { 7 | local database=$1 8 | local app_user=${database}-application-user 9 | echo " Creating user and database '$database'" 10 | psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" <<-EOSQL 11 | CREATE USER "$app_user" WITH PASSWORD 'password'; 12 | CREATE DATABASE $database; 13 | \c $database 14 | ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO "$app_user"; 15 | EOSQL 16 | } 17 | 18 | if [ -n "$POSTGRES_MULTIPLE_DATABASES" ]; then 19 | echo "Multiple database creation requested: $POSTGRES_MULTIPLE_DATABASES" 20 | for db in $(echo $POSTGRES_MULTIPLE_DATABASES | tr ',' ' '); do 21 | create_user_and_database $db 22 | done 23 | echo "Multiple databases created" 24 | fi 25 | -------------------------------------------------------------------------------- /infrastructure/single-tenant-testing-stack/postgres/max_conns.sql: -------------------------------------------------------------------------------- 1 | ALTER SYSTEM SET max_connections = 500; 2 | -------------------------------------------------------------------------------- /infrastructure/utils/python/github-helpers/.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | *.egg-info/ 3 | .env-e 4 | -------------------------------------------------------------------------------- /infrastructure/utils/python/github-helpers/github_helpers/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperledger-identus/cloud-agent/96f97f680d80f11399770a65100e0a915bca41d8/infrastructure/utils/python/github-helpers/github_helpers/__init__.py -------------------------------------------------------------------------------- /infrastructure/utils/python/github-helpers/setup.py: -------------------------------------------------------------------------------- 1 | """Setup script for GitHub Helpers""" 2 | 3 | from setuptools import find_packages, setup 4 | 5 | setup( 6 | name="github-helpers", 7 | version="0.1", 8 | description="GitHub API Python helpers for QA needs.", 9 | author="Baliasnikov Anton", 10 | author_email="anton.baliasnikov@iohk.io", 11 | packages=find_packages(), 12 | entry_points={ 13 | "console_scripts": ["github=github_helpers.cli:cli"], 14 | }, 15 | install_requires=[ 16 | "Click==8.1.3", 17 | "requests==2.32.0", 18 | "pylint==2.10.2", 19 | "pytest==6.2.4", 20 | "pytest-cov==2.12.1", 21 | ], 22 | ) 23 | -------------------------------------------------------------------------------- /mercury/agent/src/main/scala/org/hyperledger/identus/mercury/HttpClient.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.mercury 2 | 3 | import zio.* 4 | 5 | opaque type Header = (String, String) 6 | object Header: 7 | def apply(key: String, value: String): Header = (key, value) 8 | def apply(tuple: (String, String)): Header = tuple 9 | extension (header: Header) 10 | def key: String = header._1 11 | def value: String = header._2 12 | 13 | case class HttpResponse(status: Int, headers: Seq[Header], bodyAsString: String) 14 | 15 | trait HttpClient { 16 | def get(url: String): Task[HttpResponse] 17 | def postDIDComm(url: String, data: String): Task[HttpResponse] 18 | } 19 | 20 | object HttpClient { 21 | def get(url: String): RIO[HttpClient, HttpResponse] = 22 | ZIO.serviceWithZIO(_.get(url)) 23 | def postDIDComm(url: String, data: String): RIO[HttpClient, HttpResponse] = 24 | ZIO.serviceWithZIO(_.postDIDComm(url, data)) 25 | } 26 | -------------------------------------------------------------------------------- /mercury/agent/src/main/scala/org/hyperledger/identus/mercury/OutOfBandLoginPrograms.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.mercury 2 | 3 | import org.hyperledger.identus.mercury.model.* 4 | import org.hyperledger.identus.mercury.protocol.outofbandlogin.* 5 | 6 | object OutOfBandLoginPrograms { 7 | 8 | def generateLoginInvitation(did: DidId) = { 9 | val invitation = OutOfBandLoginInvitation(from = did) 10 | Message( 11 | `type` = invitation.`type`, 12 | from = Some(invitation.from), 13 | to = Seq.empty, 14 | id = invitation.id, 15 | ) 16 | } 17 | 18 | // def replyToLoginInvitation(replier: DidId, invitation: Invitation) = { 19 | // val requestMediation = MediateRequest() 20 | // Message( 21 | // from = replier, 22 | // to = DidId(invitation.from), 23 | // id = requestMediation.id, 24 | // piuri = requestMediation.`type` 25 | // ) 26 | // } 27 | } 28 | -------------------------------------------------------------------------------- /mercury/models/src/main/scala/org/hyperledger/identus/mercury/DidAgent.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.mercury 2 | 3 | import com.nimbusds.jose.jwk.* 4 | import org.hyperledger.identus.mercury.model.DidId 5 | 6 | /** Represente a Decentralized Identifier with secrets keys */ 7 | trait DidAgent { 8 | def id: DidId 9 | def jwkForKeyAgreement: Seq[OctetKeyPair] 10 | def jwkForKeyAuthentication: Seq[OctetKeyPair] 11 | } 12 | -------------------------------------------------------------------------------- /mercury/models/src/main/scala/org/hyperledger/identus/mercury/MediaTypes.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.mercury 2 | 3 | object MediaTypes { 4 | val contentTypePlain = "application/didcomm-plain+json" 5 | val contentTypeSigned = "application/didcomm-signed+json" 6 | val contentTypeEncrypted = "application/didcomm-encrypted+json" 7 | } 8 | -------------------------------------------------------------------------------- /mercury/models/src/main/scala/org/hyperledger/identus/mercury/model/DidId.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.mercury.model 2 | 3 | import zio.json.{JsonDecoder, JsonEncoder} 4 | 5 | final case class DidId(value: String) 6 | object DidId { 7 | given encoder: JsonEncoder[DidId] = JsonEncoder[String].contramap(_.value) 8 | given decoder: JsonDecoder[DidId] = JsonDecoder[String].map(str => DidId(str)) 9 | } 10 | -------------------------------------------------------------------------------- /mercury/models/src/main/scala/org/hyperledger/identus/mercury/model/EncryptedMessage.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.mercury.model 2 | 3 | import zio.json.ast.Json 4 | import zio.json.DecoderOps 5 | 6 | import java.util.Base64 7 | 8 | trait EncryptedMessage { // (private val msg: PackEncryptedResult) { 9 | def string: String // = msg.getPackedMessage 10 | def base64: String = Base64.getUrlEncoder.encodeToString(string.getBytes) 11 | def asJson: Json.Obj = { 12 | string 13 | .fromJson[Json] 14 | .flatMap(o => 15 | o.asObject match 16 | case None => Left(RuntimeException(s"Expecting Json Object got '$o'")) 17 | case Some(value) => Right(value) 18 | ) 19 | .getOrElse(UnexpectedCodeExecutionPath) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /mercury/models/src/main/scala/org/hyperledger/identus/mercury/model/SignedMesage.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.mercury.model 2 | 3 | import java.util.Base64 4 | 5 | trait SignedMesage { 6 | def string: String 7 | def base64: String = Base64.getUrlEncoder.encodeToString(string.getBytes) 8 | } 9 | -------------------------------------------------------------------------------- /mercury/models/src/main/scala/org/hyperledger/identus/mercury/model/UnpackResult.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.mercury.model 2 | 3 | trait UnpackMessage { 4 | def message: Message 5 | } 6 | -------------------------------------------------------------------------------- /mercury/models/src/main/scala/org/hyperledger/identus/mercury/model/error/package.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.mercury.model 2 | 3 | import org.hyperledger.identus.shared.models.* 4 | 5 | package object error { 6 | 7 | sealed trait MercuryError extends Failure { 8 | override val namespace: String = "MercuryError" 9 | } 10 | 11 | sealed case class SendMessageError(cause: Throwable, mData: Option[String] = None) extends MercuryError { 12 | override val statusCode = StatusCode.BadRequest 13 | override val userFacingMessage = 14 | s"Error when sending message: ${cause.getMessage};${mData.map(e => s" DATA:'$e'").getOrElse("")}. " 15 | + cause.getMessage 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /mercury/protocol-did-exchange/src/main/scala/org/hyperledger/identus/mercury/protocol/didexchange/v1/DidExchangeRequest.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.mercury.protocol.didexchange.v1 2 | 3 | import org.hyperledger.identus.mercury.model.{AttachmentDescriptor, PIURI} 4 | 5 | final case class Thread(thid: String, pthid: String) 6 | 7 | final case class DidExchangeRequest( 8 | `@id`: String, 9 | `@type`: PIURI, 10 | `~thread`: Thread, 11 | label: String, 12 | goal_code: String, 13 | goal: String, 14 | `did_doc~attach`: Option[AttachmentDescriptor] 15 | ) 16 | -------------------------------------------------------------------------------- /mercury/protocol-invitation/src/main/scala/org/hyperledger/identus/mercury/protocol/invitation/package.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.mercury.protocol 2 | 3 | package object invitation { 4 | 5 | /** provides new msg id 6 | * @return 7 | */ 8 | def getNewMsgId: String = java.util.UUID.randomUUID().toString 9 | } 10 | -------------------------------------------------------------------------------- /mercury/protocol-present-proof/src/main/scala/org/hyperledger/identus/mercury/protocol/presentproof/ProofType.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.mercury.protocol.presentproof 2 | 3 | import org.hyperledger.identus.mercury.model.DidId 4 | import zio.json.{DeriveJsonDecoder, DeriveJsonEncoder, JsonDecoder, JsonEncoder} 5 | 6 | case class ProofType( 7 | schema: String, // Schema ID EX: https://schema.org/Person 8 | requiredFields: Option[Seq[String]], // ["email"] 9 | trustIssuers: Option[Seq[DidId]] // ["did:prism:123321123"] 10 | ) 11 | object ProofType { 12 | given JsonEncoder[ProofType] = DeriveJsonEncoder.gen 13 | given JsonDecoder[ProofType] = DeriveJsonDecoder.gen 14 | } 15 | -------------------------------------------------------------------------------- /mercury/vc/src/main/scala/io/iohk/atala/mercury/vc/anoncreds/CredentialFilterFormat.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.vc.anoncreds 2 | 3 | import org.hyperledger.identus.mercury.protocol.issuecredential.IssueCredentialProposeFormat 4 | 5 | /** @see 6 | * https://github.com/hyperledger/aries-rfcs/blob/main/features/0771-anoncreds-attachments/README.md#credential-filter-format 7 | */ 8 | final case class CredentialFilterFormat( 9 | schema_issuer_id: Option[String], 10 | schema_name: Option[String], 11 | schema_version: Option[String], 12 | schema_id: Option[String], 13 | issuer_id: Option[String], 14 | cred_def_id: Option[String], 15 | ) 16 | 17 | object CredentialFilterFormat { 18 | // anoncreds/credential-filter@v1.0 19 | def format = IssueCredentialProposeFormat.Anoncred 20 | } 21 | -------------------------------------------------------------------------------- /mercury/vc/src/main/scala/io/iohk/atala/mercury/vc/anoncreds/CredentialFormat.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.vc.anoncreds 2 | 3 | import org.hyperledger.identus.mercury.protocol.issuecredential.IssueCredentialIssuedFormat 4 | 5 | /** @see 6 | * https://github.com/hyperledger/aries-rfcs/blob/main/features/0771-anoncreds-attachments/README.md#credential-format 7 | */ 8 | final case class CredentialFormat( 9 | schema_id: String, 10 | cred_def_id: String, 11 | rev_reg_id: String, 12 | values: Seq[Attr], 13 | // Fields below can depend on Cred Def type 14 | signature: String, 15 | signature_correctness_proof: String, 16 | rev_reg: String, 17 | witness: String, 18 | ) 19 | 20 | object CredentialFormat { 21 | // anoncreds/credential@v1.0 22 | def format = IssueCredentialIssuedFormat.Anoncred 23 | } 24 | 25 | final case class Attr(raw: String, encoded: String) 26 | -------------------------------------------------------------------------------- /mercury/vc/src/main/scala/io/iohk/atala/mercury/vc/anoncreds/CredentialRequestFormat.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.vc.anoncreds 2 | 3 | import org.hyperledger.identus.mercury.protocol.issuecredential.IssueCredentialRequestFormat 4 | 5 | /** https://github.com/hyperledger/aries-rfcs/blob/main/features/0771-anoncreds-attachments/README.md#credential-request-format 6 | */ 7 | final case class CredentialRequestFormat( 8 | entropy: String, 9 | cred_def_id: String, 10 | // Fields below can depend on Cred Def type 11 | blinded_ms: String, 12 | blinded_ms_correctness_proof: String, 13 | nonce: String, 14 | ) 15 | 16 | object CredentialRequestFormat { 17 | // anoncreds/credential-request@v1.0 18 | def format = IssueCredentialRequestFormat.Anoncred 19 | } 20 | -------------------------------------------------------------------------------- /mercury/vc/src/main/scala/io/iohk/atala/mercury/vc/anoncreds/ProofFormat.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.vc.anoncreds 2 | 3 | import org.hyperledger.identus.mercury.protocol.issuecredential.IssueCredentialRequestFormat 4 | 5 | type TODO = Any 6 | 7 | /** @see 8 | * https://github.com/hyperledger/aries-rfcs/blob/main/features/0771-anoncreds-attachments/README.md#proof-format 9 | */ 10 | final case class ProofFormat( 11 | proof: Proof, 12 | requested_proof: TODO, 13 | identifiers: Seq[Identifier], 14 | ) 15 | 16 | object ProofFormat { 17 | // anoncreds/proof@v1.0 18 | def format = IssueCredentialRequestFormat.Anoncred 19 | } 20 | 21 | final case class Proof( 22 | proof: Seq[TODO], 23 | aggregated_proof: TODO 24 | ) 25 | 26 | final case class Identifier( 27 | schema_id: String, 28 | cred_def_id: String, 29 | rev_reg_id: Option[String], 30 | timestamp: Option[String], 31 | ) 32 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "identus-cloud-agent", 3 | "version": "2.0.0", 4 | "engines": { 5 | "node": ">=16.13.0" 6 | }, 7 | "devDependencies": { 8 | "@commitlint/cli": "^19.3.0", 9 | "@commitlint/config-conventional": "^19.7.1", 10 | "@semantic-release/changelog": "^6.0.3", 11 | "@semantic-release/exec": "^7.0.3", 12 | "@semantic-release/git": "^10.0.1", 13 | "conventional-changelog-conventionalcommits": "^8.0.0", 14 | "gradle-semantic-release-plugin": "^1.10.1", 15 | "husky": "^9.0.11", 16 | "pinst": "^3.0.0", 17 | "prettier": "^3.2.5", 18 | "semantic-release": "^24.2.1" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /pollux/README.md: -------------------------------------------------------------------------------- 1 | ## sbt project compiled with Scala 3 2 | 3 | ### Usage 4 | 5 | This is a normal sbt project. You can compile code with `sbt compile`, run it with `sbt run`, and `sbt console` will start a Scala 3 REPL. 6 | 7 | For more information on the sbt-dotty plugin, see the 8 | [scala3-example-project](https://github.com/scala/scala3-example-project/blob/main/README.md). 9 | 10 | ### To publish lib locally 11 | sbt publishLocal 12 | -------------------------------------------------------------------------------- /pollux/anoncreds/anoncreds-jvm-1.0-SNAPSHOT.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperledger-identus/cloud-agent/96f97f680d80f11399770a65100e0a915bca41d8/pollux/anoncreds/anoncreds-jvm-1.0-SNAPSHOT.jar -------------------------------------------------------------------------------- /pollux/anoncreds/native-lib/NATIVE/darwin-aarch64/libuniffi_anoncreds_wrapper.dylib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperledger-identus/cloud-agent/96f97f680d80f11399770a65100e0a915bca41d8/pollux/anoncreds/native-lib/NATIVE/darwin-aarch64/libuniffi_anoncreds_wrapper.dylib -------------------------------------------------------------------------------- /pollux/anoncreds/native-lib/NATIVE/darwin-x86-64/libuniffi_anoncreds_wrapper.dylib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperledger-identus/cloud-agent/96f97f680d80f11399770a65100e0a915bca41d8/pollux/anoncreds/native-lib/NATIVE/darwin-x86-64/libuniffi_anoncreds_wrapper.dylib -------------------------------------------------------------------------------- /pollux/anoncreds/native-lib/NATIVE/linux-aarch64/libuniffi_anoncreds_wrapper.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperledger-identus/cloud-agent/96f97f680d80f11399770a65100e0a915bca41d8/pollux/anoncreds/native-lib/NATIVE/linux-aarch64/libuniffi_anoncreds_wrapper.so -------------------------------------------------------------------------------- /pollux/anoncreds/native-lib/NATIVE/linux-x86-64/libuniffi_anoncreds_wrapper.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperledger-identus/cloud-agent/96f97f680d80f11399770a65100e0a915bca41d8/pollux/anoncreds/native-lib/NATIVE/linux-x86-64/libuniffi_anoncreds_wrapper.so -------------------------------------------------------------------------------- /pollux/anoncredsTest/src/test/scala/Uniffy.scala: -------------------------------------------------------------------------------- 1 | import uniffi.anoncreds_wrapper.* 2 | object Uniffy extends App { 3 | val prover = new Prover() 4 | val seceret = prover.createLinkSecret(); 5 | 6 | println("Prover secret") 7 | println(seceret.getBigNumber) 8 | } 9 | -------------------------------------------------------------------------------- /pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/model/CredentialFormat.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.pollux.core.model 2 | 3 | enum CredentialFormat: 4 | case JWT extends CredentialFormat 5 | case SDJWT extends CredentialFormat 6 | case AnonCreds extends CredentialFormat 7 | 8 | object CredentialFormat { 9 | def fromString(str: String) = str match 10 | case "JWT" => Some(CredentialFormat.JWT) 11 | case "SDJWT" => Some(CredentialFormat.SDJWT) 12 | case "AnonCreds" => Some(CredentialFormat.AnonCreds) 13 | case _ => None 14 | } 15 | -------------------------------------------------------------------------------- /pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/model/CredentialOfferAttachment.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.pollux.core.model 2 | 3 | import org.hyperledger.identus.pollux.core.model.presentation.Options 4 | import org.hyperledger.identus.pollux.prex.PresentationDefinition 5 | import zio.json.{DeriveJsonDecoder, DeriveJsonEncoder, JsonDecoder, JsonEncoder} 6 | 7 | final case class CredentialOfferAttachment(options: Options, presentation_definition: PresentationDefinition) 8 | 9 | object CredentialOfferAttachment { 10 | given JsonEncoder[CredentialOfferAttachment] = DeriveJsonEncoder.gen 11 | given JsonDecoder[CredentialOfferAttachment] = DeriveJsonDecoder.gen 12 | } 13 | -------------------------------------------------------------------------------- /pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/model/DidCommID.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.pollux.core.model 2 | 3 | import java.util.UUID 4 | 5 | // type DidCommID = String 6 | opaque type DidCommID = String 7 | object DidCommID: 8 | def apply(value: String): DidCommID = value 9 | def apply(): DidCommID = UUID.randomUUID.toString() 10 | extension (id: DidCommID) 11 | def value: String = id 12 | def uuid: UUID = UUID.fromString(id) 13 | -------------------------------------------------------------------------------- /pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/model/ResourceResolutionMethod.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.pollux.core.model 2 | 3 | import sttp.tapir.Schema 4 | import zio.json.* 5 | 6 | enum ResourceResolutionMethod { 7 | case did 8 | case http 9 | } 10 | 11 | object ResourceResolutionMethod { 12 | given schema: Schema[ResourceResolutionMethod] = Schema.derivedEnumeration.defaultStringBased 13 | given encoder: JsonEncoder[ResourceResolutionMethod] = JsonEncoder[String].contramap(_.toString) 14 | given decoder: JsonDecoder[ResourceResolutionMethod] = JsonDecoder[String].mapOrFail { s => 15 | ResourceResolutionMethod.values.find(_.toString == s).toRight(s"Unknown ResourceResolutionMethod: $s") 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/model/error/LinkSecretError.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.pollux.core.model.error 2 | 3 | final case class LinkSecretError(cause: Throwable) 4 | -------------------------------------------------------------------------------- /pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/model/error/VerificationPolicyError.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.pollux.core.model.error 2 | 3 | import org.hyperledger.identus.shared.models.{Failure, StatusCode} 4 | 5 | import java.util.UUID 6 | 7 | sealed trait VerificationPolicyError( 8 | val statusCode: StatusCode, 9 | val userFacingMessage: String 10 | ) extends Failure { 11 | override val namespace = "CredentialSchema" 12 | } 13 | 14 | object VerificationPolicyError { 15 | final case class NotFoundError(id: UUID) 16 | extends VerificationPolicyError(StatusCode.NotFound, s"VerificationPolicy is not found by $id") 17 | } 18 | -------------------------------------------------------------------------------- /pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/model/oid4vci/CredentialConfiguration.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.pollux.core.model.oid4vci 2 | 3 | import org.hyperledger.identus.pollux.core.model.CredentialFormat 4 | 5 | import java.net.URI 6 | import java.time.temporal.ChronoUnit 7 | import java.time.Instant 8 | 9 | final case class CredentialConfiguration( 10 | configurationId: String, 11 | format: CredentialFormat, 12 | schemaId: URI, 13 | createdAt: Instant 14 | ) { 15 | def scope: String = configurationId 16 | 17 | def withTruncatedTimestamp(unit: ChronoUnit = ChronoUnit.MICROS): CredentialConfiguration = copy( 18 | createdAt = createdAt.truncatedTo(unit), 19 | ) 20 | } 21 | -------------------------------------------------------------------------------- /pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/model/primitives/UriString.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.pollux.core.model.primitives 2 | 3 | import zio.prelude.Validation 4 | 5 | import java.net.URI 6 | import scala.util.Try 7 | 8 | opaque type UriString = String 9 | 10 | object UriString { 11 | 12 | def make(value: String): Validation[String, UriString] = { 13 | Try(URI(value)).fold( 14 | _ => Validation.fail(s"Invalid URI: $value"), 15 | _ => Validation.succeed(value) 16 | ) 17 | } 18 | 19 | extension (uriString: UriString) { 20 | def toUri: java.net.URI = new java.net.URI(uriString) 21 | def value: String = uriString 22 | } 23 | 24 | extension (uri: java.net.URI) { 25 | def toUriString: UriString = uri.toString 26 | } 27 | 28 | given CanEqual[UriString, UriString] = CanEqual.derived 29 | } 30 | -------------------------------------------------------------------------------- /pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/model/primitives/UrlString.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.pollux.core.model.primitives 2 | 3 | import zio.prelude.Validation 4 | 5 | import java.net.URI 6 | import scala.util.Try 7 | 8 | opaque type UrlString = String 9 | 10 | object UrlString { 11 | def make(value: String): Validation[String, UrlString] = { 12 | Try(URI(value).toURL).fold( 13 | _ => Validation.fail(s"Invalid URL: $value"), 14 | _ => Validation.succeed(value) 15 | ) 16 | } 17 | 18 | extension (urlString: UrlString) { 19 | def toUrl: java.net.URL = new java.net.URI(urlString).toURL 20 | def value: String = urlString 21 | } 22 | extension (url: java.net.URL) { 23 | def toUrlString: UrlString = url.toString 24 | } 25 | given CanEqual[UrlString, UrlString] = CanEqual.derived 26 | } 27 | -------------------------------------------------------------------------------- /pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/model/schema/CredentialSchemaRef.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.pollux.core.model.schema 2 | 3 | import org.hyperledger.identus.pollux.core.model.primitives.UriString 4 | 5 | enum CredentialSchemaRefType: 6 | case JsonSchema // according to W3C VCDM 2.0 7 | case JsonSchemaValidator2018 // according to W3C VCDM 1.1 8 | 9 | // Represents the credentialSchema properly of the VC according to W3C VCDM 1.1 10 | case class CredentialSchemaRef(`type`: CredentialSchemaRefType, id: UriString) 11 | -------------------------------------------------------------------------------- /pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/model/schema/type/CredentialJsonSchemaType.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.pollux.core.model.schema.`type` 2 | 3 | import org.hyperledger.identus.pollux.core.model.schema.Schema 4 | import org.hyperledger.identus.shared.json.{JsonSchemaError, JsonSchemaValidatorImpl} 5 | import zio.* 6 | import zio.json.* 7 | 8 | object CredentialJsonSchemaType extends CredentialSchemaType { 9 | val VC_JSON_SCHEMA_URI = "https://w3c-ccg.github.io/vc-json-schemas/schema/2.0/schema.json" 10 | 11 | override val `type`: String = VC_JSON_SCHEMA_URI 12 | 13 | override def validate(schema: Schema): IO[JsonSchemaError, Unit] = 14 | for { 15 | credentialJsonSchema <- CredentialJsonSchemaSerDesV1.schemaSerDes.deserialize(schema.toJson) 16 | _ <- JsonSchemaValidatorImpl.from(schema) 17 | } yield () 18 | } 19 | -------------------------------------------------------------------------------- /pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/model/schema/type/CredentialSchemaType.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.pollux.core.model.schema.`type` 2 | 3 | import org.hyperledger.identus.pollux.core.model.schema.Schema 4 | import org.hyperledger.identus.shared.json.JsonSchemaError 5 | import zio.IO 6 | 7 | trait CredentialSchemaType { 8 | val `type`: String 9 | 10 | def validate(schema: Schema): IO[JsonSchemaError, Unit] 11 | } 12 | -------------------------------------------------------------------------------- /pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/model/secret/CredentialDefinitionSecret.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.pollux.core.model.secret 2 | 3 | import org.hyperledger.identus.agent.walletapi.storage.GenericSecret 4 | import zio.json.ast.Json 5 | 6 | import java.util.UUID 7 | import scala.util.Try 8 | 9 | final case class CredentialDefinitionSecret(json: Json) 10 | 11 | object CredentialDefinitionSecret { 12 | given GenericSecret[UUID, CredentialDefinitionSecret] = new { 13 | override def keyPath(id: UUID): String = s"credential-definitions/${id.toString}" 14 | 15 | override def encodeValue(secret: CredentialDefinitionSecret): Json = secret.json 16 | 17 | override def decodeValue(json: Json): Try[CredentialDefinitionSecret] = Try(CredentialDefinitionSecret(json)) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/repository/PresentationExchangeRepository.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.pollux.core.repository 2 | 3 | import org.hyperledger.identus.pollux.prex.PresentationDefinition 4 | import org.hyperledger.identus.shared.models.WalletAccessContext 5 | import zio.* 6 | 7 | import java.util.UUID 8 | 9 | trait PresentationExchangeRepository { 10 | def createPresentationDefinition(pd: PresentationDefinition): URIO[WalletAccessContext, Unit] 11 | def findPresentationDefinition(id: UUID): UIO[Option[PresentationDefinition]] 12 | def listPresentationDefinition( 13 | offset: Option[Int] = None, 14 | limit: Option[Int] = None 15 | ): URIO[WalletAccessContext, (Seq[PresentationDefinition], Int)] 16 | } 17 | -------------------------------------------------------------------------------- /pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/repository/repository.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.pollux.core.repository 2 | 3 | import org.hyperledger.identus.shared.models.WalletAccessContext 4 | import zio.URIO 5 | 6 | trait Repository[F[_], T] 7 | 8 | type WalletTask[T] = URIO[WalletAccessContext, T] 9 | 10 | object Repository { 11 | case class SearchQuery[Filter](filter: Filter, skip: Int, limit: Int) 12 | 13 | case class SearchResult[T](entries: Seq[T], count: Long, totalCount: Long) 14 | 15 | trait SearchCapability[F[_], Filter, T] { 16 | self: Repository[F, T] => 17 | def search(query: SearchQuery[Filter]): F[SearchResult[T]] 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/service/LinkSecretService.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.pollux.core.service 2 | 3 | import org.hyperledger.identus.pollux.anoncreds.AnoncredLinkSecretWithId 4 | import org.hyperledger.identus.shared.models.WalletAccessContext 5 | import zio.URIO 6 | 7 | trait LinkSecretService { 8 | def fetchOrCreate(): URIO[WalletAccessContext, AnoncredLinkSecretWithId] 9 | } 10 | -------------------------------------------------------------------------------- /pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/service/serdes/SDJwtPresentationRequest.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.pollux.core.service.serdes 2 | 3 | import org.hyperledger.identus.pollux.core.model.presentation.Options 4 | import zio.json.* 5 | 6 | case class SDJwtPresentation(options: Option[Options], claims: ast.Json.Obj) 7 | 8 | object SDJwtPresentation { 9 | given JsonDecoder[Options] = DeriveJsonDecoder.gen[Options] 10 | given JsonEncoder[Options] = DeriveJsonEncoder.gen[Options] 11 | 12 | given JsonDecoder[SDJwtPresentation] = DeriveJsonDecoder.gen[SDJwtPresentation] 13 | given JsonEncoder[SDJwtPresentation] = DeriveJsonEncoder.gen[SDJwtPresentation] 14 | } 15 | -------------------------------------------------------------------------------- /pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/service/verification/VcVerificationService.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.pollux.core.service.verification 2 | 3 | import zio.* 4 | 5 | trait VcVerificationService { 6 | def verify(request: List[VcVerificationRequest]): IO[VcVerificationServiceError, List[VcVerificationResult]] 7 | } 8 | 9 | final case class VcVerificationRequest( 10 | credential: String, 11 | verification: VcVerification, 12 | ) 13 | 14 | final case class VcVerificationResult( 15 | credential: String, 16 | verification: VcVerification, 17 | success: Boolean 18 | ) 19 | -------------------------------------------------------------------------------- /pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/service/verification/VcVerificationServiceError.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.pollux.core.service.verification 2 | 3 | sealed trait VcVerificationServiceError { 4 | def error: String 5 | } 6 | 7 | object VcVerificationServiceError { 8 | final case class UnexpectedError(error: String) extends VcVerificationServiceError 9 | } 10 | -------------------------------------------------------------------------------- /pollux/core/src/test/resources/anoncred-presentation-schema-example.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "resource:///anoncred-presentation-schema-example.json", 3 | "version": "1.0", 4 | "attrNames": [ 5 | "name", 6 | "sex", 7 | "age" 8 | ], 9 | "issuerId": "did:prism:issuer" 10 | } -------------------------------------------------------------------------------- /pollux/core/src/test/resources/anoncred-schema-example.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Driving licence Anoncred Schema", 3 | "version": "1.0", 4 | "attrNames": [ 5 | "emailAddress", 6 | "familyName", 7 | "dateOfIssuance", 8 | "drivingLicenseID", 9 | "drivingClass" 10 | ], 11 | "issuerId": "http://www.example.com/issuer" 12 | } 13 | -------------------------------------------------------------------------------- /pollux/core/src/test/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | [%level] %logger{15} - %message%n%rEx%xException{10} 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /pollux/core/src/test/resources/vc-schema-driver-license.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2020-12/schema", 3 | "description": "Driving License", 4 | "type": "object", 5 | "properties": { 6 | "credentialSubject": { 7 | "type": "object", 8 | "properties": { 9 | "dateOfIssuance": { 10 | "type": "string", 11 | "format": "date-time" 12 | }, 13 | "drivingLicenseID": { 14 | "type": "integer" 15 | }, 16 | "drivingClass": { 17 | "type": "integer" 18 | } 19 | }, 20 | "required": ["dateOfIssuance", "drivingLicenseID", "drivingClass"], 21 | "additionalProperties": true 22 | } 23 | }, 24 | "required": ["credentialSubject"], 25 | "additionalProperties": true 26 | } 27 | -------------------------------------------------------------------------------- /pollux/core/src/test/resources/vc-schema-personal.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2020-12/schema", 3 | "description": "Age", 4 | "type": "object", 5 | "properties": { 6 | "credentialSubject": { 7 | "type": "object", 8 | "properties": { 9 | "email": { 10 | "type": "string", 11 | "format": "email" 12 | }, 13 | "userName": { 14 | "type": "string" 15 | }, 16 | "age": { 17 | "type": "integer" 18 | } 19 | }, 20 | "required": ["email", "userName", "age"], 21 | "additionalProperties": true 22 | } 23 | }, 24 | "required": ["credentialSubject"], 25 | "additionalProperties": true 26 | } 27 | -------------------------------------------------------------------------------- /pollux/core/src/test/scala/org/hyperledger/identus/pollux/core/repository/CredentialRepositoryInMemorySpec.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.pollux.core.repository 2 | 3 | import zio.* 4 | import zio.test.* 5 | 6 | /** core/testOnly org.hyperledger.identus.pollux.core.repository.CredentialRepositoryInMemorySpec */ 7 | object CredentialRepositoryInMemorySpec extends ZIOSpecDefault { 8 | 9 | override def spec: Spec[TestEnvironment & Scope, Any] = 10 | suite("Credential Repository In Memory test suite")( 11 | CredentialRepositorySpecSuite.testSuite, 12 | CredentialRepositorySpecSuite.multitenantTestSuite 13 | ).provide(CredentialRepositoryInMemory.layer) 14 | 15 | } 16 | -------------------------------------------------------------------------------- /pollux/core/src/test/scala/org/hyperledger/identus/pollux/core/repository/PresentationRepositoryInMemorySpec.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.pollux.core.repository 2 | 3 | import zio.* 4 | import zio.test.* 5 | 6 | object PresentationRepositoryInMemorySpec extends ZIOSpecDefault { 7 | 8 | override def spec: Spec[TestEnvironment & Scope, Any] = 9 | suite("Presentation Repository In Memory test suite")( 10 | PresentationRepositorySpecSuite.testSuite, 11 | PresentationRepositorySpecSuite.multitenantTestSuite 12 | ).provide(PresentationRepositoryInMemory.layer) 13 | 14 | } 15 | -------------------------------------------------------------------------------- /pollux/prex/src/test/resources/pd/filter_by_cred_type.json: -------------------------------------------------------------------------------- 1 | { 2 | "presentation_definition": { 3 | "id": "first simple example", 4 | "input_descriptors": [ 5 | { 6 | "id": "A specific type of VC", 7 | "name": "A specific type of VC", 8 | "purpose": "We want a VC of this type", 9 | "constraints": { 10 | "fields": [ 11 | { 12 | "path": ["$.type"], 13 | "filter": { 14 | "type": "array" 15 | } 16 | } 17 | ] 18 | } 19 | } 20 | ] 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /pollux/prex/src/test/resources/pd/minimal_example.json: -------------------------------------------------------------------------------- 1 | { 2 | "comment": "Note: VP, OIDC, DIDComm, or CHAPI outer wrapper would be here.", 3 | "presentation_definition": { 4 | "id": "32f54163-7166-48f1-93d8-ff217bdb0653", 5 | "input_descriptors": [ 6 | { 7 | "id": "wa_driver_license", 8 | "name": "Washington State Business License", 9 | "purpose": "We can only allow licensed Washington State business representatives into the WA Business Conference", 10 | "constraints": { 11 | "fields": [ 12 | { 13 | "path": [ 14 | "$.credentialSubject.dateOfBirth", 15 | "$.credentialSubject.dob", 16 | "$.vc.credentialSubject.dateOfBirth", 17 | "$.vc.credentialSubject.dob" 18 | ] 19 | } 20 | ] 21 | } 22 | } 23 | ] 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /pollux/prex/src/test/resources/ps/basic_presentation.json: -------------------------------------------------------------------------------- 1 | { 2 | "presentation_submission": { 3 | "id": "a30e3b91-fb77-4d22-95fa-871689c322e2", 4 | "definition_id": "32f54163-7166-48f1-93d8-ff217bdb0653", 5 | "descriptor_map": [ 6 | { 7 | "id": "banking_input_2", 8 | "format": "jwt_vc", 9 | "path": "$.verifiableCredential[0]" 10 | }, 11 | { 12 | "id": "employment_input", 13 | "format": "jwt_vc", 14 | "path": "$.verifiableCredential[1]" 15 | }, 16 | { 17 | "id": "citizenship_input_1", 18 | "format": "jwt_vc", 19 | "path": "$.verifiableCredential[2]" 20 | } 21 | ] 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /pollux/prex/src/test/resources/ps/nested_presentation.json: -------------------------------------------------------------------------------- 1 | { 2 | "presentation_submission": { 3 | "id": "a30e3b91-fb77-4d22-95fa-871689c322e2", 4 | "definition_id": "32f54163-7166-48f1-93d8-ff217bdb0653", 5 | "descriptor_map": [ 6 | { 7 | "id": "banking_input_2", 8 | "format": "jwt_vp", 9 | "path": "$.outerClaim[0]", 10 | "path_nested": { 11 | "id": "banking_input_2", 12 | "format": "jwt_vc", 13 | "path": "$.innerClaim[1]", 14 | "path_nested": { 15 | "id": "banking_input_2", 16 | "format": "jwt_vc", 17 | "path": "$.mostInnerClaim[2]" 18 | } 19 | } 20 | } 21 | ] 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /pollux/sql-doobie/src/main/resources/sql/pollux/V10__presentation_records_add_thid_unique_constraint.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE public.presentation_records ADD CONSTRAINT presentation_records_unique_thid UNIQUE (thid); -------------------------------------------------------------------------------- /pollux/sql-doobie/src/main/resources/sql/pollux/V11__issue_credential_extend_schema_id.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE public.issue_credential_records ALTER COLUMN "schema_id" TYPE VARCHAR(500); -------------------------------------------------------------------------------- /pollux/sql-doobie/src/main/resources/sql/pollux/V12__verification_policies_reset_nonce.sql: -------------------------------------------------------------------------------- 1 | UPDATE public.verification_policy 2 | SET nonce = 0; -------------------------------------------------------------------------------- /pollux/sql-doobie/src/main/resources/sql/pollux/V15__add_anoncreds_columns.sql: -------------------------------------------------------------------------------- 1 | -- issue_credential_records 2 | ALTER TABLE public.issue_credential_records 3 | ADD COLUMN "credential_format" VARCHAR(9), 4 | ADD COLUMN "credential_definition_id" UUID, 5 | ADD COLUMN "ac_request_credential_metadata" TEXT; 6 | 7 | UPDATE public.issue_credential_records 8 | SET "credential_format" = 'JWT'; 9 | 10 | ALTER TABLE public.issue_credential_records 11 | ALTER COLUMN "credential_format" SET NOT NULL; 12 | 13 | 14 | 15 | -- presentation_records 16 | ALTER TABLE public.presentation_records 17 | ADD COLUMN "credential_format" VARCHAR(9); 18 | 19 | UPDATE public.presentation_records 20 | SET "credential_format" = 'JWT'; 21 | 22 | ALTER TABLE public.presentation_records 23 | ALTER COLUMN "credential_format" SET NOT NULL; 24 | -------------------------------------------------------------------------------- /pollux/sql-doobie/src/main/resources/sql/pollux/V17__add_anoncred_credentials_to_use_columns.sql: -------------------------------------------------------------------------------- 1 | -- presentation_records 2 | ALTER TABLE public.presentation_records 3 | ADD COLUMN "anoncred_credentials_to_use_json_schema_id" VARCHAR(64), 4 | ADD COLUMN "anoncred_credentials_to_use" JSON; -------------------------------------------------------------------------------- /pollux/sql-doobie/src/main/resources/sql/pollux/V18__issue_credential_rename_schema_id.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE public.issue_credential_records RENAME COLUMN schema_id TO schema_uri; 2 | ALTER TABLE public.issue_credential_records ADD COLUMN credential_definition_uri VARCHAR(500); 3 | -------------------------------------------------------------------------------- /pollux/sql-doobie/src/main/resources/sql/pollux/V19__update_revocation_status_list_table_and_columns.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE public.credential_status_lists 2 | DROP COLUMN encoded_list, 3 | DROP COLUMN proof; 4 | 5 | ALTER TABLE public.credential_status_lists 6 | ADD COLUMN status_list_credential JSON NOT NULL, 7 | ADD COLUMN size INTEGER NOT NULL DEFAULT 131072, 8 | ADD COLUMN last_used_index INTEGER NOT NULL DEFAULT 0; 9 | 10 | ALTER TABLE public.credentials_in_status_list 11 | ADD COLUMN is_processed BOOLEAN NOT NULL DEFAULT false; 12 | -------------------------------------------------------------------------------- /pollux/sql-doobie/src/main/resources/sql/pollux/V20__add_sdjwt_claims_to_disclose_columns.sql: -------------------------------------------------------------------------------- 1 | -- presentation_records 2 | ALTER TABLE public.presentation_records 3 | ADD COLUMN "sd_jwt_claims_to_use_json_schema_id" VARCHAR(64), 4 | ADD COLUMN "sd_jwt_claims_to_disclose" JSON; -------------------------------------------------------------------------------- /pollux/sql-doobie/src/main/resources/sql/pollux/V22__add_keyId_column_issue_credential_record.sql: -------------------------------------------------------------------------------- 1 | -- presentation_records 2 | ALTER TABLE public.issue_credential_records 3 | ADD COLUMN "key_id" TEXT 4 | -------------------------------------------------------------------------------- /pollux/sql-doobie/src/main/resources/sql/pollux/V23__clear_content_of_meta_last_failure.sql: -------------------------------------------------------------------------------- 1 | -- Clear content of meta_last_failure 2 | UPDATE public.issue_credential_records SET meta_last_failure=NULL; 3 | UPDATE public.presentation_records SET meta_last_failure=NULL; -------------------------------------------------------------------------------- /pollux/sql-doobie/src/main/resources/sql/pollux/V24__add_invitation_column_presentation_record.sql: -------------------------------------------------------------------------------- 1 | -- presentation_records 2 | -- Introduce new field invitation for connection-less presentation 3 | ALTER TABLE public.presentation_records 4 | ADD COLUMN "invitation" TEXT; -------------------------------------------------------------------------------- /pollux/sql-doobie/src/main/resources/sql/pollux/V25__add_invitation_column_invitation_record.sql: -------------------------------------------------------------------------------- 1 | -- issue_credential_records 2 | -- Introduce new field invitation for connection-less credential issuance 3 | ALTER TABLE public.issue_credential_records 4 | ADD COLUMN "invitation" TEXT; -------------------------------------------------------------------------------- /pollux/sql-doobie/src/main/resources/sql/pollux/V26__remove_subject_id_column_presentation_record.sql: -------------------------------------------------------------------------------- 1 | -- presentation_records 2 | -- Remove subject_id column 3 | ALTER TABLE public.presentation_records 4 | DROP COLUMN "subject_id"; -------------------------------------------------------------------------------- /pollux/sql-doobie/src/main/resources/sql/pollux/V27__presentation_definition_table.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE public.presentation_definition ( 2 | id UUID PRIMARY KEY, 3 | input_descriptors json NOT NULL, 4 | name VARCHAR(300), 5 | purpose VARCHAR(100), 6 | "format" json, 7 | wallet_id UUID NOT NULL, 8 | created_at TIMESTAMP WITH TIME ZONE NOT NULL 9 | ); 10 | 11 | ALTER TABLE public.presentation_definition 12 | ENABLE ROW LEVEL SECURITY; 13 | 14 | CREATE POLICY presentation_definition_wallet_isolation 15 | ON public.presentation_definition 16 | USING (wallet_id = current_setting('app.current_wallet_id')::UUID); 17 | -------------------------------------------------------------------------------- /pollux/sql-doobie/src/main/resources/sql/pollux/V28__support_multiple_credential_schema.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE public.issue_credential_records 2 | ADD COLUMN schema_uris VARCHAR(500)[]; 3 | 4 | UPDATE public.issue_credential_records 5 | SET schema_uris = ARRAY[schema_uri] 6 | WHERE schema_uri IS NOT NULL; 7 | 8 | ALTER TABLE public.issue_credential_records 9 | DROP COLUMN schema_uri; -------------------------------------------------------------------------------- /pollux/sql-doobie/src/main/resources/sql/pollux/V29__add_resolution_method_to_schema_and_cred_definition.sql: -------------------------------------------------------------------------------- 1 | -- Create the enum type 2 | CREATE TYPE resolution_method_enum AS ENUM ('http', 'did'); 3 | 4 | -- Add the column to credential_definition table 5 | ALTER TABLE public.credential_definition 6 | ADD COLUMN resolution_method resolution_method_enum NOT NULL DEFAULT 'http'; 7 | 8 | -- Add the column to credential_schema table 9 | ALTER TABLE public.credential_schema 10 | ADD COLUMN resolution_method resolution_method_enum NOT NULL DEFAULT 'http'; 11 | -------------------------------------------------------------------------------- /pollux/sql-doobie/src/main/resources/sql/pollux/V30__add_sdjwt_disclosed_claims_columns.sql: -------------------------------------------------------------------------------- 1 | -- presentation_records 2 | ALTER TABLE public.presentation_records 3 | ADD COLUMN "sd_jwt_disclosed_claims" JSON; -------------------------------------------------------------------------------- /pollux/sql-doobie/src/main/resources/sql/pollux/V5__create_protocol_state_index.sql: -------------------------------------------------------------------------------- 1 | CREATE INDEX protocol_state_idx 2 | ON public.issue_credential_records (protocol_state); -------------------------------------------------------------------------------- /pollux/sql-doobie/src/main/resources/sql/pollux/V9__issue_credential_drop_subjectId_not_null.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE public.issue_credential_records ALTER COLUMN "subject_id" DROP NOT NULL; 2 | 3 | ALTER TABLE public.issue_credential_records ALTER COLUMN "created_at" TYPE TIMESTAMP WITH TIME ZONE; 4 | ALTER TABLE public.issue_credential_records ALTER COLUMN "updated_at" TYPE TIMESTAMP WITH TIME ZONE; 5 | ALTER TABLE public.issue_credential_records ALTER COLUMN "meta_next_retry" TYPE TIMESTAMP WITH TIME ZONE; 6 | 7 | ALTER TABLE public.presentation_records ALTER COLUMN "created_at" TYPE TIMESTAMP WITH TIME ZONE; 8 | ALTER TABLE public.presentation_records ALTER COLUMN "updated_at" TYPE TIMESTAMP WITH TIME ZONE; 9 | ALTER TABLE public.presentation_records ALTER COLUMN "meta_next_retry" TYPE TIMESTAMP WITH TIME ZONE; -------------------------------------------------------------------------------- /pollux/sql-doobie/src/main/scala/org/hyperledger/identus/pollux/sql/model/JWTCredentialRow.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.pollux.sql.model 2 | 3 | private[sql] final case class JWTCredentialRow( 4 | batchId: String, 5 | credentialId: String, 6 | content: String 7 | ) 8 | -------------------------------------------------------------------------------- /pollux/sql-doobie/src/test/resources/data/verifiableCredentialClaims.csv: -------------------------------------------------------------------------------- 1 | first_name 2 | second_name 3 | date_of_birth 4 | country_of_residence 5 | country_of_birth 6 | marriage_status 7 | sex 8 | degree 9 | alumni_of 10 | resident_of 11 | member_of 12 | owner_of 13 | grade 14 | score 15 | flight_destination 16 | flight_origin 17 | board_number 18 | booking_reference 19 | expired_date 20 | issuance_date -------------------------------------------------------------------------------- /pollux/vc-jwt/src/main/scala/org/hyperledger/identus/pollux/vc/jwt/CredentialSchemaAndTrustedIssuersConstraint.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.pollux.vc.jwt 2 | 3 | case class CredentialSchemaAndTrustedIssuersConstraint( 4 | schemaId: String, 5 | trustedIssuers: Option[Seq[String]] 6 | ) 7 | -------------------------------------------------------------------------------- /pollux/vc-jwt/src/main/scala/org/hyperledger/identus/pollux/vc/jwt/JsonWebKey.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.pollux.vc.jwt 2 | 3 | import zio.json.{DeriveJsonDecoder, DeriveJsonEncoder, JsonDecoder, JsonEncoder} 4 | 5 | case class JsonWebKey( 6 | alg: Option[String] = Option.empty, 7 | crv: Option[String] = Option.empty, 8 | e: Option[String] = Option.empty, 9 | d: Option[String] = Option.empty, 10 | ext: Option[Boolean] = Option.empty, 11 | key_ops: Vector[String] = Vector.empty, 12 | kid: Option[String] = Option.empty, 13 | kty: String, 14 | n: Option[String] = Option.empty, 15 | use: Option[String] = Option.empty, 16 | x: Option[String] = Option.empty, 17 | y: Option[String] = Option.empty 18 | ) 19 | 20 | object JsonWebKey { 21 | given JsonEncoder[JsonWebKey] = DeriveJsonEncoder.gen 22 | given JsonDecoder[JsonWebKey] = DeriveJsonDecoder.gen 23 | } 24 | -------------------------------------------------------------------------------- /pollux/vc-jwt/src/main/scala/org/hyperledger/identus/pollux/vc/jwt/ValidationUtils.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.pollux.vc.jwt 2 | 3 | import zio.{Trace, ZIO} 4 | import zio.prelude.{Validation, ZValidation} 5 | 6 | object ValidationUtils { 7 | final def foreach[R, E, W, VE, A, B](in: ZValidation[W, VE, A])(f: A => ZIO[R, E, B])(implicit 8 | trace: Trace 9 | ): ZIO[R, E, ZValidation[W, VE, B]] = 10 | in.fold(e => ZIO.succeed(Validation.failNonEmptyChunk(e)), f(_).map(Validation.succeed)) 11 | 12 | } 13 | -------------------------------------------------------------------------------- /pollux/vc-jwt/src/main/scala/org/hyperledger/identus/pollux/vc/jwt/Verifiable.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.pollux.vc.jwt 2 | 3 | import zio.json.{DeriveJsonDecoder, DeriveJsonEncoder, JsonDecoder, JsonEncoder} 4 | 5 | import scala.annotation.unused 6 | 7 | trait Verifiable(@unused proof: JwtProof) 8 | 9 | // JwtProof2020 is not following the spec 10 | case class JwtProof(`type`: String = "JwtProof2020", jwt: JWT) 11 | 12 | object JwtProof { 13 | given JsonEncoder[JwtProof] = DeriveJsonEncoder.gen 14 | given JsonDecoder[JwtProof] = DeriveJsonDecoder.gen 15 | } 16 | -------------------------------------------------------------------------------- /pollux/vc-jwt/src/test/scala/org/hyperledger/identus/pollux/vc/jwt/ECDSAVerifierTest.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.pollux.vc.jwt 2 | 3 | import com.nimbusds.jose.crypto.bc.BouncyCastleProviderSingleton 4 | import com.nimbusds.jose.jwk.gen.ECKeyGenerator 5 | import com.nimbusds.jose.jwk.Curve 6 | import org.bouncycastle.jce.provider.BouncyCastleProvider 7 | import org.scalatest.funsuite.AnyFunSuite 8 | import org.scalatest.matchers.must.Matchers.mustBe 9 | import org.scalatest.matchers.should.Matchers 10 | 11 | class ECDSAVerifierTest extends AnyFunSuite with Matchers { 12 | 13 | test("toECDSAVerifier should use BouncyCastleProviderSingleton") { 14 | val ecKey = ECKeyGenerator(Curve.SECP256K1).provider(BouncyCastleProviderSingleton.getInstance()).generate() 15 | val verifier = JWTVerification.toECDSAVerifier(ecKey.toPublicKey) 16 | val provider = verifier.getJCAContext.getProvider 17 | provider mustBe a[BouncyCastleProvider] 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /pollux/vc-jwt/src/test/scala/org/hyperledger/identus/pollux/vc/jwt/ES256KSignerTest.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.pollux.vc.jwt 2 | 3 | import com.nimbusds.jose.crypto.bc.BouncyCastleProviderSingleton 4 | import com.nimbusds.jose.jwk.gen.ECKeyGenerator 5 | import com.nimbusds.jose.jwk.Curve 6 | import org.bouncycastle.jce.provider.BouncyCastleProvider 7 | import org.scalatest.funsuite.AnyFunSuite 8 | import org.scalatest.matchers.must.Matchers.mustBe 9 | import org.scalatest.matchers.should.Matchers 10 | 11 | class ES256KSignerTest extends AnyFunSuite with Matchers { 12 | 13 | test("ES256KSigner should use BouncyCastleProviderSingleton") { 14 | val ecKey = ECKeyGenerator(Curve.SECP256K1).provider(BouncyCastleProviderSingleton.getInstance()).generate() 15 | val signer = new ES256KSigner(ecKey.toPrivateKey).signer 16 | val provider = signer.getJCAContext.getProvider 17 | provider mustBe a[BouncyCastleProvider] 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /prism-node/client/scala-client/README.md: -------------------------------------------------------------------------------- 1 | ## sbt project compiled with Scala 3 2 | 3 | ### Usage 4 | 5 | This is a normal sbt project. You can compile code with `sbt compile`, run it with `sbt run`, and `sbt console` will start a Scala 3 REPL. 6 | 7 | For more information on the sbt-dotty plugin, see the 8 | [scala3-example-project](https://github.com/scala/scala3-example-project/blob/main/README.md). 9 | -------------------------------------------------------------------------------- /prism-node/client/scala-client/api/grpc/cviews_api.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | option java_multiple_files = true; 4 | option java_package = "io.iohk.atala.prism.protos"; 5 | 6 | package io.iohk.atala.prism.protos; 7 | 8 | import "cviews_models.proto"; 9 | 10 | // The API for the credential views. 11 | service CredentialViewsService { 12 | // Gets the available view templates. 13 | rpc GetCredentialViewTemplates (GetCredentialViewTemplatesRequest) returns (GetCredentialViewTemplatesResponse) {} 14 | } 15 | 16 | // Request to get the available view templates. 17 | message GetCredentialViewTemplatesRequest {} 18 | // Response with the available view templates. 19 | message GetCredentialViewTemplatesResponse { 20 | repeated CredentialViewTemplate templates = 1; // the available templates 21 | } 22 | -------------------------------------------------------------------------------- /prism-node/client/scala-client/api/grpc/cviews_models.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | option java_multiple_files = true; 4 | option java_package = "io.iohk.atala.prism.protos"; 5 | 6 | package io.iohk.atala.prism.protos; 7 | 8 | // Represents a credential template. 9 | message CredentialViewTemplate { 10 | int64 id = 1; // The unique ID for this template. 11 | string name = 2; // The template's name. 12 | string encoded_logo_image = 3; // Logo image encoded in base64 as a UTF-8 string. 13 | string logo_image_mime_type = 4; // The MIME Type for the logo. 14 | 15 | // HTML view with replaceable variables enclosed by double brackets, e.g., "{{foo.bar}}" 16 | string html_template = 5; 17 | } 18 | -------------------------------------------------------------------------------- /prism-node/client/scala-client/api/grpc/intdemo/intdemo_models.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package io.iohk.atala.prism.intdemo.protos; 4 | 5 | message Date { 6 | int32 year = 1; // positive value 7 | int32 month = 2; // value in the [1, 12] interval 8 | int32 day = 3; // value in the [1, 31] interval (depending on the month, the max value might be 28 9 | } 10 | 11 | enum SubjectStatus { 12 | UNCONNECTED = 0; 13 | CONNECTED = 1; 14 | CREDENTIAL_AVAILABLE = 2; 15 | CREDENTIAL_SENT = 3; 16 | CREDENTIAL_RECEIVED = 4; 17 | } 18 | -------------------------------------------------------------------------------- /prism-node/client/scala-client/api/grpc/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@input-output-hk/atala-prism-protos", 3 | "version": "2.0.0", 4 | "description": "raw proto files for Atala PRISM project", 5 | "repository": { 6 | "type": "git", 7 | "url": "git+https://github.com/input-output-hk/atala-prism-sdk.git" 8 | }, 9 | "author": "input-output-hk" 10 | } 11 | -------------------------------------------------------------------------------- /prism-node/client/scala-client/src/main/resources/package.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package org.hyperledger.identus.protos; 4 | 5 | import "scalapb/scalapb.proto"; 6 | 7 | option (scalapb.options) = { 8 | scope: PACKAGE 9 | no_default_values_in_constructor: true 10 | }; 11 | -------------------------------------------------------------------------------- /project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version=1.10.11 2 | -------------------------------------------------------------------------------- /project/build.sbt: -------------------------------------------------------------------------------- 1 | // Using unreleased plugin from 'main' which accepts DependencyResolution interface for building license report. 2 | lazy val sbtLicenseReportPlugin = ProjectRef( 3 | uri("https://github.com/sbt/sbt-license-report.git#9675cedb19c794de1119cbcf46a255fc8dcd5d4e"), 4 | "sbt-license-report" 5 | ) 6 | 7 | lazy val root = (project in file(".")).dependsOn(sbtLicenseReportPlugin) 8 | -------------------------------------------------------------------------------- /shared/README.md: -------------------------------------------------------------------------------- 1 | ## shared 2 | 3 | Contains a stateless utility code which might be reused across all the building blocks. 4 | -------------------------------------------------------------------------------- /shared/core/src/main/scala/org/hyperledger/identus/shared/db/DbConfig.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.shared.db 2 | 3 | case class DbConfig( 4 | username: String, 5 | password: String, 6 | jdbcUrl: String, 7 | awaitConnectionThreads: Int = 8 8 | ) 9 | -------------------------------------------------------------------------------- /shared/core/src/main/scala/org/hyperledger/identus/shared/http/DataUrlResolver.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.shared.http 2 | 3 | import io.lemonlabs.uri.DataUrl 4 | import zio.* 5 | 6 | class DataUrlResolver extends UriResolver { 7 | override def resolve(dataUrl: String): IO[GenericUriResolverError, String] = { 8 | 9 | DataUrl.parseOption(dataUrl).fold(ZIO.fail(InvalidUri(dataUrl))) { url => 10 | ZIO.succeed(String(url.data, url.mediaType.charset)) 11 | } 12 | } 13 | } 14 | 15 | object DataUrlResolver { 16 | val layer: ULayer[DataUrlResolver] = ZLayer.succeed(new DataUrlResolver) 17 | } 18 | -------------------------------------------------------------------------------- /shared/core/src/main/scala/org/hyperledger/identus/shared/models/Base64UrlString.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.shared.models 2 | 3 | import org.hyperledger.identus.shared.utils.Base64Utils 4 | 5 | import scala.util.Try 6 | 7 | opaque type Base64UrlString = String 8 | 9 | object Base64UrlString { 10 | def fromStringUnsafe(s: String): Base64UrlString = s 11 | def fromString(s: String): Try[Base64UrlString] = Try(Base64Utils.decodeURL(s)).map(_ => s) 12 | def fromByteArray(bytes: Array[Byte]): Base64UrlString = Base64Utils.encodeURL(bytes) 13 | 14 | extension (s: Base64UrlString) { 15 | def toStringNoPadding: String = s.takeWhile(_ != '=') 16 | def toByteArray: Array[Byte] = Base64Utils.decodeURL(s) 17 | def toString: String = s 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /shared/core/src/main/scala/org/hyperledger/identus/shared/models/HexString.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.shared.models 2 | 3 | import org.hyperledger.identus.shared.utils.BytesOps 4 | 5 | import scala.util.Try 6 | 7 | opaque type HexString = String 8 | 9 | object HexString { 10 | def fromStringUnsafe(s: String): HexString = s 11 | def fromString(s: String): Try[HexString] = Try(BytesOps.hexToBytes(s)).map(_ => s) 12 | def fromByteArray(bytes: Array[Byte]): HexString = BytesOps.bytesToHex(bytes) 13 | 14 | extension (s: HexString) { 15 | def toByteArray: Array[Byte] = BytesOps.hexToBytes(s) 16 | def toString: String = s 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /shared/core/src/main/scala/org/hyperledger/identus/shared/models/KeyId.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.shared.models 2 | 3 | import zio.json.* 4 | 5 | opaque type KeyId = String 6 | object KeyId: 7 | def apply(value: String): KeyId = value 8 | extension (id: KeyId) def value: String = id 9 | given decoder: JsonDecoder[KeyId] = JsonDecoder.string.map(KeyId(_)) 10 | given encoder: JsonEncoder[KeyId] = JsonEncoder.string.contramap[KeyId](_.value) 11 | -------------------------------------------------------------------------------- /shared/core/src/main/scala/org/hyperledger/identus/shared/models/PrismEnvelope.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.shared.models 2 | import zio.json.* 3 | 4 | trait PrismEnvelope { 5 | val resource: String 6 | val url: String 7 | } 8 | 9 | case class PrismEnvelopeData(resource: String, url: String) extends PrismEnvelope 10 | object PrismEnvelopeData { 11 | given encoder: JsonEncoder[PrismEnvelopeData] = 12 | DeriveJsonEncoder.gen[PrismEnvelopeData] 13 | 14 | given decoder: JsonDecoder[PrismEnvelopeData] = 15 | DeriveJsonDecoder.gen[PrismEnvelopeData] 16 | } 17 | -------------------------------------------------------------------------------- /shared/core/src/main/scala/org/hyperledger/identus/shared/utils/Base64Utils.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.shared.utils 2 | 3 | import java.nio.charset.StandardCharsets 4 | import java.util.Base64 5 | 6 | object Base64Utils { 7 | def encodeURL(bytes: Array[Byte]): String = { 8 | Base64.getUrlEncoder.encodeToString(bytes) 9 | } 10 | 11 | def decodeUrlToString(encodedStr: String): String = { 12 | new String(Base64.getUrlDecoder.decode(encodedStr), StandardCharsets.UTF_8) 13 | } 14 | 15 | def decodeURL(string: String): Array[Byte] = { 16 | Base64.getUrlDecoder.decode(string) 17 | } 18 | 19 | def createDataUrl(data: Array[Byte], mimeType: String): String = { 20 | val encodedData = encodeURL(data) 21 | s"data:$mimeType;base64,$encodedData" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /shared/core/src/main/scala/org/hyperledger/identus/shared/utils/DurationOps.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.shared.utils 2 | 3 | import java.time.Duration 4 | 5 | object DurationOps { 6 | 7 | extension (d: Duration) def toMetricsSeconds: Double = d.toMillis.toDouble / 1000.0 8 | 9 | } 10 | -------------------------------------------------------------------------------- /shared/core/src/main/scala/org/hyperledger/identus/shared/utils/Traverse.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.shared.utils 2 | 3 | /** A lightweight DIY version of traverse to not rely on Cats because Scala3 + Cats implicits break the IDE compile 4 | * server making the development counterproductive. 5 | */ 6 | object Traverse { 7 | 8 | extension [A](ls: Seq[A]) { 9 | def traverse[E, B](f: A => Either[E, B]): Either[E, Seq[B]] = 10 | ls.foldRight[Either[E, List[B]]](Right(Nil))((i, acc) => acc.flatMap(ls => f(i).map(_ :: ls))) 11 | } 12 | 13 | extension [A, E](ls: Seq[Either[E, A]]) { 14 | def sequence: Either[E, Seq[A]] = ls.traverse(identity) 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /shared/core/src/main/scala/org/hyperledger/identus/shared/utils/proto/Path.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.shared.utils.proto 2 | 3 | /** Representation of sequence of field names pointing to some place in protobuf message 4 | */ 5 | case class Path(path: Vector[String]) extends AnyVal { 6 | def /(axis: String): Path = Path(path :+ axis) 7 | 8 | def dotRender: String = path.mkString(".") 9 | } 10 | 11 | object Path { 12 | def root: Path = Path(Vector.empty) 13 | def apply(): Path = root 14 | } 15 | -------------------------------------------------------------------------------- /shared/core/src/main/scala/org/hyperledger/identus/shared/validation/ValidationUtils.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.shared.validation 2 | 3 | import zio.prelude.* 4 | 5 | object ValidationUtils { 6 | 7 | def validateLengthOptional( 8 | fieldName: String, 9 | value: Option[String], 10 | min: Int, 11 | max: Int 12 | ): Validation[String, Option[String]] = { 13 | value match 14 | case None => Validation.succeed(value) 15 | case Some(v) => 16 | val len = v.length 17 | if (min <= len && max >= len) Validation.succeed(value) 18 | else Validation.fail(s"Invalid length for '$fieldName': expected=[$min -> $max], actual=$len") 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /shared/crypto/src/test/scala/org/hyperledger/identus/shared/crypto/ApolloSpecHelper.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.shared.crypto 2 | 3 | import zio.* 4 | 5 | trait ApolloSpecHelper { 6 | protected val apollo: Apollo = Apollo.default 7 | protected val apolloLayer: ULayer[Apollo] = Apollo.layer 8 | } 9 | -------------------------------------------------------------------------------- /shared/json/src/main/scala/org/hyperledger/identus/shared/json/JsonOps.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.shared.json 2 | 3 | import zio.json.ast.Json 4 | 5 | object JsonOps { 6 | extension (json: Json) { 7 | def removeNullValues: Json = json match 8 | case Json.Obj(fields) => 9 | Json.Obj(fields.collect { case (key, value) if value != Json.Null => key -> value.removeNullValues }) 10 | case Json.Arr(elements) => 11 | Json.Arr(elements.map(_.removeNullValues)) 12 | case other => other 13 | 14 | def removeField(name: String): Json = json match 15 | case Json.Obj(fields) => 16 | Json.Obj(fields.filterNot { case (key, value) => key == name }) 17 | case Json.Arr(elements) => 18 | Json.Arr(elements.map(_.removeField(name))) 19 | case other => other 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /shared/test/src/test/scala/org/hyperledger/identus/sharedtest/containers/KeycloakTestContainer.scala: -------------------------------------------------------------------------------- 1 | package org.hyperledger.identus.sharedtest.containers 2 | 3 | import org.testcontainers.utility.DockerImageName 4 | 5 | object KeycloakTestContainer { 6 | def keycloakContainer( 7 | imageName: String = "quay.io/keycloak/keycloak:23.0.7", 8 | ): KeycloakContainerCustom = { 9 | val isOnGithubRunner = sys.env.contains("GITHUB_NETWORK") 10 | val container = 11 | new KeycloakContainerCustom( 12 | dockerImageNameOverride = DockerImageName.parse(imageName), 13 | isOnGithubRunner = isOnGithubRunner 14 | ) 15 | 16 | sys.env.get("GITHUB_NETWORK").map { network => 17 | container.container.withNetworkMode(network) 18 | } 19 | 20 | container 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /tests/didcomm-tests/docker/initdb.js: -------------------------------------------------------------------------------- 1 | db.createUser({ 2 | user: 'admin', 3 | pwd: 'admin', 4 | roles: [ 5 | { role: 'readWrite', db: 'mediator' } 6 | ] 7 | }) 8 | 9 | const database = 'mediator' 10 | const collectionDidAccount = 'user.account' 11 | const collectionMessages = 'messages' 12 | const collectionMessagesSend = 'messages.outbound' 13 | 14 | // The current database to use. 15 | use(database) 16 | 17 | // Create collections. 18 | db.createCollection(collectionDidAccount) 19 | db.createCollection(collectionMessages) 20 | db.createCollection(collectionMessagesSend) 21 | 22 | // create index 23 | db.getCollection(collectionDidAccount).createIndex({ did: 1 }, { unique: true }) 24 | // Only enforce uniqueness on non-empty arrays 25 | db.getCollection(collectionDidAccount).createIndex({ alias: 1 }, { unique: true, partialFilterExpression: { 'alias.0': { $exists: true } } }) 26 | db.getCollection(collectionDidAccount).createIndex({ 'messagesRef.hash': 1, 'messagesRef.recipient': 1 }) 27 | -------------------------------------------------------------------------------- /tests/didcomm-tests/docker/postgres/init-script.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | set -u 5 | 6 | function create_user_and_database() { 7 | local database=$1 8 | local app_user=${database}-application-user 9 | echo " Creating user and database '$database'" 10 | psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" <<-EOSQL 11 | CREATE USER "$app_user" WITH PASSWORD 'password'; 12 | CREATE DATABASE $database; 13 | \c $database 14 | ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO "$app_user"; 15 | EOSQL 16 | } 17 | 18 | if [ -n "$POSTGRES_MULTIPLE_DATABASES" ]; then 19 | echo "Multiple database creation requested: $POSTGRES_MULTIPLE_DATABASES" 20 | for db in $(echo "$POSTGRES_MULTIPLE_DATABASES" | tr ',' ' '); do 21 | create_user_and_database "$db" 22 | done 23 | echo "Multiple databases created" 24 | fi 25 | -------------------------------------------------------------------------------- /tests/didcomm-tests/docker/postgres/max_conns.sql: -------------------------------------------------------------------------------- 1 | 2 | ALTER SYSTEM SET max_connections = 500; 3 | -------------------------------------------------------------------------------- /tests/didcomm-tests/docker/run.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | CLOUD_AGENT_VERSION=$1 6 | 7 | PORT="$PRISM_PORT" \ 8 | CLOUD_AGENT_VERSION="$CLOUD_AGENT_VERSION" \ 9 | docker compose \ 10 | -f "docker/docker-compose.yml" \ 11 | up -d --wait 12 | -------------------------------------------------------------------------------- /tests/didcomm-tests/docker/stop.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | CLOUD_AGENT_VERSION="$CLOUD_AGENT_VERSION" \ 6 | docker compose \ 7 | -f "./docker/docker-compose.yml" \ 8 | down -v 9 | -------------------------------------------------------------------------------- /tests/didcomm-tests/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "didcomm-tests", 3 | "version": "1.0.0", 4 | "description": "Test suite for executing didcomm tests", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "node node_modules/@amagyar-iohk/didcomm-test/dist/suite.spec.js" 8 | }, 9 | "author": "Allain Magyar", 10 | "license": "ISC", 11 | "dependencies": { 12 | "@amagyar-iohk/didcomm-test": "^1.0.4" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /tests/integration-tests/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*.{kt,kts}] 4 | ktlint_code_style = intellij_idea 5 | ij_kotlin_packages_to_use_import_on_demand = ** 6 | ij_kotlin_name_count_to_use_star_import = 3 7 | ij_kotlin_name_count_to_use_star_import_for_members = 3 8 | -------------------------------------------------------------------------------- /tests/integration-tests/.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | build/ 3 | !gradle/wrapper/gradle-wrapper.jar 4 | !**/src/main/**/build/ 5 | !**/src/test/**/build/ 6 | 7 | ### IntelliJ IDEA ### 8 | .idea/modules.xml 9 | .idea/jarRepositories.xml 10 | .idea/compiler.xml 11 | .idea/libraries/ 12 | *.iws 13 | *.iml 14 | *.ipr 15 | out/ 16 | !**/src/main/**/out/ 17 | !**/src/test/**/out/ 18 | .run/ 19 | 20 | ### Eclipse ### 21 | .apt_generated 22 | .classpath 23 | .factorypath 24 | .project 25 | .settings 26 | .springBeans 27 | .sts4-cache 28 | bin/ 29 | !**/src/main/**/bin/ 30 | !**/src/test/**/bin/ 31 | 32 | ### NetBeans ### 33 | /nbproject/private/ 34 | /nbbuild/ 35 | /dist/ 36 | /nbdist/ 37 | /.nb-gradle/ 38 | 39 | ### VS Code ### 40 | .vscode/ 41 | 42 | ### Mac OS ### 43 | .DS_Store 44 | -------------------------------------------------------------------------------- /tests/integration-tests/docs/static/functional_coverage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperledger-identus/cloud-agent/96f97f680d80f11399770a65100e0a915bca41d8/tests/integration-tests/docs/static/functional_coverage.png -------------------------------------------------------------------------------- /tests/integration-tests/docs/static/intellij.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperledger-identus/cloud-agent/96f97f680d80f11399770a65100e0a915bca41d8/tests/integration-tests/docs/static/intellij.png -------------------------------------------------------------------------------- /tests/integration-tests/docs/static/logs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperledger-identus/cloud-agent/96f97f680d80f11399770a65100e0a915bca41d8/tests/integration-tests/docs/static/logs.png -------------------------------------------------------------------------------- /tests/integration-tests/docs/static/report_summary.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperledger-identus/cloud-agent/96f97f680d80f11399770a65100e0a915bca41d8/tests/integration-tests/docs/static/report_summary.png -------------------------------------------------------------------------------- /tests/integration-tests/docs/static/rest_requests.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperledger-identus/cloud-agent/96f97f680d80f11399770a65100e0a915bca41d8/tests/integration-tests/docs/static/rest_requests.png -------------------------------------------------------------------------------- /tests/integration-tests/docs/static/screenplay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperledger-identus/cloud-agent/96f97f680d80f11399770a65100e0a915bca41d8/tests/integration-tests/docs/static/screenplay.png -------------------------------------------------------------------------------- /tests/integration-tests/docs/static/serenity_context.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperledger-identus/cloud-agent/96f97f680d80f11399770a65100e0a915bca41d8/tests/integration-tests/docs/static/serenity_context.png -------------------------------------------------------------------------------- /tests/integration-tests/docs/static/system_under_test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperledger-identus/cloud-agent/96f97f680d80f11399770a65100e0a915bca41d8/tests/integration-tests/docs/static/system_under_test.png -------------------------------------------------------------------------------- /tests/integration-tests/gradle.properties: -------------------------------------------------------------------------------- 1 | kotlin.code.style=official 2 | org.gradle.parallel=false 3 | org.gradle.workers.max=1 4 | -------------------------------------------------------------------------------- /tests/integration-tests/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperledger-identus/cloud-agent/96f97f680d80f11399770a65100e0a915bca41d8/tests/integration-tests/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /tests/integration-tests/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /tests/integration-tests/hosts_test: -------------------------------------------------------------------------------- 1 | 127.0.0.1 localhost 2 | 127.0.0.1 host.docker.internal -------------------------------------------------------------------------------- /tests/integration-tests/serenity.properties: -------------------------------------------------------------------------------- 1 | serenity.project.name=Identus Integration tests 2 | jira.url=https://input-output.atlassian.net 3 | jira.project=ATL 4 | serenity.reports.show.step.details=true 5 | serenity.report.show.manual.tests=false 6 | serenity.verbose.steps=true 7 | serenity.simplified.stack.traces=false 8 | serenity.report.accessibility=true 9 | json.pretty.printing=true 10 | serenity.console.colors=true 11 | -------------------------------------------------------------------------------- /tests/integration-tests/settings.gradle.kts: -------------------------------------------------------------------------------- 1 | rootProject.name = "integration-tests" 2 | -------------------------------------------------------------------------------- /tests/integration-tests/src/test/kotlin/IntegrationTestsRunner.kt: -------------------------------------------------------------------------------- 1 | import io.cucumber.junit.CucumberOptions 2 | import net.serenitybdd.cucumber.CucumberWithSerenity 3 | import org.junit.runner.RunWith 4 | 5 | @CucumberOptions( 6 | features = ["src/test/resources/features"], 7 | snippets = CucumberOptions.SnippetType.CAMELCASE, 8 | plugin = ["pretty"], 9 | tags = "not @flaky", 10 | ) 11 | @RunWith(CucumberWithSerenity::class) 12 | class IntegrationTestsRunner 13 | -------------------------------------------------------------------------------- /tests/integration-tests/src/test/kotlin/common/CredentialClaims.kt: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | enum class CredentialClaims { 4 | STUDENT_CLAIMS { 5 | override val claims: Map = linkedMapOf( 6 | "name" to "Name", 7 | "age" to 18, 8 | ) 9 | }, 10 | ID_CLAIMS { 11 | override val claims: Map = linkedMapOf( 12 | "firstName" to "John", 13 | "lastName" to "Doe", 14 | ) 15 | }, 16 | ANONCREDS_STUDENT_CLAIMS { 17 | override val claims: Map = linkedMapOf( 18 | "name" to "Bob", 19 | "age" to "21", 20 | "sex" to "M", 21 | ) 22 | }, 23 | ; 24 | 25 | abstract val claims: Map 26 | } 27 | -------------------------------------------------------------------------------- /tests/integration-tests/src/test/kotlin/common/CredentialType.kt: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | enum class CredentialType { 4 | JWT_VCDM_1_1 { 5 | override val format: String = "JWT" 6 | }, 7 | JWT_VCDM_2_0 { 8 | override val format: String = "JWT" 9 | }, 10 | ANONCREDS_V1 { 11 | override val format: String = "AnonCreds" 12 | }, 13 | SD_JWT_VCDM_1_1 { 14 | override val format: String = "SDJWT" 15 | }, 16 | ; 17 | 18 | abstract val format: String 19 | } 20 | -------------------------------------------------------------------------------- /tests/integration-tests/src/test/kotlin/common/DidDocumentTemplate.kt: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import org.hyperledger.identus.client.models.ManagedDIDKeyTemplate 4 | import org.hyperledger.identus.client.models.Service 5 | 6 | data class DidDocumentTemplate( 7 | val publicKeys: MutableList, 8 | val services: MutableList, 9 | ) 10 | -------------------------------------------------------------------------------- /tests/integration-tests/src/test/kotlin/config/AgentRole.kt: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | enum class AgentRole(val roleName: String) { 4 | Admin("admin"), 5 | Tenant("tenant"), 6 | } 7 | -------------------------------------------------------------------------------- /tests/integration-tests/src/test/kotlin/config/Config.kt: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import config.services.Agent 4 | import config.services.Service 5 | 6 | data class Config( 7 | val roles: List, 8 | val agents: List?, 9 | val services: Service?, 10 | ) 11 | -------------------------------------------------------------------------------- /tests/integration-tests/src/test/kotlin/config/Role.kt: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import java.net.URL 4 | 5 | data class Role( 6 | val name: String, 7 | val url: URL, 8 | val apikey: String?, 9 | val token: String?, 10 | val authHeader: String = "apikey", 11 | val webhook: Webhook?, 12 | val agentRole: AgentRole?, 13 | val oid4vciAuthServer: URL?, 14 | ) 15 | -------------------------------------------------------------------------------- /tests/integration-tests/src/test/kotlin/config/VaultAuthType.kt: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | enum class VaultAuthType { 4 | APP_ROLE, 5 | TOKEN, 6 | } 7 | -------------------------------------------------------------------------------- /tests/integration-tests/src/test/kotlin/config/Webhook.kt: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import com.sksamuel.hoplite.ConfigAlias 4 | import java.net.URL 5 | 6 | data class Webhook( 7 | val url: URL, 8 | @ConfigAlias("local_port") val localPort: Int? = null, 9 | @ConfigAlias("init_required") val initRequired: Boolean = true, 10 | ) 11 | -------------------------------------------------------------------------------- /tests/integration-tests/src/test/kotlin/config/services/Service.kt: -------------------------------------------------------------------------------- 1 | package config.services 2 | 3 | import com.sksamuel.hoplite.ConfigAlias 4 | 5 | data class Service( 6 | @ConfigAlias("prism_node") val prismNode: VerifiableDataRegistry?, 7 | val keycloak: Keycloak?, 8 | @ConfigAlias("keycloak_oid4vci") val keycloakOid4vci: Keycloak, 9 | val vault: Vault?, 10 | ) 11 | -------------------------------------------------------------------------------- /tests/integration-tests/src/test/kotlin/config/services/VerifiableDataRegistry.kt: -------------------------------------------------------------------------------- 1 | package config.services 2 | 3 | import com.sksamuel.hoplite.ConfigAlias 4 | import org.testcontainers.containers.ComposeContainer 5 | import org.testcontainers.containers.wait.strategy.Wait 6 | import java.io.File 7 | 8 | data class VerifiableDataRegistry( 9 | @ConfigAlias("http_port") val httpPort: Int, 10 | val version: String, 11 | ) : ServiceBase() { 12 | override val logServices: List = listOf("prism-node") 13 | private val vdrComposeFile = "src/test/resources/containers/vdr.yml" 14 | override val container: ComposeContainer = ComposeContainer(File(vdrComposeFile)).withEnv( 15 | mapOf( 16 | "PRISM_NODE_VERSION" to version, 17 | "PRISM_NODE_PORT" to httpPort.toString(), 18 | ), 19 | ).waitingFor( 20 | "prism-node", 21 | Wait.forLogMessage(".*Server started, listening on.*", 1), 22 | ) 23 | } 24 | -------------------------------------------------------------------------------- /tests/integration-tests/src/test/kotlin/interactions/AuthRestExtensions.kt: -------------------------------------------------------------------------------- 1 | package interactions 2 | 3 | import net.serenitybdd.screenplay.rest.interactions.RestInteraction 4 | 5 | fun Post.body(obj: Any): RestInteraction { 6 | return this.with { 7 | it.header("Content-Type", "application/json").body(obj) 8 | } 9 | } 10 | 11 | fun Patch.body(obj: Any): RestInteraction { 12 | return this.with { 13 | it.header("Content-Type", "application/json").body(obj) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /tests/integration-tests/src/test/kotlin/interactions/AuthRestInteraction.kt: -------------------------------------------------------------------------------- 1 | package interactions 2 | 3 | import io.restassured.specification.RequestSpecification 4 | import net.serenitybdd.screenplay.Actor 5 | import net.serenitybdd.screenplay.rest.interactions.RestInteraction 6 | 7 | abstract class AuthRestInteraction : RestInteraction() { 8 | 9 | fun specWithAuthHeaders(actor: T): RequestSpecification { 10 | val spec = rest() 11 | if (actor!!.recall("BEARER_TOKEN") != null) { 12 | spec.header("Authorization", "Bearer ${actor.recall("BEARER_TOKEN")}") 13 | } 14 | if (actor.recall("AUTH_KEY") != null) { 15 | spec.header(actor.recall("AUTH_HEADER"), actor.recall("AUTH_KEY")) 16 | } 17 | return spec 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /tests/integration-tests/src/test/kotlin/interactions/Delete.kt: -------------------------------------------------------------------------------- 1 | package interactions 2 | 3 | import net.serenitybdd.annotations.Step 4 | import net.serenitybdd.screenplay.Actor 5 | import net.serenitybdd.screenplay.Tasks 6 | import net.serenitybdd.screenplay.rest.abilities.CallAnApi 7 | 8 | /** 9 | * This class is a copy of the class Delete from serenity rest interactions 10 | * to add a custom authentication header to the request on-the-fly. 11 | */ 12 | open class Delete(private val resource: String) : AuthRestInteraction() { 13 | @Step("{0} executes a DELETE on the resource #resource") 14 | override fun performAs(actor: T) { 15 | specWithAuthHeaders(actor).delete(CallAnApi.`as`(actor).resolve(resource)) 16 | } 17 | 18 | companion object { 19 | fun from(resource: String?): Delete { 20 | return Tasks.instrumented(Delete::class.java, resource) 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /tests/integration-tests/src/test/kotlin/interactions/Get.kt: -------------------------------------------------------------------------------- 1 | package interactions 2 | 3 | import net.serenitybdd.annotations.Step 4 | import net.serenitybdd.screenplay.Actor 5 | import net.serenitybdd.screenplay.Tasks 6 | import net.serenitybdd.screenplay.rest.abilities.CallAnApi 7 | 8 | /** 9 | * This class is a copy of the class Get from serenity rest interactions 10 | * to add a custom authentication header to the request on-the-fly. 11 | */ 12 | open class Get(private val resource: String) : AuthRestInteraction() { 13 | @Step("{0} executes a GET on the resource #resource") 14 | override fun performAs(actor: T) { 15 | specWithAuthHeaders(actor).get(CallAnApi.`as`(actor).resolve(resource)) 16 | } 17 | 18 | companion object { 19 | fun resource(resource: String?): Get { 20 | return Tasks.instrumented(Get::class.java, resource) 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /tests/integration-tests/src/test/kotlin/interactions/Patch.kt: -------------------------------------------------------------------------------- 1 | package interactions 2 | 3 | import net.serenitybdd.annotations.Step 4 | import net.serenitybdd.screenplay.Actor 5 | import net.serenitybdd.screenplay.Tasks 6 | import net.serenitybdd.screenplay.rest.abilities.CallAnApi 7 | 8 | /** 9 | * This class is a copy of the class Patch from serenity rest interactions 10 | * to add a custom authentication header to the request on-the-fly. 11 | */ 12 | open class Patch(private val resource: String) : AuthRestInteraction() { 13 | @Step("{0} executes a PATCH on the resource #resource") 14 | override fun performAs(actor: T) { 15 | specWithAuthHeaders(actor).patch(CallAnApi.`as`(actor).resolve(resource)) 16 | } 17 | 18 | companion object { 19 | fun to(resource: String?): Patch { 20 | return Tasks.instrumented(Patch::class.java, resource) 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /tests/integration-tests/src/test/kotlin/interactions/Post.kt: -------------------------------------------------------------------------------- 1 | package interactions 2 | 3 | import net.serenitybdd.annotations.Step 4 | import net.serenitybdd.screenplay.Actor 5 | import net.serenitybdd.screenplay.Tasks 6 | import net.serenitybdd.screenplay.rest.abilities.CallAnApi 7 | 8 | /** 9 | * This class is a copy of the class Post from serenity rest interactions 10 | * to add a custom authentication header to the request on-the-fly. 11 | */ 12 | open class Post(private val resource: String) : AuthRestInteraction() { 13 | @Step("{0} executes a POST on the resource #resource") 14 | override fun performAs(actor: T) { 15 | specWithAuthHeaders(actor).post(CallAnApi.`as`(actor).resolve(resource)) 16 | } 17 | 18 | companion object { 19 | fun to(resource: String?): Post { 20 | return Tasks.instrumented(Post::class.java, resource) 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /tests/integration-tests/src/test/kotlin/interactions/Put.kt: -------------------------------------------------------------------------------- 1 | package interactions 2 | 3 | import net.serenitybdd.annotations.Step 4 | import net.serenitybdd.screenplay.Actor 5 | import net.serenitybdd.screenplay.Tasks 6 | import net.serenitybdd.screenplay.rest.abilities.CallAnApi 7 | 8 | /** 9 | * This class is a copy of the class Put from serenity rest interactions 10 | * to add a custom authentication header to the request on-the-fly. 11 | */ 12 | open class Put(private val resource: String) : AuthRestInteraction() { 13 | @Step("{0} executes a PUT on the resource #resource") 14 | override fun performAs(actor: T) { 15 | specWithAuthHeaders(actor).put(CallAnApi.`as`(actor).resolve(resource)) 16 | } 17 | 18 | companion object { 19 | fun to(resource: String?): Put { 20 | return Tasks.instrumented(Put::class.java, resource) 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /tests/integration-tests/src/test/kotlin/models/AnoncredsSchema.kt: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import com.google.gson.annotations.SerializedName 4 | 5 | class AnoncredsSchema( 6 | @SerializedName("name") 7 | val name: String, 8 | 9 | @SerializedName("version") 10 | val version: String, 11 | 12 | @SerializedName("issuerId") 13 | val issuerId: String, 14 | 15 | @SerializedName("attrNames") 16 | val attrNames: List, 17 | ) 18 | -------------------------------------------------------------------------------- /tests/integration-tests/src/test/kotlin/models/JsonSchema.kt: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import com.google.gson.annotations.SerializedName 4 | 5 | data class JsonSchema( 6 | @SerializedName("\$id") 7 | var id: String = "", 8 | 9 | @SerializedName("\$schema") 10 | var schema: String = "", 11 | 12 | @SerializedName("description") 13 | var description: String = "", 14 | 15 | @SerializedName("type") 16 | var type: String = "", 17 | 18 | @SerializedName("required") 19 | var required: List = emptyList(), 20 | 21 | @SerializedName("properties") 22 | val properties: MutableMap = mutableMapOf(), 23 | ) 24 | -------------------------------------------------------------------------------- /tests/integration-tests/src/test/kotlin/models/JsonSchemaProperty.kt: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import com.google.gson.annotations.SerializedName 4 | 5 | data class JsonSchemaProperty( 6 | @SerializedName("type") 7 | var type: String = "", 8 | ) 9 | -------------------------------------------------------------------------------- /tests/integration-tests/src/test/kotlin/models/SdJwtClaim.kt: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | data class SdJwtClaim( 4 | val salt: String, 5 | val key: String, 6 | val value: String, 7 | ) 8 | -------------------------------------------------------------------------------- /tests/integration-tests/src/test/kotlin/steps/multitenancy/EventsSteps.kt: -------------------------------------------------------------------------------- 1 | package steps.multitenancy 2 | 3 | import interactions.Post 4 | import io.iohk.atala.automation.serenity.ensure.Ensure 5 | import net.serenitybdd.screenplay.Actor 6 | import org.apache.http.HttpStatus 7 | import org.hyperledger.identus.client.models.CreateWebhookNotification 8 | 9 | class EventsSteps { 10 | fun registerNewWebhook(actor: Actor, webhookUrl: String) { 11 | actor.attemptsTo( 12 | Post.to("/events/webhooks") 13 | .with { 14 | it.body( 15 | CreateWebhookNotification(url = webhookUrl), 16 | ) 17 | }, 18 | ) 19 | 20 | actor.attemptsTo( 21 | Ensure.thatTheLastResponse().statusCode().isEqualTo(HttpStatus.SC_CREATED), 22 | ) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tests/integration-tests/src/test/resources/containers/keycloak-oid4vci.yml: -------------------------------------------------------------------------------- 1 | --- 2 | version: "3.8" 3 | 4 | services: 5 | keycloak: 6 | image: ghcr.io/hyperledger/identus-keycloak-plugins:0.2.0 7 | ports: 8 | - "${KEYCLOAK_HTTP_PORT}:8080" 9 | environment: 10 | KEYCLOAK_ADMIN: admin 11 | KEYCLOAK_ADMIN_PASSWORD: admin 12 | IDENTUS_URL: 13 | command: start-dev --health-enabled=true --hostname-url=http://host.docker.internal:${KEYCLOAK_HTTP_PORT} 14 | extra_hosts: 15 | - "host.docker.internal:host-gateway" 16 | -------------------------------------------------------------------------------- /tests/integration-tests/src/test/resources/containers/keycloak.yml: -------------------------------------------------------------------------------- 1 | --- 2 | version: "3.8" 3 | 4 | services: 5 | keycloak: 6 | image: quay.io/keycloak/keycloak:23.0.7 7 | ports: 8 | - "${KEYCLOAK_HTTP_PORT}:8080" 9 | environment: 10 | KEYCLOAK_ADMIN: admin 11 | KEYCLOAK_ADMIN_PASSWORD: admin 12 | command: start-dev --health-enabled=true --hostname-url=http://localhost:${KEYCLOAK_HTTP_PORT} 13 | -------------------------------------------------------------------------------- /tests/integration-tests/src/test/resources/containers/postgres/init-script.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | set -u 5 | 6 | function create_user_and_database() { 7 | local database=$1 8 | local app_user=${database}-application-user 9 | echo " Creating user and database '$database'" 10 | psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" <<-EOSQL 11 | CREATE USER "$app_user" WITH PASSWORD 'password'; 12 | CREATE DATABASE $database; 13 | \c $database 14 | ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO "$app_user"; 15 | EOSQL 16 | } 17 | 18 | if [ -n "$POSTGRES_MULTIPLE_DATABASES" ]; then 19 | echo "Multiple database creation requested: $POSTGRES_MULTIPLE_DATABASES" 20 | for db in $(echo $POSTGRES_MULTIPLE_DATABASES | tr ',' ' '); do 21 | create_user_and_database $db 22 | done 23 | echo "Multiple databases created" 24 | fi 25 | -------------------------------------------------------------------------------- /tests/integration-tests/src/test/resources/containers/postgres/max_conns.sql: -------------------------------------------------------------------------------- 1 | ALTER SYSTEM SET max_connections = 500; 2 | -------------------------------------------------------------------------------- /tests/integration-tests/src/test/resources/containers/vault.yml: -------------------------------------------------------------------------------- 1 | --- 2 | version: "3.8" 3 | 4 | services: 5 | 6 | vault: 7 | image: hashicorp/vault:1.13.3 8 | ports: 9 | - "${VAULT_PORT}:8200" 10 | environment: 11 | VAULT_ADDR: "http://0.0.0.0:8200" 12 | VAULT_DEV_ROOT_TOKEN_ID: root 13 | command: server -dev -dev-root-token-id=root 14 | cap_add: 15 | - IPC_LOCK 16 | healthcheck: 17 | test: ["CMD", "vault", "status"] 18 | interval: 10s 19 | timeout: 5s 20 | retries: 5 21 | -------------------------------------------------------------------------------- /tests/integration-tests/src/test/resources/containers/vdr.yml: -------------------------------------------------------------------------------- 1 | --- 2 | version: "3.8" 3 | 4 | services: 5 | node-db: 6 | image: postgres:13 7 | environment: 8 | POSTGRES_DB: "node_db" 9 | POSTGRES_USER: postgres 10 | POSTGRES_PASSWORD: postgres 11 | healthcheck: 12 | test: ["CMD", "pg_isready", "-U", "postgres", "-d", "node_db"] 13 | interval: 10s 14 | timeout: 5s 15 | retries: 5 16 | 17 | prism-node: 18 | image: docker.io/inputoutput/prism-node:${PRISM_NODE_VERSION} 19 | environment: 20 | NODE_PSQL_HOST: node-db:5432 21 | NODE_REFRESH_AND_SUBMIT_PERIOD: 1s 22 | NODE_MOVE_SCHEDULED_TO_PENDING_PERIOD: 1s 23 | ports: 24 | - "${PRISM_NODE_PORT}:50053" 25 | depends_on: 26 | node-db: 27 | condition: service_healthy 28 | -------------------------------------------------------------------------------- /tests/integration-tests/src/test/resources/features/connection/connection.feature: -------------------------------------------------------------------------------- 1 | @connection @create 2 | Feature: Agents connection 3 | 4 | Scenario: Establish a connection between two agents 5 | When Issuer generates a connection invitation to Holder 6 | And Holder sends a connection request to Issuer 7 | And Issuer receives the connection request and sends back the response 8 | And Holder receives the connection response 9 | Then Issuer and Holder have a connection 10 | -------------------------------------------------------------------------------- /tests/integration-tests/src/test/resources/features/credential/anoncred/issuance.feature: -------------------------------------------------------------------------------- 1 | @anoncred @issuance 2 | Feature: Issue Anoncred credential 3 | 4 | Background: 5 | Given Issuer and Holder have an existing connection 6 | And Issuer has a published DID for 'ANONCRED' 7 | And Holder has an unpublished DID for 'ANONCRED' 8 | 9 | Scenario: Issuing anoncred with published PRISM DID 10 | Given Issuer has an anoncred schema definition 11 | When Issuer offers anoncred to Holder 12 | And Holder receives the credential offer 13 | And Holder accepts anoncred credential offer 14 | And Issuer issues the credential 15 | Then Holder receives the issued credential 16 | -------------------------------------------------------------------------------- /tests/integration-tests/src/test/resources/features/credential/anoncred/present_proof.feature: -------------------------------------------------------------------------------- 1 | @anoncred @proof 2 | Feature: Present Proof Protocol 3 | 4 | Scenario: Holder presents anoncreds credential proof to verifier 5 | Given Issuer and Holder have an existing connection 6 | And Verifier and Holder have an existing connection 7 | And Issuer has a published DID for 'ANONCRED' 8 | And Holder has an unpublished DID for 'ANONCRED' 9 | And Issuer has an anoncred schema definition 10 | And Issuer offers anoncred to Holder 11 | And Holder receives the credential offer 12 | And Holder accepts anoncred credential offer 13 | And Issuer issues the credential 14 | And Holder receives the issued credential 15 | When Verifier sends a anoncreds request for proof presentation to Holder using credential definition issued by Issuer 16 | And Holder receives the presentation proof request 17 | And Holder accepts the anoncreds presentation request 18 | # Then Verifier has the proof verified FIXME 19 | -------------------------------------------------------------------------------- /tests/integration-tests/src/test/resources/features/did/deactivate_did.feature: -------------------------------------------------------------------------------- 1 | @DLT @did @deactivate 2 | Feature: Deactivate DID 3 | 4 | Scenario: Deactivate DID 5 | Given Issuer creates empty unpublished DID 6 | And Issuer publishes DID to ledger 7 | When Issuer deactivates PRISM DID 8 | Then He sees that PRISM DID is successfully deactivated 9 | -------------------------------------------------------------------------------- /tests/integration-tests/src/test/resources/features/did/listing_did.feature: -------------------------------------------------------------------------------- 1 | @did @list 2 | Feature: DID listing 3 | 4 | Scenario: Listing multiple PRISM DIDs 5 | Given Issuer creates 5 PRISM DIDs 6 | When He lists all PRISM DIDs 7 | Then He sees the list contains all created DIDs 8 | -------------------------------------------------------------------------------- /tests/integration-tests/src/test/resources/features/system/health_endpoint.feature: -------------------------------------------------------------------------------- 1 | @system @smoke 2 | Feature: Agent Health Endpoint 3 | 4 | Scenario: The runtime version can be retrieved from the Health Endpoint 5 | When Issuer makes a request to the health endpoint 6 | Then Issuer knows what version of the service is running 7 | -------------------------------------------------------------------------------- /tests/integration-tests/src/test/resources/features/system/metrics_endpoint.feature: -------------------------------------------------------------------------------- 1 | @system @smoke 2 | Feature: Metrics Endpoint 3 | 4 | Scenario: Background job metrics are available to scrape 5 | When Issuer makes a request to the metrics endpoint 6 | Then Issuer sees that the metrics contain background job stats 7 | -------------------------------------------------------------------------------- /tests/integration-tests/src/test/resources/features/verificationpolicies/verification_policies.feature: -------------------------------------------------------------------------------- 1 | @verificationpolicy 2 | Feature: Verification Policies 3 | 4 | Scenario: Successful verification policy creation 5 | When Issuer creates a new verification policy 6 | Then He sees new verification policy is available 7 | When He updates a new verification policy 8 | Then He sees the updated verification policy is available 9 | -------------------------------------------------------------------------------- /tests/integration-tests/src/test/resources/logback-test.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /tests/performance-tests/agent-performance-tests-k6/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/env", "@babel/typescript"], 3 | "plugins": [ 4 | "@babel/proposal-class-properties", 5 | 6 | "@babel/proposal-object-rest-spread" 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /tests/performance-tests/agent-performance-tests-k6/.env: -------------------------------------------------------------------------------- 1 | AGENT_VERSION=1.40.1-SNAPSHOT 2 | PRISM_NODE_VERSION=2.5.0 3 | VAULT_DEV_ROOT_TOKEN_ID=root 4 | -------------------------------------------------------------------------------- /tests/performance-tests/agent-performance-tests-k6/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | yarn-error.log 3 | dist 4 | -------------------------------------------------------------------------------- /tests/performance-tests/agent-performance-tests-k6/.npmrc: -------------------------------------------------------------------------------- 1 | //npm.pkg.github.com/:_authToken=${GITHUB_TOKEN} 2 | -------------------------------------------------------------------------------- /tests/performance-tests/agent-performance-tests-k6/.yarnrc: -------------------------------------------------------------------------------- 1 | registry "https://registry.npmjs.org" 2 | -------------------------------------------------------------------------------- /tests/performance-tests/agent-performance-tests-k6/src/actors/index.ts: -------------------------------------------------------------------------------- 1 | import { Actor } from './Actor' 2 | import { Holder } from './Holder' 3 | import { Issuer } from './Issuer' 4 | import { Verifier } from './Verifier' 5 | export { Actor, Holder, Issuer, Verifier } 6 | -------------------------------------------------------------------------------- /tests/performance-tests/agent-performance-tests-k6/src/tests/common.ts: -------------------------------------------------------------------------------- 1 | import { describe } from '../k6chaijs.js' 2 | import { Holder, Issuer } from '../actors' 3 | 4 | export const issuer = new Issuer() 5 | export const holder = new Holder() 6 | 7 | export function connectionFlow () { 8 | describe('Issuer initiates connection with Holder', function () { 9 | issuer.createHolderConnection() 10 | }) && 11 | 12 | describe('Holder accepts connection with Issuer', function () { 13 | holder.acceptIssuerConnection(issuer.connectionWithHolder!.invitation) 14 | }) && 15 | 16 | describe('Issuer finalizes connection with Holder', function () { 17 | issuer.finalizeConnectionWithHolder() 18 | }) && 19 | 20 | describe('Holder finalizes connection with Issuer', function () { 21 | holder.finalizeConnectionWithIssuer() 22 | }) 23 | } 24 | -------------------------------------------------------------------------------- /tests/performance-tests/agent-performance-tests-k6/src/tests/dids/create-prism-did-test.ts: -------------------------------------------------------------------------------- 1 | import { Options } from 'k6/options' 2 | import { Issuer } from '../../actors' 3 | import { defaultOptions } from '../../scenarios/default' 4 | import merge from 'ts-deepmerge' 5 | import { describe } from '../../k6chaijs.js' 6 | 7 | export const localOptions: Options = { 8 | thresholds: { 9 | 'group_duration{group:::Issuer create unpublished DID}': ['avg < 5000'] 10 | } 11 | } 12 | export const options: Options = merge(localOptions, defaultOptions) 13 | 14 | const issuer = new Issuer() 15 | 16 | export default () => { 17 | describe('Issuer create unpublished DID', function () { 18 | issuer.createUnpublishedDid() 19 | }) 20 | } 21 | -------------------------------------------------------------------------------- /tests/performance-tests/agent-performance-tests-k6/src/tests/dids/did-publishing-test.ts: -------------------------------------------------------------------------------- 1 | import { Options } from 'k6/options' 2 | import { Issuer } from '../../actors' 3 | import merge from 'ts-deepmerge' 4 | import { defaultOptions } from '../../scenarios/default' 5 | import { describe } from '../../k6chaijs.js' 6 | 7 | export const localOptions: Options = { 8 | thresholds: { 9 | 'group_duration{group:::Issuer create published DID}': ['avg < 5000'] 10 | } 11 | } 12 | export const options: Options = merge(localOptions, defaultOptions) 13 | 14 | const issuer = new Issuer() 15 | 16 | export default () => { 17 | describe('Issuer create published DID', function () { 18 | issuer.createUnpublishedDid() 19 | issuer.publishDid() 20 | }) 21 | } 22 | -------------------------------------------------------------------------------- /tests/performance-tests/agent-performance-tests-k6/src/tests/flows/connection-flow-test.ts: -------------------------------------------------------------------------------- 1 | import { Options } from 'k6/options' 2 | import { connectionFlow } from '../common' 3 | import { defaultOptions } from '../../scenarios/default' 4 | import merge from 'ts-deepmerge' 5 | 6 | export const localOptions: Options = { 7 | thresholds: { 8 | 'group_duration{group:::Issuer initiates connection with Holder}': [ 9 | 'avg<10000' 10 | ], 11 | 'group_duration{group:::Holder accepts connection with Issuer}': [ 12 | 'avg<10000' 13 | ], 14 | 'group_duration{group:::Issuer finalizes connection with Holder}': [ 15 | 'avg<10000' 16 | ], 17 | 'group_duration{group:::Holder finalizes connection with Issuer}': [ 18 | 'avg<10000' 19 | ] 20 | } 21 | } 22 | export const options: Options = merge(localOptions, defaultOptions) 23 | 24 | export default () => { 25 | connectionFlow() 26 | } 27 | -------------------------------------------------------------------------------- /tests/performance-tests/agent-performance-tests-k6/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "moduleResolution": "node", 5 | "module": "commonjs", 6 | "noEmit": true, 7 | "allowJs": true, 8 | "removeComments": false, 9 | 10 | "strict": true, 11 | "noImplicitAny": true, 12 | "noImplicitThis": true, 13 | 14 | "noUnusedLocals": true, 15 | "noUnusedParameters": true, 16 | "noImplicitReturns": true, 17 | "noFallthroughCasesInSwitch": true, 18 | 19 | "allowSyntheticDefaultImports": true, 20 | "esModuleInterop": true, 21 | "experimentalDecorators": true, 22 | "emitDecoratorMetadata": true, 23 | 24 | "skipLibCheck": true 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tests/performance-tests/agent-performance-tests/.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | **/build/ 3 | !src/**/build/ 4 | 5 | # Ignore Gradle GUI config 6 | gradle-app.setting 7 | 8 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) 9 | !gradle-wrapper.jar 10 | 11 | # Avoid ignore Gradle wrappper properties 12 | !gradle-wrapper.properties 13 | 14 | # Cache of project 15 | .gradletasknamecache 16 | 17 | # Eclipse Gradle plugin generated files 18 | # Eclipse Core 19 | .project 20 | # JDT-specific (Eclipse Java Development Tools) 21 | .classpath 22 | -------------------------------------------------------------------------------- /tests/performance-tests/agent-performance-tests/bin/gatling/simulations/ConnectionSimulation.kt: -------------------------------------------------------------------------------- 1 | package simulations 2 | 3 | import io.gatling.javaapi.core.* 4 | import io.gatling.javaapi.core.CoreDsl.* 5 | import steps.ConnectionSteps 6 | 7 | /** 8 | * Simulation for Atala PRISM V2 Connection protocol 9 | */ 10 | class ConnectionSimulation : Simulation() { 11 | 12 | private val settingUpConnection = scenario("Setting up connection").exec( 13 | ConnectionSteps.generateInvitation(), 14 | ConnectionSteps.inviteeSendsConnectionRequest(), 15 | ConnectionSteps.inviterReceivesTheConnectionRequestAndSendsTheConnectionResponseToInvitee(), 16 | ConnectionSteps.inviteeAchievesConnectionResponse() 17 | ) 18 | 19 | init { 20 | setUp( 21 | settingUpConnection 22 | .injectOpen(rampUsers(1) 23 | .during(1)) 24 | ) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tests/performance-tests/agent-performance-tests/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import org.jetbrains.kotlin.gradle.tasks.KotlinCompile 2 | 3 | plugins { 4 | kotlin("jvm") version "1.7.21" 5 | id("io.gatling.gradle") version "3.9.0.2" 6 | } 7 | 8 | group = "io.atala.prism" 9 | version = "0.1.0" 10 | 11 | repositories { 12 | mavenCentral() 13 | } 14 | 15 | gatling { 16 | logLevel = "WARN" 17 | // set to 'ALL' for all HTTP traffic in TRACE, 'FAILURES' for failed HTTP traffic in DEBUG 18 | logHttp = io.gatling.gradle.LogHttp.NONE 19 | } 20 | 21 | dependencies { 22 | testImplementation(kotlin("test")) 23 | } 24 | 25 | tasks.test { 26 | useJUnitPlatform() 27 | } 28 | 29 | tasks.withType { 30 | kotlinOptions.jvmTarget = "1.8" 31 | } 32 | -------------------------------------------------------------------------------- /tests/performance-tests/agent-performance-tests/gradle.properties: -------------------------------------------------------------------------------- 1 | kotlin.code.style=official 2 | -------------------------------------------------------------------------------- /tests/performance-tests/agent-performance-tests/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperledger-identus/cloud-agent/96f97f680d80f11399770a65100e0a915bca41d8/tests/performance-tests/agent-performance-tests/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /tests/performance-tests/agent-performance-tests/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /tests/performance-tests/agent-performance-tests/settings.gradle.kts: -------------------------------------------------------------------------------- 1 | 2 | rootProject.name = "agent-performance-tests" 3 | 4 | -------------------------------------------------------------------------------- /tests/performance-tests/agent-performance-tests/src/gatling/kotlin/simulations/ConnectionSimulation.kt: -------------------------------------------------------------------------------- 1 | package simulations 2 | 3 | import io.gatling.javaapi.core.* 4 | import io.gatling.javaapi.core.CoreDsl.* 5 | import steps.ConnectionSteps 6 | 7 | /** 8 | * Simulation for Atala PRISM V2 Connection protocol 9 | */ 10 | class ConnectionSimulation : Simulation() { 11 | 12 | private val settingUpConnection = scenario("Setting up connection").exec( 13 | ConnectionSteps.generateInvitation(), 14 | ConnectionSteps.inviteeSendsConnectionRequest(), 15 | ConnectionSteps.inviterReceivesTheConnectionRequestAndSendsTheConnectionResponseToInvitee(), 16 | ConnectionSteps.inviteeAchievesConnectionResponse() 17 | ) 18 | 19 | init { 20 | setUp( 21 | settingUpConnection 22 | .injectOpen(rampUsers(1) 23 | .during(1)) 24 | ) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /version.sbt: -------------------------------------------------------------------------------- 1 | ThisBuild / version := "2.0.1-SNAPSHOT" 2 | --------------------------------------------------------------------------------