From 49f7ab3d0473d820c37dc7f4f944cf1c2cae2a25 Mon Sep 17 00:00:00 2001 From: patlo-iog Date: Thu, 19 Sep 2024 12:01:44 +0700 Subject: [PATCH] feat: add presentation-exchange endpoints (#1365) Signed-off-by: Pat Losoponkul --- .../castor/core/model/ProtoModelHelper.scala | 6 +- .../castor/core/model/did/PublicKey.scala | 3 +- .../castor/core/service/MockDIDService.scala | 3 +- .../core/util/DIDOperationValidatorSpec.scala | 3 +- .../identus/castor/core/util/GenUtils.scala | 3 +- .../identus/agent/server/CloudAgentApp.scala | 6 +- .../identus/agent/server/MainApp.scala | 7 ++ .../identus/agent/server/http/DocModels.scala | 4 +- .../agent/server/jobs/StatusListJobs.scala | 1 - .../controller/DIDController.scala | 0 .../controller/DIDEndpoints.scala | 0 .../controller/DIDRegistrarController.scala | 0 .../controller/DIDRegistrarEndpoints.scala | 0 .../DIDRegistrarServerEndpoints.scala | 0 .../controller/DIDServerEndpoints.scala | 0 .../controller/http/DIDDocument.scala | 0 .../controller/http/DIDDocumentMetadata.scala | 0 .../controller/http/DIDInput.scala | 0 .../http/DIDResolutionMetadata.scala | 0 .../controller/http/DIDResolutionResult.scala | 0 .../controller/http/ManagedDID.scala | 0 .../controller/http/PublicKeyJwk.scala | 0 .../controller/http/ScheduledOperation.scala | 0 .../controller/http/Service.scala | 0 .../controller/http/UpdateManagedDID.scala | 0 .../controller/http/VerificationMethod.scala | 0 .../controller/DIDCommControllerError.scala | 3 +- .../prex/PresentationExchangeEndpoints.scala | 97 +++++++++++++++++++ .../PresentationExchangeServerEndpoints.scala | 61 ++++++++++++ .../PresentationExchangeController.scala | 62 ++++++++++++ .../prex/http/PresentationDefinition.scala | 42 ++++++++ .../PresentationExchangeTapirSchemas.scala | 24 +++++ .../identus/api/util/Tapir2StaticOAS.scala | 2 + .../controller/IssueControllerImplSpec.scala | 3 +- .../walletapi/service/ManagedDIDService.scala | 3 +- .../service/ManagedDIDServiceImpl.scala | 3 +- .../service/handler/DIDCreateHandler.scala | 3 +- .../service/handler/DIDUpdateHandler.scala | 3 +- .../service/handler/PublicationHandler.scala | 3 +- .../sql/JdbcDIDNonSecretStorage.scala | 3 +- .../walletapi/sql/JdbcDIDSecretStorage.scala | 3 +- .../storage/DIDNonSecretStorage.scala | 3 +- .../walletapi/storage/DIDSecretStorage.scala | 3 +- .../agent/walletapi/util/KeyResolver.scala | 3 +- .../walletapi/util/OperationFactory.scala | 3 +- .../vault/VaultDIDSecretStorage.scala | 3 +- .../service/ManagedDIDServiceSpec.scala | 3 +- .../storage/DIDSecretStorageSpec.scala | 3 +- .../storage/MockDIDNonSecretStorage.scala | 3 +- .../walletapi/storage/StorageSpecHelper.scala | 3 +- .../walletapi/util/OperationFactorySpec.scala | 3 +- .../model/error/CredentialServiceError.scala | 3 +- .../PresentationExchangeRepository.scala | 16 +++ .../service/PresentationExchangeService.scala | 44 +++++++++ .../PresentationExchangeServiceImpl.scala | 41 ++++++++ .../pollux/prex/PresentationDefinition.scala | 29 ++++++ .../PresentationDefinitionValidator.scala | 3 +- .../V27__presentation_definition_table.sql | 16 +++ .../sql/model/db/PresentationDefinition.scala | 69 +++++++++++++ .../JdbcPresentationExchangeRepository.scala | 67 +++++++++++++ .../identus/shared/models/KeyId.scala | 2 +- 61 files changed, 614 insertions(+), 57 deletions(-) rename cloud-agent/service/server/src/main/scala/org/hyperledger/identus/{ => castor}/controller/DIDController.scala (100%) rename cloud-agent/service/server/src/main/scala/org/hyperledger/identus/{ => castor}/controller/DIDEndpoints.scala (100%) rename cloud-agent/service/server/src/main/scala/org/hyperledger/identus/{ => castor}/controller/DIDRegistrarController.scala (100%) rename cloud-agent/service/server/src/main/scala/org/hyperledger/identus/{ => castor}/controller/DIDRegistrarEndpoints.scala (100%) rename cloud-agent/service/server/src/main/scala/org/hyperledger/identus/{ => castor}/controller/DIDRegistrarServerEndpoints.scala (100%) rename cloud-agent/service/server/src/main/scala/org/hyperledger/identus/{ => castor}/controller/DIDServerEndpoints.scala (100%) rename cloud-agent/service/server/src/main/scala/org/hyperledger/identus/{ => castor}/controller/http/DIDDocument.scala (100%) rename cloud-agent/service/server/src/main/scala/org/hyperledger/identus/{ => castor}/controller/http/DIDDocumentMetadata.scala (100%) rename cloud-agent/service/server/src/main/scala/org/hyperledger/identus/{ => castor}/controller/http/DIDInput.scala (100%) rename cloud-agent/service/server/src/main/scala/org/hyperledger/identus/{ => castor}/controller/http/DIDResolutionMetadata.scala (100%) rename cloud-agent/service/server/src/main/scala/org/hyperledger/identus/{ => castor}/controller/http/DIDResolutionResult.scala (100%) rename cloud-agent/service/server/src/main/scala/org/hyperledger/identus/{ => castor}/controller/http/ManagedDID.scala (100%) rename cloud-agent/service/server/src/main/scala/org/hyperledger/identus/{ => castor}/controller/http/PublicKeyJwk.scala (100%) rename cloud-agent/service/server/src/main/scala/org/hyperledger/identus/{ => castor}/controller/http/ScheduledOperation.scala (100%) rename cloud-agent/service/server/src/main/scala/org/hyperledger/identus/{ => castor}/controller/http/Service.scala (100%) rename cloud-agent/service/server/src/main/scala/org/hyperledger/identus/{ => castor}/controller/http/UpdateManagedDID.scala (100%) rename cloud-agent/service/server/src/main/scala/org/hyperledger/identus/{ => castor}/controller/http/VerificationMethod.scala (100%) create mode 100644 cloud-agent/service/server/src/main/scala/org/hyperledger/identus/pollux/prex/PresentationExchangeEndpoints.scala create mode 100644 cloud-agent/service/server/src/main/scala/org/hyperledger/identus/pollux/prex/PresentationExchangeServerEndpoints.scala create mode 100644 cloud-agent/service/server/src/main/scala/org/hyperledger/identus/pollux/prex/controller/PresentationExchangeController.scala create mode 100644 cloud-agent/service/server/src/main/scala/org/hyperledger/identus/pollux/prex/http/PresentationDefinition.scala create mode 100644 cloud-agent/service/server/src/main/scala/org/hyperledger/identus/pollux/prex/http/PresentationExchangeTapirSchemas.scala create mode 100644 pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/repository/PresentationExchangeRepository.scala create mode 100644 pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/service/PresentationExchangeService.scala create mode 100644 pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/service/PresentationExchangeServiceImpl.scala create mode 100644 pollux/sql-doobie/src/main/resources/sql/pollux/V27__presentation_definition_table.sql create mode 100644 pollux/sql-doobie/src/main/scala/org/hyperledger/identus/pollux/sql/model/db/PresentationDefinition.scala create mode 100644 pollux/sql-doobie/src/main/scala/org/hyperledger/identus/pollux/sql/repository/JdbcPresentationExchangeRepository.scala diff --git a/castor/src/main/scala/org/hyperledger/identus/castor/core/model/ProtoModelHelper.scala b/castor/src/main/scala/org/hyperledger/identus/castor/core/model/ProtoModelHelper.scala index cd12aeeb4b..2e66913279 100644 --- a/castor/src/main/scala/org/hyperledger/identus/castor/core/model/ProtoModelHelper.scala +++ b/castor/src/main/scala/org/hyperledger/identus/castor/core/model/ProtoModelHelper.scala @@ -24,10 +24,8 @@ import org.hyperledger.identus.castor.core.model.did.{ UpdateDIDAction, VerificationRelationship } -import org.hyperledger.identus.castor.core.model.did.ServiceEndpoint.value -import org.hyperledger.identus.castor.core.model.did.ServiceEndpoint.UriOrJsonEndpoint -import org.hyperledger.identus.shared.models.Base64UrlString -import org.hyperledger.identus.shared.models.KeyId +import org.hyperledger.identus.castor.core.model.did.ServiceEndpoint.{value, UriOrJsonEndpoint} +import org.hyperledger.identus.shared.models.{Base64UrlString, KeyId} import org.hyperledger.identus.shared.utils.Traverse.* import zio.* diff --git a/castor/src/main/scala/org/hyperledger/identus/castor/core/model/did/PublicKey.scala b/castor/src/main/scala/org/hyperledger/identus/castor/core/model/did/PublicKey.scala index da27a541c2..ec79f7fd2b 100644 --- a/castor/src/main/scala/org/hyperledger/identus/castor/core/model/did/PublicKey.scala +++ b/castor/src/main/scala/org/hyperledger/identus/castor/core/model/did/PublicKey.scala @@ -1,7 +1,6 @@ package org.hyperledger.identus.castor.core.model.did -import org.hyperledger.identus.shared.models.Base64UrlString -import org.hyperledger.identus.shared.models.KeyId +import org.hyperledger.identus.shared.models.{Base64UrlString, KeyId} final case class PublicKey( id: KeyId, diff --git a/castor/src/test/scala/org/hyperledger/identus/castor/core/service/MockDIDService.scala b/castor/src/test/scala/org/hyperledger/identus/castor/core/service/MockDIDService.scala index ae128f47ed..b911ff9a92 100644 --- a/castor/src/test/scala/org/hyperledger/identus/castor/core/service/MockDIDService.scala +++ b/castor/src/test/scala/org/hyperledger/identus/castor/core/service/MockDIDService.scala @@ -3,8 +3,7 @@ package org.hyperledger.identus.castor.core.service import org.hyperledger.identus.castor.core.model.did.* import org.hyperledger.identus.castor.core.model.error import org.hyperledger.identus.shared.crypto.{Apollo, Secp256k1KeyPair} -import org.hyperledger.identus.shared.models.Base64UrlString -import org.hyperledger.identus.shared.models.KeyId +import org.hyperledger.identus.shared.models.{Base64UrlString, KeyId} import zio.{mock, IO, URLayer, ZIO, ZLayer} import zio.mock.{Expectation, Mock, Proxy} import zio.test.Assertion diff --git a/castor/src/test/scala/org/hyperledger/identus/castor/core/util/DIDOperationValidatorSpec.scala b/castor/src/test/scala/org/hyperledger/identus/castor/core/util/DIDOperationValidatorSpec.scala index 72957513b0..7e2e8fee99 100644 --- a/castor/src/test/scala/org/hyperledger/identus/castor/core/util/DIDOperationValidatorSpec.scala +++ b/castor/src/test/scala/org/hyperledger/identus/castor/core/util/DIDOperationValidatorSpec.scala @@ -3,8 +3,7 @@ package org.hyperledger.identus.castor.core.util import org.hyperledger.identus.castor.core.model.did.* import org.hyperledger.identus.castor.core.model.error.OperationValidationError import org.hyperledger.identus.castor.core.util.DIDOperationValidator.Config -import org.hyperledger.identus.shared.models.Base64UrlString -import org.hyperledger.identus.shared.models.KeyId +import org.hyperledger.identus.shared.models.{Base64UrlString, KeyId} import zio.* import zio.test.* import zio.test.Assertion.* diff --git a/castor/src/test/scala/org/hyperledger/identus/castor/core/util/GenUtils.scala b/castor/src/test/scala/org/hyperledger/identus/castor/core/util/GenUtils.scala index 29622b3b70..e25519ebc2 100644 --- a/castor/src/test/scala/org/hyperledger/identus/castor/core/util/GenUtils.scala +++ b/castor/src/test/scala/org/hyperledger/identus/castor/core/util/GenUtils.scala @@ -4,8 +4,7 @@ import io.circe.Json import org.hyperledger.identus.castor.core.model.did.* import org.hyperledger.identus.castor.core.model.did.ServiceEndpoint.{UriOrJsonEndpoint, UriValue} import org.hyperledger.identus.shared.crypto.Apollo -import org.hyperledger.identus.shared.models.Base64UrlString -import org.hyperledger.identus.shared.models.KeyId +import org.hyperledger.identus.shared.models.{Base64UrlString, KeyId} import zio.* import zio.test.Gen diff --git a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/agent/server/CloudAgentApp.scala b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/agent/server/CloudAgentApp.scala index 5503393c1a..ced294305e 100644 --- a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/agent/server/CloudAgentApp.scala +++ b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/agent/server/CloudAgentApp.scala @@ -26,6 +26,7 @@ import org.hyperledger.identus.pollux.credentialschema.{ SchemaRegistryServerEndpoints, VerificationPolicyServerEndpoints } +import org.hyperledger.identus.pollux.prex.PresentationExchangeServerEndpoints import org.hyperledger.identus.pollux.vc.jwt.DidResolver as JwtDidResolver import org.hyperledger.identus.presentproof.controller.PresentProofServerEndpoints import org.hyperledger.identus.resolvers.DIDResolver @@ -47,7 +48,7 @@ object CloudAgentApp { _ <- syncRevocationStatusListsJob.debug.fork _ <- AgentHttpServer.run.tapDefect(e => ZIO.logErrorCause("Agent HTTP Server failure", e)).fork fiber <- DidCommHttpServer.run.tapDefect(e => ZIO.logErrorCause("DIDComm HTTP Server failure", e)).fork - _ <- WebhookPublisher.layer.build.map(_.get[WebhookPublisher]).flatMap(_.run.debug.fork) + _ <- WebhookPublisher.layer.build.map(_.get[WebhookPublisher]).flatMap(_.run.fork) _ <- fiber.join *> ZIO.log(s"Server End") _ <- ZIO.never } yield () @@ -137,6 +138,7 @@ object AgentHttpServer { allWalletManagementEndpoints <- WalletManagementServerEndpoints.all allEventEndpoints <- EventServerEndpoints.all allOIDCEndpoints <- CredentialIssuerServerEndpoints.all + allPresentationExchangeEndpoints <- PresentationExchangeServerEndpoints.all } yield allCredentialDefinitionRegistryEndpoints ++ allSchemaRegistryEndpoints ++ allVerificationPolicyEndpoints ++ @@ -147,11 +149,13 @@ object AgentHttpServer { allStatusListEndpoints ++ allPresentProofEndpoints ++ allVcVerificationEndpoints ++ + allPresentationExchangeEndpoints ++ allSystemEndpoints ++ allEntityEndpoints ++ allWalletManagementEndpoints ++ allEventEndpoints ++ allOIDCEndpoints + def run = for { allEndpoints <- agentRESTServiceEndpoints diff --git a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/agent/server/MainApp.scala b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/agent/server/MainApp.scala index a2a69e8d9e..10b4928d25 100644 --- a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/agent/server/MainApp.scala +++ b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/agent/server/MainApp.scala @@ -46,12 +46,15 @@ import org.hyperledger.identus.pollux.credentialschema.controller.{ CredentialSchemaControllerImpl, VerificationPolicyControllerImpl } +import org.hyperledger.identus.pollux.prex.controller.PresentationExchangeControllerImpl +import org.hyperledger.identus.pollux.prex.PresentationDefinitionValidatorImpl import org.hyperledger.identus.pollux.sql.repository.{ JdbcCredentialDefinitionRepository, JdbcCredentialRepository, JdbcCredentialSchemaRepository, JdbcCredentialStatusListRepository, JdbcOID4VCIIssuerMetadataRepository, + JdbcPresentationExchangeRepository, JdbcPresentationRepository, JdbcVerificationPolicyRepository, Migrations as PolluxMigrations @@ -169,12 +172,14 @@ object MainApp extends ZIOAppDefault { WalletManagementControllerImpl.layer, EventControllerImpl.layer, DIDCommControllerImpl.layer, + PresentationExchangeControllerImpl.layer, // domain AppModule.apolloLayer, AppModule.didJwtResolverLayer, DIDOperationValidator.layer(), DIDResolver.layer, HttpURIDereferencerImpl.layer, + PresentationDefinitionValidatorImpl.layer, // service ConnectionServiceImpl.layer >>> ConnectionServiceNotifier.layer, CredentialSchemaServiceImpl.layer, @@ -188,6 +193,7 @@ object MainApp extends ZIOAppDefault { VerificationPolicyServiceImpl.layer, WalletManagementServiceImpl.layer, VcVerificationServiceImpl.layer, + PresentationExchangeServiceImpl.layer, // authentication AppModule.builtInAuthenticatorLayer, AppModule.keycloakAuthenticatorLayer, @@ -211,6 +217,7 @@ object MainApp extends ZIOAppDefault { RepoModule.polluxContextAwareTransactorLayer ++ RepoModule.polluxTransactorLayer >>> JdbcCredentialDefinitionRepository.layer, RepoModule.polluxContextAwareTransactorLayer ++ RepoModule.polluxTransactorLayer >>> JdbcPresentationRepository.layer, RepoModule.polluxContextAwareTransactorLayer ++ RepoModule.polluxTransactorLayer >>> JdbcOID4VCIIssuerMetadataRepository.layer, + RepoModule.polluxContextAwareTransactorLayer ++ RepoModule.polluxTransactorLayer >>> JdbcPresentationExchangeRepository.layer, RepoModule.polluxContextAwareTransactorLayer >>> JdbcVerificationPolicyRepository.layer, // oidc CredentialIssuerControllerImpl.layer, diff --git a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/agent/server/http/DocModels.scala b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/agent/server/http/DocModels.scala index 0faceda3cf..e13321a552 100644 --- a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/agent/server/http/DocModels.scala +++ b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/agent/server/http/DocModels.scala @@ -8,6 +8,7 @@ import org.hyperledger.identus.iam.wallet.http.WalletManagementEndpoints import org.hyperledger.identus.issue.controller.IssueEndpoints import org.hyperledger.identus.pollux.credentialdefinition.CredentialDefinitionRegistryEndpoints import org.hyperledger.identus.pollux.credentialschema.{SchemaRegistryEndpoints, VerificationPolicyEndpoints} +import org.hyperledger.identus.pollux.prex.PresentationExchangeEndpoints import org.hyperledger.identus.system.controller.SystemEndpoints import sttp.apispec.{SecurityScheme, Tag} import sttp.apispec.openapi.* @@ -122,7 +123,8 @@ object DocModels { WalletManagementEndpoints.tag, SystemEndpoints.tag, EventEndpoints.tag, - EntityEndpoints.tag + EntityEndpoints.tag, + PresentationExchangeEndpoints.tag ) ) diff --git a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/agent/server/jobs/StatusListJobs.scala b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/agent/server/jobs/StatusListJobs.scala index d57cccb079..71d02db3e2 100644 --- a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/agent/server/jobs/StatusListJobs.scala +++ b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/agent/server/jobs/StatusListJobs.scala @@ -7,7 +7,6 @@ import org.hyperledger.identus.mercury.protocol.revocationnotificaiton.Revocatio import org.hyperledger.identus.pollux.core.service.{CredentialService, CredentialStatusListService} import org.hyperledger.identus.pollux.vc.jwt.revocation.{VCStatusList2021, VCStatusList2021Error} import org.hyperledger.identus.shared.models.* -import org.hyperledger.identus.shared.models.WalletAccessContext import org.hyperledger.identus.shared.utils.DurationOps.toMetricsSeconds import zio.* import zio.metrics.Metric diff --git a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/controller/DIDController.scala b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/castor/controller/DIDController.scala similarity index 100% rename from cloud-agent/service/server/src/main/scala/org/hyperledger/identus/controller/DIDController.scala rename to cloud-agent/service/server/src/main/scala/org/hyperledger/identus/castor/controller/DIDController.scala diff --git a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/controller/DIDEndpoints.scala b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/castor/controller/DIDEndpoints.scala similarity index 100% rename from cloud-agent/service/server/src/main/scala/org/hyperledger/identus/controller/DIDEndpoints.scala rename to cloud-agent/service/server/src/main/scala/org/hyperledger/identus/castor/controller/DIDEndpoints.scala diff --git a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/controller/DIDRegistrarController.scala b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/castor/controller/DIDRegistrarController.scala similarity index 100% rename from cloud-agent/service/server/src/main/scala/org/hyperledger/identus/controller/DIDRegistrarController.scala rename to cloud-agent/service/server/src/main/scala/org/hyperledger/identus/castor/controller/DIDRegistrarController.scala diff --git a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/controller/DIDRegistrarEndpoints.scala b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/castor/controller/DIDRegistrarEndpoints.scala similarity index 100% rename from cloud-agent/service/server/src/main/scala/org/hyperledger/identus/controller/DIDRegistrarEndpoints.scala rename to cloud-agent/service/server/src/main/scala/org/hyperledger/identus/castor/controller/DIDRegistrarEndpoints.scala diff --git a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/controller/DIDRegistrarServerEndpoints.scala b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/castor/controller/DIDRegistrarServerEndpoints.scala similarity index 100% rename from cloud-agent/service/server/src/main/scala/org/hyperledger/identus/controller/DIDRegistrarServerEndpoints.scala rename to cloud-agent/service/server/src/main/scala/org/hyperledger/identus/castor/controller/DIDRegistrarServerEndpoints.scala diff --git a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/controller/DIDServerEndpoints.scala b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/castor/controller/DIDServerEndpoints.scala similarity index 100% rename from cloud-agent/service/server/src/main/scala/org/hyperledger/identus/controller/DIDServerEndpoints.scala rename to cloud-agent/service/server/src/main/scala/org/hyperledger/identus/castor/controller/DIDServerEndpoints.scala diff --git a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/controller/http/DIDDocument.scala b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/castor/controller/http/DIDDocument.scala similarity index 100% rename from cloud-agent/service/server/src/main/scala/org/hyperledger/identus/controller/http/DIDDocument.scala rename to cloud-agent/service/server/src/main/scala/org/hyperledger/identus/castor/controller/http/DIDDocument.scala diff --git a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/controller/http/DIDDocumentMetadata.scala b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/castor/controller/http/DIDDocumentMetadata.scala similarity index 100% rename from cloud-agent/service/server/src/main/scala/org/hyperledger/identus/controller/http/DIDDocumentMetadata.scala rename to cloud-agent/service/server/src/main/scala/org/hyperledger/identus/castor/controller/http/DIDDocumentMetadata.scala diff --git a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/controller/http/DIDInput.scala b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/castor/controller/http/DIDInput.scala similarity index 100% rename from cloud-agent/service/server/src/main/scala/org/hyperledger/identus/controller/http/DIDInput.scala rename to cloud-agent/service/server/src/main/scala/org/hyperledger/identus/castor/controller/http/DIDInput.scala diff --git a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/controller/http/DIDResolutionMetadata.scala b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/castor/controller/http/DIDResolutionMetadata.scala similarity index 100% rename from cloud-agent/service/server/src/main/scala/org/hyperledger/identus/controller/http/DIDResolutionMetadata.scala rename to cloud-agent/service/server/src/main/scala/org/hyperledger/identus/castor/controller/http/DIDResolutionMetadata.scala diff --git a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/controller/http/DIDResolutionResult.scala b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/castor/controller/http/DIDResolutionResult.scala similarity index 100% rename from cloud-agent/service/server/src/main/scala/org/hyperledger/identus/controller/http/DIDResolutionResult.scala rename to cloud-agent/service/server/src/main/scala/org/hyperledger/identus/castor/controller/http/DIDResolutionResult.scala diff --git a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/controller/http/ManagedDID.scala b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/castor/controller/http/ManagedDID.scala similarity index 100% rename from cloud-agent/service/server/src/main/scala/org/hyperledger/identus/controller/http/ManagedDID.scala rename to cloud-agent/service/server/src/main/scala/org/hyperledger/identus/castor/controller/http/ManagedDID.scala diff --git a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/controller/http/PublicKeyJwk.scala b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/castor/controller/http/PublicKeyJwk.scala similarity index 100% rename from cloud-agent/service/server/src/main/scala/org/hyperledger/identus/controller/http/PublicKeyJwk.scala rename to cloud-agent/service/server/src/main/scala/org/hyperledger/identus/castor/controller/http/PublicKeyJwk.scala diff --git a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/controller/http/ScheduledOperation.scala b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/castor/controller/http/ScheduledOperation.scala similarity index 100% rename from cloud-agent/service/server/src/main/scala/org/hyperledger/identus/controller/http/ScheduledOperation.scala rename to cloud-agent/service/server/src/main/scala/org/hyperledger/identus/castor/controller/http/ScheduledOperation.scala diff --git a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/controller/http/Service.scala b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/castor/controller/http/Service.scala similarity index 100% rename from cloud-agent/service/server/src/main/scala/org/hyperledger/identus/controller/http/Service.scala rename to cloud-agent/service/server/src/main/scala/org/hyperledger/identus/castor/controller/http/Service.scala diff --git a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/controller/http/UpdateManagedDID.scala b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/castor/controller/http/UpdateManagedDID.scala similarity index 100% rename from cloud-agent/service/server/src/main/scala/org/hyperledger/identus/controller/http/UpdateManagedDID.scala rename to cloud-agent/service/server/src/main/scala/org/hyperledger/identus/castor/controller/http/UpdateManagedDID.scala diff --git a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/controller/http/VerificationMethod.scala b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/castor/controller/http/VerificationMethod.scala similarity index 100% rename from cloud-agent/service/server/src/main/scala/org/hyperledger/identus/controller/http/VerificationMethod.scala rename to cloud-agent/service/server/src/main/scala/org/hyperledger/identus/castor/controller/http/VerificationMethod.scala diff --git a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/didcomm/controller/DIDCommControllerError.scala b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/didcomm/controller/DIDCommControllerError.scala index 1bc1a644d4..5a27032b75 100644 --- a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/didcomm/controller/DIDCommControllerError.scala +++ b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/didcomm/controller/DIDCommControllerError.scala @@ -1,8 +1,7 @@ package org.hyperledger.identus.didcomm.controller import org.hyperledger.identus.mercury.model.DidId -import org.hyperledger.identus.shared.models.{Failure, StatusCode} -import org.hyperledger.identus.shared.models.KeyId +import org.hyperledger.identus.shared.models.{Failure, KeyId, StatusCode} sealed trait DIDCommControllerError extends Failure { override def namespace = "DIDCommControllerError" diff --git a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/pollux/prex/PresentationExchangeEndpoints.scala b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/pollux/prex/PresentationExchangeEndpoints.scala new file mode 100644 index 0000000000..435042b052 --- /dev/null +++ b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/pollux/prex/PresentationExchangeEndpoints.scala @@ -0,0 +1,97 @@ +package org.hyperledger.identus.pollux.prex + +import org.hyperledger.identus.api.http.{EndpointOutputs, ErrorResponse, RequestContext} +import org.hyperledger.identus.api.http.model.PaginationInput +import org.hyperledger.identus.iam.authentication.apikey.ApiKeyCredentials +import org.hyperledger.identus.iam.authentication.apikey.ApiKeyEndpointSecurityLogic.apiKeyHeader +import org.hyperledger.identus.iam.authentication.oidc.JwtCredentials +import org.hyperledger.identus.iam.authentication.oidc.JwtSecurityLogic.jwtAuthHeader +import org.hyperledger.identus.pollux.prex.http.{CreatePresentationDefinition, PresentationDefinitionPage} +import org.hyperledger.identus.pollux.prex.http.PresentationExchangeTapirSchemas.given +import sttp.apispec.Tag +import sttp.model.StatusCode +import sttp.tapir.* +import sttp.tapir.json.zio.jsonBody + +import java.util.UUID + +object PresentationExchangeEndpoints { + + private val tagName = "Presentation Exchange" + private val tagDescription = + s""" + |The __${tagName}__ endpoints offers a way to manage resources related to [presentation exchange protocol](https://identity.foundation/presentation-exchange/spec/v2.1.1/). + | + |The verifier can create the resources such as `presentation-definition` that can be publicly referenced + |in various protocols such as [OpenID for Verificable Presentation](https://openid.net/specs/openid-4-verifiable-presentations-1_0.html). + |""".stripMargin + + val tag = Tag(tagName, Some(tagDescription)) + + private val paginationInput: EndpointInput[PaginationInput] = EndpointInput.derived[PaginationInput] + + private val baseEndpoint = endpoint + .tag(tagName) + .in("presentation-exchange") + .in(extractFromRequest[RequestContext](RequestContext.apply)) + + private val basePrivateEndpoint = baseEndpoint + .securityIn(apiKeyHeader) + .securityIn(jwtAuthHeader) + + val getPresentationDefinition: Endpoint[ + Unit, + (RequestContext, UUID), + ErrorResponse, + PresentationDefinition, + Any + ] = + baseEndpoint.get + .in("presentation-definitions" / path[UUID]("id")) + .out(statusCode(StatusCode.Ok).description("Presentation Definition retrieved successfully")) + .out(jsonBody[PresentationDefinition]) + .errorOut(EndpointOutputs.basicFailuresAndNotFound) + .name("getPresentationDefinition") + .summary("Get a presentation-definition") + + val listPresentationDefinition: Endpoint[ + (ApiKeyCredentials, JwtCredentials), + (RequestContext, PaginationInput), + ErrorResponse, + PresentationDefinitionPage, + Any, + ] = + basePrivateEndpoint.get + .in("presentation-definitions") + .in(paginationInput) + .out(statusCode(StatusCode.Ok).description("Presentation Definitions retrieved successfully")) + .out(jsonBody[PresentationDefinitionPage]) + .errorOut(EndpointOutputs.basicFailuresAndForbidden) + .name("listPresentationDefinition") + .summary("List all presentation-definitions") + .description( + """List all `presentation-definitions` in the wallet. + |Return a paginated items ordered by created timestamp.""".stripMargin + ) + + val createPresentationDefinition: Endpoint[ + (ApiKeyCredentials, JwtCredentials), + (RequestContext, CreatePresentationDefinition), + ErrorResponse, + PresentationDefinition, + Any + ] = + basePrivateEndpoint.post + .in("presentation-definitions") + .in(jsonBody[CreatePresentationDefinition]) + .out(statusCode(StatusCode.Created).description("Presentation Definition created successfully")) + .out(jsonBody[PresentationDefinition]) + .errorOut(EndpointOutputs.basicFailureAndNotFoundAndForbidden) + .name("createPresentationDefinition") + .summary("Create a new presentation-definition") + .description( + """Create a `presentation-definition` object according to the [presentation exchange protocol](https://identity.foundation/presentation-exchange/spec/v2.1.1/). + |The `POST` endpoint is restricted to the owner of the wallet. The `presentation-definition` object, however can be referenced by publicly by `id` returned in the response.""".stripMargin + ) + +} diff --git a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/pollux/prex/PresentationExchangeServerEndpoints.scala b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/pollux/prex/PresentationExchangeServerEndpoints.scala new file mode 100644 index 0000000000..e5daa287d1 --- /dev/null +++ b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/pollux/prex/PresentationExchangeServerEndpoints.scala @@ -0,0 +1,61 @@ +package org.hyperledger.identus.pollux.prex + +import org.hyperledger.identus.agent.walletapi.model.BaseEntity +import org.hyperledger.identus.iam.authentication.{Authenticator, Authorizer, DefaultAuthenticator, SecurityLogic} +import org.hyperledger.identus.pollux.prex.controller.PresentationExchangeController +import org.hyperledger.identus.LogUtils.* +import sttp.tapir.ztapir.* +import zio.* + +class PresentationExchangeServerEndpoints( + controller: PresentationExchangeController, + authenticator: Authenticator[BaseEntity], + authorizer: Authorizer[BaseEntity] +) { + + private val getPresentationDefinitionServerEndpoint: ZServerEndpoint[Any, Any] = + PresentationExchangeEndpoints.getPresentationDefinition + .zServerLogic { case (rc, id) => + controller.getPresentationDefinition(id).logTrace(rc) + } + + private val listPresentationDefinitionServerEndpoint: ZServerEndpoint[Any, Any] = + PresentationExchangeEndpoints.listPresentationDefinition + .zServerSecurityLogic(SecurityLogic.authorizeWalletAccessWith(_)(authenticator, authorizer)) + .serverLogic { wac => + { case (rc, pagination) => + controller + .listPresentationDefinition(pagination)(rc) + .provideSomeLayer(ZLayer.succeed(wac)) + .logTrace(rc) + } + } + + private val createPresentationDefinitionServerEndpoint: ZServerEndpoint[Any, Any] = + PresentationExchangeEndpoints.createPresentationDefinition + .zServerSecurityLogic(SecurityLogic.authorizeWalletAccessWith(_)(authenticator, authorizer)) + .serverLogic { wac => + { case (rc, pd) => + controller + .createPresentationDefinition(pd) + .provideSomeLayer(ZLayer.succeed(wac)) + .logTrace(rc) + } + } + + val all: List[ZServerEndpoint[Any, Any]] = List( + getPresentationDefinitionServerEndpoint, + listPresentationDefinitionServerEndpoint, + createPresentationDefinitionServerEndpoint + ) +} + +object PresentationExchangeServerEndpoints { + def all: URIO[DefaultAuthenticator & PresentationExchangeController, List[ZServerEndpoint[Any, Any]]] = { + for { + controller <- ZIO.service[PresentationExchangeController] + authenticator <- ZIO.service[DefaultAuthenticator] + endpoints = PresentationExchangeServerEndpoints(controller, authenticator, authenticator) + } yield endpoints.all + } +} diff --git a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/pollux/prex/controller/PresentationExchangeController.scala b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/pollux/prex/controller/PresentationExchangeController.scala new file mode 100644 index 0000000000..0376544d9b --- /dev/null +++ b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/pollux/prex/controller/PresentationExchangeController.scala @@ -0,0 +1,62 @@ +package org.hyperledger.identus.pollux.prex.controller + +import org.hyperledger.identus.api.http.{ErrorResponse, RequestContext} +import org.hyperledger.identus.api.http.model.{CollectionStats, PaginationInput} +import org.hyperledger.identus.api.util.PaginationUtils +import org.hyperledger.identus.pollux.core.service.PresentationExchangeService +import org.hyperledger.identus.pollux.prex.http.{CreatePresentationDefinition, PresentationDefinitionPage} +import org.hyperledger.identus.pollux.prex.PresentationDefinition +import org.hyperledger.identus.shared.models.WalletAccessContext +import zio.* + +import java.util.UUID +import scala.language.implicitConversions + +trait PresentationExchangeController { + def createPresentationDefinition( + cpd: CreatePresentationDefinition + ): ZIO[WalletAccessContext, ErrorResponse, PresentationDefinition] + + def getPresentationDefinition(id: UUID): IO[ErrorResponse, PresentationDefinition] + + def listPresentationDefinition(paginationInput: PaginationInput)(implicit + rc: RequestContext + ): ZIO[WalletAccessContext, ErrorResponse, PresentationDefinitionPage] +} + +class PresentationExchangeControllerImpl(service: PresentationExchangeService) extends PresentationExchangeController { + + override def createPresentationDefinition( + cpd: CreatePresentationDefinition + ): ZIO[WalletAccessContext, ErrorResponse, PresentationDefinition] = { + val pd: PresentationDefinition = cpd + service.createPresentationDefinititon(pd).as(pd) + } + + override def getPresentationDefinition(id: UUID): IO[ErrorResponse, PresentationDefinition] = + service.getPresentationDefinition(id) + + override def listPresentationDefinition( + paginationInput: PaginationInput + )(implicit rc: RequestContext): ZIO[WalletAccessContext, ErrorResponse, PresentationDefinitionPage] = { + val uri = rc.request.uri + val pagination = paginationInput.toPagination + for { + pageResult <- service.listPresentationDefinition(offset = paginationInput.offset, limit = paginationInput.limit) + (items, totalCount) = pageResult + stats = CollectionStats(totalCount = totalCount, filteredCount = totalCount) + } yield PresentationDefinitionPage( + self = uri.toString(), + pageOf = PaginationUtils.composePageOfUri(uri).toString, + next = PaginationUtils.composeNextUri(uri, items, pagination, stats).map(_.toString), + previous = PaginationUtils.composePreviousUri(uri, items, pagination, stats).map(_.toString), + contents = items, + ) + } + +} + +object PresentationExchangeControllerImpl { + def layer: URLayer[PresentationExchangeService, PresentationExchangeController] = + ZLayer.fromFunction(PresentationExchangeControllerImpl(_)) +} diff --git a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/pollux/prex/http/PresentationDefinition.scala b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/pollux/prex/http/PresentationDefinition.scala new file mode 100644 index 0000000000..fb3c3066b2 --- /dev/null +++ b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/pollux/prex/http/PresentationDefinition.scala @@ -0,0 +1,42 @@ +package org.hyperledger.identus.pollux.prex.http + +import org.hyperledger.identus.pollux.prex.{ClaimFormat, InputDescriptor, PresentationDefinition} +import org.hyperledger.identus.pollux.prex.http.PresentationExchangeTapirSchemas.given +import sttp.tapir.Schema +import zio.json.{JsonDecoder, JsonEncoder} + +case class CreatePresentationDefinition( + input_descriptors: Seq[InputDescriptor] = Seq.empty, + name: Option[String] = None, + purpose: Option[String] = None, + format: Option[ClaimFormat] = None +) + +object CreatePresentationDefinition { + given Schema[CreatePresentationDefinition] = Schema.derived + given JsonEncoder[CreatePresentationDefinition] = JsonEncoder.derived + given JsonDecoder[CreatePresentationDefinition] = JsonDecoder.derived + + given Conversion[CreatePresentationDefinition, PresentationDefinition] = cpd => + PresentationDefinition( + input_descriptors = cpd.input_descriptors, + name = cpd.name, + purpose = cpd.purpose, + format = cpd.format + ) +} + +case class PresentationDefinitionPage( + self: String, + kind: String = "PresentationDefinitionPage", + pageOf: String, + next: Option[String] = None, + previous: Option[String] = None, + contents: Seq[PresentationDefinition] +) + +object PresentationDefinitionPage { + given Schema[PresentationDefinitionPage] = Schema.derived + given JsonEncoder[PresentationDefinitionPage] = JsonEncoder.derived + given JsonDecoder[PresentationDefinitionPage] = JsonDecoder.derived +} diff --git a/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/pollux/prex/http/PresentationExchangeTapirSchemas.scala b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/pollux/prex/http/PresentationExchangeTapirSchemas.scala new file mode 100644 index 0000000000..91b129f5f2 --- /dev/null +++ b/cloud-agent/service/server/src/main/scala/org/hyperledger/identus/pollux/prex/http/PresentationExchangeTapirSchemas.scala @@ -0,0 +1,24 @@ +package org.hyperledger.identus.pollux.prex.http + +import org.hyperledger.identus.pollux.prex.* +import sttp.tapir.json.zio.* +import sttp.tapir.Schema +import zio.json.ast.Json + +import scala.language.implicitConversions + +object PresentationExchangeTapirSchemas { + given Schema[PresentationDefinition] = Schema + .derived[PresentationDefinition] + .description( + "*Presentation Definition* object according to the [PresentationExchange spec](https://identity.foundation/presentation-exchange/spec/v2.1.1/#presentation-definition)" + ) + given Schema[InputDescriptor] = Schema.derived + given Schema[ClaimFormat] = Schema.derived + given Schema[Constraints] = Schema.derived + given Schema[Jwt] = Schema.derived + given Schema[Ldp] = Schema.derived + given Schema[Field] = Schema.derived + given Schema[JsonPathValue] = Schema.schemaForString.map[JsonPathValue](Some(_))(_.value) + given Schema[FieldFilter] = Schema.derived[Json].map[FieldFilter](Some(_))(_.asJsonZio) +} diff --git a/cloud-agent/service/server/src/test/scala/org/hyperledger/identus/api/util/Tapir2StaticOAS.scala b/cloud-agent/service/server/src/test/scala/org/hyperledger/identus/api/util/Tapir2StaticOAS.scala index 42f55edbc5..05b217c71e 100644 --- a/cloud-agent/service/server/src/test/scala/org/hyperledger/identus/api/util/Tapir2StaticOAS.scala +++ b/cloud-agent/service/server/src/test/scala/org/hyperledger/identus/api/util/Tapir2StaticOAS.scala @@ -16,6 +16,7 @@ import org.hyperledger.identus.pollux.credentialschema.controller.{ CredentialSchemaController, VerificationPolicyController } +import org.hyperledger.identus.pollux.prex.controller.PresentationExchangeController import org.hyperledger.identus.presentproof.controller.PresentProofController import org.hyperledger.identus.system.controller.SystemController import org.hyperledger.identus.verification.controller.VcVerificationController @@ -58,6 +59,7 @@ object Tapir2StaticOAS extends ZIOAppDefault { ZLayer.succeed(mock[DefaultAuthenticator]) ++ ZLayer.succeed(mock[EventController]) ++ ZLayer.succeed(mock[CredentialIssuerController]) ++ + ZLayer.succeed(mock[PresentationExchangeController]) ++ ZLayer.succeed(mock[Oid4vciAuthenticatorFactory]) ) } diff --git a/cloud-agent/service/server/src/test/scala/org/hyperledger/identus/issue/controller/IssueControllerImplSpec.scala b/cloud-agent/service/server/src/test/scala/org/hyperledger/identus/issue/controller/IssueControllerImplSpec.scala index edcb5f1411..422928756c 100644 --- a/cloud-agent/service/server/src/test/scala/org/hyperledger/identus/issue/controller/IssueControllerImplSpec.scala +++ b/cloud-agent/service/server/src/test/scala/org/hyperledger/identus/issue/controller/IssueControllerImplSpec.scala @@ -22,8 +22,7 @@ import org.hyperledger.identus.mercury.protocol.invitation.v2.Invitation import org.hyperledger.identus.pollux.core.model.{CredentialFormat, DidCommID, IssueCredentialRecord} import org.hyperledger.identus.pollux.core.model.IssueCredentialRecord.{ProtocolState, Role} import org.hyperledger.identus.pollux.core.service.MockCredentialService -import org.hyperledger.identus.shared.models.KeyId -import org.hyperledger.identus.shared.models.WalletId +import org.hyperledger.identus.shared.models.{KeyId, WalletId} import sttp.client3.{basicRequest, DeserializationException, UriContext} import sttp.client3.ziojson.* import sttp.model.StatusCode diff --git a/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/service/ManagedDIDService.scala b/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/service/ManagedDIDService.scala index c233844df1..935a38244f 100644 --- a/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/service/ManagedDIDService.scala +++ b/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/service/ManagedDIDService.scala @@ -7,8 +7,7 @@ import org.hyperledger.identus.castor.core.model.did.* import org.hyperledger.identus.mercury.model.* import org.hyperledger.identus.mercury.PeerDID import org.hyperledger.identus.shared.crypto.{Ed25519KeyPair, Secp256k1KeyPair, X25519KeyPair} -import org.hyperledger.identus.shared.models.KeyId -import org.hyperledger.identus.shared.models.WalletAccessContext +import org.hyperledger.identus.shared.models.{KeyId, WalletAccessContext} import zio.* /** A wrapper around Castor's DIDService providing key-management capability. Analogous to the secretAPI in diff --git a/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/service/ManagedDIDServiceImpl.scala b/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/service/ManagedDIDServiceImpl.scala index c93806c040..4e8763bdad 100644 --- a/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/service/ManagedDIDServiceImpl.scala +++ b/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/service/ManagedDIDServiceImpl.scala @@ -14,8 +14,7 @@ import org.hyperledger.identus.castor.core.util.DIDOperationValidator import org.hyperledger.identus.mercury.model.DidId import org.hyperledger.identus.mercury.PeerDID import org.hyperledger.identus.shared.crypto.{Apollo, Ed25519KeyPair, Secp256k1KeyPair, X25519KeyPair} -import org.hyperledger.identus.shared.models.KeyId -import org.hyperledger.identus.shared.models.WalletAccessContext +import org.hyperledger.identus.shared.models.{KeyId, WalletAccessContext} import zio.* import scala.collection.immutable.ArraySeq diff --git a/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/service/handler/DIDCreateHandler.scala b/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/service/handler/DIDCreateHandler.scala index 479b34ed2b..66fec256bb 100644 --- a/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/service/handler/DIDCreateHandler.scala +++ b/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/service/handler/DIDCreateHandler.scala @@ -12,8 +12,7 @@ import org.hyperledger.identus.agent.walletapi.storage.{DIDNonSecretStorage, DID import org.hyperledger.identus.agent.walletapi.util.OperationFactory import org.hyperledger.identus.castor.core.model.did.PrismDIDOperation import org.hyperledger.identus.shared.crypto.{Apollo, Ed25519KeyPair, X25519KeyPair} -import org.hyperledger.identus.shared.models.KeyId -import org.hyperledger.identus.shared.models.WalletAccessContext +import org.hyperledger.identus.shared.models.{KeyId, WalletAccessContext} import zio.* private[walletapi] class DIDCreateHandler( diff --git a/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/service/handler/DIDUpdateHandler.scala b/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/service/handler/DIDUpdateHandler.scala index b93510bc69..dd0af4256a 100644 --- a/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/service/handler/DIDUpdateHandler.scala +++ b/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/service/handler/DIDUpdateHandler.scala @@ -19,8 +19,7 @@ import org.hyperledger.identus.castor.core.model.did.{ } import org.hyperledger.identus.castor.core.model.did.PrismDIDOperation.Update import org.hyperledger.identus.shared.crypto.{Apollo, Ed25519KeyPair, X25519KeyPair} -import org.hyperledger.identus.shared.models.KeyId -import org.hyperledger.identus.shared.models.WalletAccessContext +import org.hyperledger.identus.shared.models.{KeyId, WalletAccessContext} import zio.* import scala.collection.immutable.ArraySeq diff --git a/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/service/handler/PublicationHandler.scala b/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/service/handler/PublicationHandler.scala index 1807e9efd9..b1656f0679 100644 --- a/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/service/handler/PublicationHandler.scala +++ b/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/service/handler/PublicationHandler.scala @@ -11,8 +11,7 @@ import org.hyperledger.identus.castor.core.model.did.{ import org.hyperledger.identus.castor.core.model.error.DIDOperationError import org.hyperledger.identus.castor.core.service.DIDService import org.hyperledger.identus.shared.crypto.Secp256k1KeyPair -import org.hyperledger.identus.shared.models.KeyId -import org.hyperledger.identus.shared.models.WalletAccessContext +import org.hyperledger.identus.shared.models.{KeyId, WalletAccessContext} import zio.* import scala.collection.immutable.ArraySeq diff --git a/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/sql/JdbcDIDNonSecretStorage.scala b/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/sql/JdbcDIDNonSecretStorage.scala index 85cada9985..bfdca44f73 100644 --- a/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/sql/JdbcDIDNonSecretStorage.scala +++ b/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/sql/JdbcDIDNonSecretStorage.scala @@ -16,8 +16,7 @@ import org.hyperledger.identus.mercury.model.DidId import org.hyperledger.identus.shared.db.ContextAwareTask import org.hyperledger.identus.shared.db.Implicits.* import org.hyperledger.identus.shared.db.Implicits.given -import org.hyperledger.identus.shared.models.{WalletAccessContext, WalletId} -import org.hyperledger.identus.shared.models.KeyId +import org.hyperledger.identus.shared.models.{KeyId, WalletAccessContext, WalletId} import zio.* import zio.interop.catz.* diff --git a/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/sql/JdbcDIDSecretStorage.scala b/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/sql/JdbcDIDSecretStorage.scala index 76f9e2650f..7ff1e935b7 100644 --- a/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/sql/JdbcDIDSecretStorage.scala +++ b/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/sql/JdbcDIDSecretStorage.scala @@ -10,8 +10,7 @@ import org.hyperledger.identus.mercury.model.DidId import org.hyperledger.identus.shared.crypto.jwk.{FromJWK, JWK} import org.hyperledger.identus.shared.db.ContextAwareTask import org.hyperledger.identus.shared.db.Implicits.* -import org.hyperledger.identus.shared.models.KeyId -import org.hyperledger.identus.shared.models.WalletAccessContext +import org.hyperledger.identus.shared.models.{KeyId, WalletAccessContext} import zio.* import java.time.Instant diff --git a/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/storage/DIDNonSecretStorage.scala b/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/storage/DIDNonSecretStorage.scala index e1f84efb4b..1830dc1600 100644 --- a/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/storage/DIDNonSecretStorage.scala +++ b/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/storage/DIDNonSecretStorage.scala @@ -3,8 +3,7 @@ package org.hyperledger.identus.agent.walletapi.storage import org.hyperledger.identus.agent.walletapi.model.* import org.hyperledger.identus.castor.core.model.did.{PrismDID, ScheduledDIDOperationStatus} import org.hyperledger.identus.mercury.model.DidId -import org.hyperledger.identus.shared.models.{WalletAccessContext, WalletId} -import org.hyperledger.identus.shared.models.KeyId +import org.hyperledger.identus.shared.models.{KeyId, WalletAccessContext, WalletId} import zio.* trait DIDNonSecretStorage { diff --git a/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/storage/DIDSecretStorage.scala b/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/storage/DIDSecretStorage.scala index 4726e5a015..0056e0d0e6 100644 --- a/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/storage/DIDSecretStorage.scala +++ b/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/storage/DIDSecretStorage.scala @@ -4,8 +4,7 @@ import com.nimbusds.jose.jwk.OctetKeyPair import org.hyperledger.identus.castor.core.model.did.PrismDID import org.hyperledger.identus.mercury.model.DidId import org.hyperledger.identus.shared.crypto.jwk.{FromJWK, JWK} -import org.hyperledger.identus.shared.models.KeyId -import org.hyperledger.identus.shared.models.WalletAccessContext +import org.hyperledger.identus.shared.models.{KeyId, WalletAccessContext} import zio.* /** A simple single-user DID key storage */ diff --git a/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/util/KeyResolver.scala b/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/util/KeyResolver.scala index 6460af34f5..76a28a853f 100644 --- a/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/util/KeyResolver.scala +++ b/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/util/KeyResolver.scala @@ -9,8 +9,7 @@ import org.hyperledger.identus.agent.walletapi.model.{ import org.hyperledger.identus.agent.walletapi.storage.{DIDNonSecretStorage, DIDSecretStorage, WalletSecretStorage} import org.hyperledger.identus.castor.core.model.did.{EllipticCurve, PrismDID} import org.hyperledger.identus.shared.crypto.{Apollo, Ed25519KeyPair, Secp256k1KeyPair, X25519KeyPair} -import org.hyperledger.identus.shared.models.KeyId -import org.hyperledger.identus.shared.models.WalletAccessContext +import org.hyperledger.identus.shared.models.{KeyId, WalletAccessContext} import zio.* class KeyResolver( diff --git a/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/util/OperationFactory.scala b/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/util/OperationFactory.scala index acabbb413d..9cf16b6a42 100644 --- a/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/util/OperationFactory.scala +++ b/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/util/OperationFactory.scala @@ -10,8 +10,7 @@ import org.hyperledger.identus.shared.crypto.{ Secp256k1PublicKey, X25519PublicKey } -import org.hyperledger.identus.shared.models.Base64UrlString -import org.hyperledger.identus.shared.models.KeyId +import org.hyperledger.identus.shared.models.{Base64UrlString, KeyId} import zio.* import scala.collection.immutable.ArraySeq diff --git a/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/vault/VaultDIDSecretStorage.scala b/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/vault/VaultDIDSecretStorage.scala index 1cf98aa9a1..2ca1faf466 100644 --- a/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/vault/VaultDIDSecretStorage.scala +++ b/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/vault/VaultDIDSecretStorage.scala @@ -6,8 +6,7 @@ import org.hyperledger.identus.castor.core.model.did.PrismDID import org.hyperledger.identus.mercury.model.DidId import org.hyperledger.identus.shared.crypto.jwk.{FromJWK, JWK} import org.hyperledger.identus.shared.crypto.Sha256Hash -import org.hyperledger.identus.shared.models.{HexString, WalletAccessContext, WalletId} -import org.hyperledger.identus.shared.models.KeyId +import org.hyperledger.identus.shared.models.{HexString, KeyId, WalletAccessContext, WalletId} import zio.* import java.nio.charset.StandardCharsets diff --git a/cloud-agent/service/wallet-api/src/test/scala/org/hyperledger/identus/agent/walletapi/service/ManagedDIDServiceSpec.scala b/cloud-agent/service/wallet-api/src/test/scala/org/hyperledger/identus/agent/walletapi/service/ManagedDIDServiceSpec.scala index 8448ae4131..7950a38265 100644 --- a/cloud-agent/service/wallet-api/src/test/scala/org/hyperledger/identus/agent/walletapi/service/ManagedDIDServiceSpec.scala +++ b/cloud-agent/service/wallet-api/src/test/scala/org/hyperledger/identus/agent/walletapi/service/ManagedDIDServiceSpec.scala @@ -15,8 +15,7 @@ import org.hyperledger.identus.castor.core.model.error import org.hyperledger.identus.castor.core.service.DIDService import org.hyperledger.identus.castor.core.util.DIDOperationValidator import org.hyperledger.identus.shared.crypto.{ApolloSpecHelper, Ed25519KeyPair, Secp256k1KeyPair, X25519KeyPair} -import org.hyperledger.identus.shared.models.{WalletAccessContext, WalletAdministrationContext} -import org.hyperledger.identus.shared.models.KeyId +import org.hyperledger.identus.shared.models.{KeyId, WalletAccessContext, WalletAdministrationContext} import org.hyperledger.identus.sharedtest.containers.PostgresTestContainerSupport import org.hyperledger.identus.test.container.{DBTestUtils, VaultTestContainerSupport} import zio.* diff --git a/cloud-agent/service/wallet-api/src/test/scala/org/hyperledger/identus/agent/walletapi/storage/DIDSecretStorageSpec.scala b/cloud-agent/service/wallet-api/src/test/scala/org/hyperledger/identus/agent/walletapi/storage/DIDSecretStorageSpec.scala index 0ff4217449..9288c39cd9 100644 --- a/cloud-agent/service/wallet-api/src/test/scala/org/hyperledger/identus/agent/walletapi/storage/DIDSecretStorageSpec.scala +++ b/cloud-agent/service/wallet-api/src/test/scala/org/hyperledger/identus/agent/walletapi/storage/DIDSecretStorageSpec.scala @@ -12,8 +12,7 @@ import org.hyperledger.identus.agent.walletapi.vault.{VaultDIDSecretStorage, Vau import org.hyperledger.identus.castor.core.model.did.PrismDIDOperation import org.hyperledger.identus.mercury.PeerDID import org.hyperledger.identus.shared.crypto.{Apollo, ApolloSpecHelper, Ed25519KeyPair, X25519KeyPair} -import org.hyperledger.identus.shared.models.{WalletAccessContext, WalletAdministrationContext} -import org.hyperledger.identus.shared.models.KeyId +import org.hyperledger.identus.shared.models.{KeyId, WalletAccessContext, WalletAdministrationContext} import org.hyperledger.identus.sharedtest.containers.PostgresTestContainerSupport import org.hyperledger.identus.test.container.{DBTestUtils, VaultTestContainerSupport} import zio.* diff --git a/cloud-agent/service/wallet-api/src/test/scala/org/hyperledger/identus/agent/walletapi/storage/MockDIDNonSecretStorage.scala b/cloud-agent/service/wallet-api/src/test/scala/org/hyperledger/identus/agent/walletapi/storage/MockDIDNonSecretStorage.scala index e20c1a245a..f14df4d00d 100644 --- a/cloud-agent/service/wallet-api/src/test/scala/org/hyperledger/identus/agent/walletapi/storage/MockDIDNonSecretStorage.scala +++ b/cloud-agent/service/wallet-api/src/test/scala/org/hyperledger/identus/agent/walletapi/storage/MockDIDNonSecretStorage.scala @@ -3,8 +3,7 @@ package org.hyperledger.identus.agent.walletapi.storage import org.hyperledger.identus.agent.walletapi.model.* import org.hyperledger.identus.castor.core.model.did.{PrismDID, ScheduledDIDOperationStatus} import org.hyperledger.identus.mercury.model.DidId -import org.hyperledger.identus.shared.models.{WalletAccessContext, WalletId} -import org.hyperledger.identus.shared.models.KeyId +import org.hyperledger.identus.shared.models.{KeyId, WalletAccessContext, WalletId} import zio.* import zio.mock.{Expectation, Mock, Proxy} import zio.test.Assertion.equalTo diff --git a/cloud-agent/service/wallet-api/src/test/scala/org/hyperledger/identus/agent/walletapi/storage/StorageSpecHelper.scala b/cloud-agent/service/wallet-api/src/test/scala/org/hyperledger/identus/agent/walletapi/storage/StorageSpecHelper.scala index ef6a3b05e4..15f348ca1d 100644 --- a/cloud-agent/service/wallet-api/src/test/scala/org/hyperledger/identus/agent/walletapi/storage/StorageSpecHelper.scala +++ b/cloud-agent/service/wallet-api/src/test/scala/org/hyperledger/identus/agent/walletapi/storage/StorageSpecHelper.scala @@ -18,8 +18,7 @@ import org.hyperledger.identus.castor.core.model.did.{ VerificationRelationship } import org.hyperledger.identus.shared.crypto.ApolloSpecHelper -import org.hyperledger.identus.shared.models.{WalletAccessContext, WalletAdministrationContext} -import org.hyperledger.identus.shared.models.KeyId +import org.hyperledger.identus.shared.models.{KeyId, WalletAccessContext, WalletAdministrationContext} import zio.* import zio.test.* diff --git a/cloud-agent/service/wallet-api/src/test/scala/org/hyperledger/identus/agent/walletapi/util/OperationFactorySpec.scala b/cloud-agent/service/wallet-api/src/test/scala/org/hyperledger/identus/agent/walletapi/util/OperationFactorySpec.scala index 8131d80f18..6d24a9c403 100644 --- a/cloud-agent/service/wallet-api/src/test/scala/org/hyperledger/identus/agent/walletapi/util/OperationFactorySpec.scala +++ b/cloud-agent/service/wallet-api/src/test/scala/org/hyperledger/identus/agent/walletapi/util/OperationFactorySpec.scala @@ -3,8 +3,7 @@ package org.hyperledger.identus.agent.walletapi.util import org.hyperledger.identus.agent.walletapi.model.* import org.hyperledger.identus.castor.core.model.did.* import org.hyperledger.identus.shared.crypto.{ApolloSpecHelper, Ed25519KeyPair, X25519KeyPair} -import org.hyperledger.identus.shared.models.HexString -import org.hyperledger.identus.shared.models.KeyId +import org.hyperledger.identus.shared.models.{HexString, KeyId} import zio.* import zio.test.* import zio.test.Assertion.* diff --git a/pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/model/error/CredentialServiceError.scala b/pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/model/error/CredentialServiceError.scala index 09d221ed25..a0ffdbe944 100644 --- a/pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/model/error/CredentialServiceError.scala +++ b/pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/model/error/CredentialServiceError.scala @@ -4,8 +4,7 @@ import org.hyperledger.identus.agent.walletapi.model.PublicationState import org.hyperledger.identus.castor.core.model.did.{PrismDID, VerificationRelationship} import org.hyperledger.identus.pollux.core.model.DidCommID import org.hyperledger.identus.pollux.core.model.IssueCredentialRecord.ProtocolState -import org.hyperledger.identus.shared.models.{Failure, StatusCode} -import org.hyperledger.identus.shared.models.KeyId +import org.hyperledger.identus.shared.models.{Failure, KeyId, StatusCode} import java.util.UUID diff --git a/pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/repository/PresentationExchangeRepository.scala b/pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/repository/PresentationExchangeRepository.scala new file mode 100644 index 0000000000..b94026af86 --- /dev/null +++ b/pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/repository/PresentationExchangeRepository.scala @@ -0,0 +1,16 @@ +package org.hyperledger.identus.pollux.core.repository + +import org.hyperledger.identus.pollux.prex.PresentationDefinition +import org.hyperledger.identus.shared.models.WalletAccessContext +import zio.* + +import java.util.UUID + +trait PresentationExchangeRepository { + def createPresentationDefinition(pd: PresentationDefinition): URIO[WalletAccessContext, Unit] + def findPresentationDefinition(id: UUID): UIO[Option[PresentationDefinition]] + def listPresentationDefinition( + offset: Option[Int] = None, + limit: Option[Int] = None + ): URIO[WalletAccessContext, (Seq[PresentationDefinition], Int)] +} diff --git a/pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/service/PresentationExchangeService.scala b/pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/service/PresentationExchangeService.scala new file mode 100644 index 0000000000..9096c2510e --- /dev/null +++ b/pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/service/PresentationExchangeService.scala @@ -0,0 +1,44 @@ +package org.hyperledger.identus.pollux.core.service + +import org.hyperledger.identus.pollux.core.service.PresentationExchangeServiceError.{ + PresentationDefinitionNotFound, + PresentationDefinitionValidationError +} +import org.hyperledger.identus.pollux.prex.{PresentationDefinition, PresentationDefinitionError} +import org.hyperledger.identus.shared.models.{Failure, StatusCode, WalletAccessContext} +import zio.* + +import java.util.UUID + +sealed trait PresentationExchangeServiceError( + val statusCode: StatusCode, + val userFacingMessage: String +) extends Failure { + override val namespace = "PresentationExchangeServiceError" +} + +object PresentationExchangeServiceError { + case class PresentationDefinitionNotFound(id: UUID) + extends PresentationExchangeServiceError(StatusCode.NotFound, s"PresentationDefinition not found with id: $id") + + case class PresentationDefinitionValidationError(error: PresentationDefinitionError) + extends PresentationExchangeServiceError( + StatusCode.BadRequest, + s"PresentationDefinition validation failed: ${error.userFacingMessage}" + ) +} + +trait PresentationExchangeService { + def createPresentationDefinititon( + pd: PresentationDefinition + ): ZIO[WalletAccessContext, PresentationDefinitionValidationError, Unit] + + def getPresentationDefinition( + id: UUID + ): IO[PresentationDefinitionNotFound, PresentationDefinition] + + def listPresentationDefinition( + limit: Option[Int], + offset: Option[Int] + ): URIO[WalletAccessContext, (Seq[PresentationDefinition], Int)] +} diff --git a/pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/service/PresentationExchangeServiceImpl.scala b/pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/service/PresentationExchangeServiceImpl.scala new file mode 100644 index 0000000000..4af0203c07 --- /dev/null +++ b/pollux/core/src/main/scala/org/hyperledger/identus/pollux/core/service/PresentationExchangeServiceImpl.scala @@ -0,0 +1,41 @@ +package org.hyperledger.identus.pollux.core.service + +import org.hyperledger.identus.pollux.core.repository.PresentationExchangeRepository +import org.hyperledger.identus.pollux.core.service.PresentationExchangeServiceError.{ + PresentationDefinitionNotFound, + PresentationDefinitionValidationError +} +import org.hyperledger.identus.pollux.prex.{PresentationDefinition, PresentationDefinitionValidator} +import org.hyperledger.identus.shared.models.WalletAccessContext +import zio.* + +import java.util.UUID + +class PresentationExchangeServiceImpl(validator: PresentationDefinitionValidator, repo: PresentationExchangeRepository) + extends PresentationExchangeService { + + override def createPresentationDefinititon( + pd: PresentationDefinition + ): ZIO[WalletAccessContext, PresentationDefinitionValidationError, Unit] = + for { + _ <- validator.validate(pd).mapError(PresentationDefinitionValidationError(_)) + _ <- repo.createPresentationDefinition(pd) + } yield () + + override def getPresentationDefinition( + id: UUID + ): IO[PresentationDefinitionNotFound, PresentationDefinition] = + repo.findPresentationDefinition(id).someOrFail(PresentationDefinitionNotFound(id)) + + override def listPresentationDefinition( + limit: Option[Int], + offset: Option[Int] + ): URIO[WalletAccessContext, (Seq[PresentationDefinition], Int)] = + repo.listPresentationDefinition(offset = offset, limit = limit) + +} + +object PresentationExchangeServiceImpl { + def layer: URLayer[PresentationDefinitionValidator & PresentationExchangeRepository, PresentationExchangeService] = + ZLayer.fromFunction(PresentationExchangeServiceImpl(_, _)) +} diff --git a/pollux/prex/src/main/scala/org/hyperledger/identus/pollux/prex/PresentationDefinition.scala b/pollux/prex/src/main/scala/org/hyperledger/identus/pollux/prex/PresentationDefinition.scala index 21ded1e947..ea16960cc9 100644 --- a/pollux/prex/src/main/scala/org/hyperledger/identus/pollux/prex/PresentationDefinition.scala +++ b/pollux/prex/src/main/scala/org/hyperledger/identus/pollux/prex/PresentationDefinition.scala @@ -6,6 +6,7 @@ import io.circe.generic.semiauto.* import io.circe.Json as CirceJson import org.hyperledger.identus.shared.json.{JsonInterop, JsonPath, JsonPathError, JsonSchemaError, JsonSchemaUtils} import zio.* +import zio.json.{JsonDecoder, JsonEncoder} import zio.json.ast.Json as ZioJson opaque type JsonPathValue = String @@ -15,6 +16,9 @@ object JsonPathValue { given Decoder[JsonPathValue] = Decoder.decodeString given Conversion[String, JsonPathValue] = identity + given JsonEncoder[JsonPathValue] = JsonEncoder.string + given JsonDecoder[JsonPathValue] = JsonDecoder.string + extension (jpv: JsonPathValue) { def toJsonPath: Either[JsonPathError, JsonPath] = JsonPath.compile(jpv) def value: String = jpv @@ -26,6 +30,10 @@ opaque type FieldFilter = ZioJson object FieldFilter { given Encoder[FieldFilter] = Encoder.encodeJson.contramap(JsonInterop.toCirceJsonAst) given Decoder[FieldFilter] = Decoder.decodeJson.map(JsonInterop.toZioJsonAst) + given Conversion[ZioJson, FieldFilter] = identity + + given JsonEncoder[FieldFilter] = ZioJson.encoder + given JsonDecoder[FieldFilter] = ZioJson.decoder extension (f: FieldFilter) def asJsonZio: ZioJson = f @@ -49,6 +57,9 @@ case class Field( object Field { given Encoder[Field] = deriveEncoder[Field] given Decoder[Field] = deriveDecoder[Field] + + given JsonEncoder[Field] = JsonEncoder.derived + given JsonDecoder[Field] = JsonDecoder.derived } case class Jwt(alg: Seq[String]) @@ -56,6 +67,9 @@ case class Jwt(alg: Seq[String]) object Jwt { given Encoder[Jwt] = deriveEncoder[Jwt] given Decoder[Jwt] = deriveDecoder[Jwt] + + given JsonEncoder[Jwt] = JsonEncoder.derived + given JsonDecoder[Jwt] = JsonDecoder.derived } case class Ldp(proof_type: Seq[String]) @@ -63,6 +77,9 @@ case class Ldp(proof_type: Seq[String]) object Ldp { given Encoder[Ldp] = deriveEncoder[Ldp] given Decoder[Ldp] = deriveDecoder[Ldp] + + given JsonEncoder[Ldp] = JsonEncoder.derived + given JsonDecoder[Ldp] = JsonDecoder.derived } enum ClaimFormatValue(val value: String) { @@ -89,6 +106,9 @@ case class ClaimFormat( object ClaimFormat { given Encoder[ClaimFormat] = deriveEncoder[ClaimFormat] given Decoder[ClaimFormat] = deriveDecoder[ClaimFormat] + + given JsonEncoder[ClaimFormat] = JsonEncoder.derived + given JsonDecoder[ClaimFormat] = JsonDecoder.derived } case class Constraints(fields: Option[Seq[Field]]) @@ -96,6 +116,9 @@ case class Constraints(fields: Option[Seq[Field]]) object Constraints { given Encoder[Constraints] = deriveEncoder[Constraints] given Decoder[Constraints] = deriveDecoder[Constraints] + + given JsonEncoder[Constraints] = JsonEncoder.derived + given JsonDecoder[Constraints] = JsonDecoder.derived } /** Refer to Input Descriptors @@ -111,6 +134,9 @@ case class InputDescriptor( object InputDescriptor { given Encoder[InputDescriptor] = deriveEncoder[InputDescriptor] given Decoder[InputDescriptor] = deriveDecoder[InputDescriptor] + + given JsonEncoder[InputDescriptor] = JsonEncoder.derived + given JsonDecoder[InputDescriptor] = JsonDecoder.derived } /** Refer to Presentation @@ -127,4 +153,7 @@ case class PresentationDefinition( object PresentationDefinition { given Encoder[PresentationDefinition] = deriveEncoder[PresentationDefinition] given Decoder[PresentationDefinition] = deriveDecoder[PresentationDefinition] + + given JsonEncoder[PresentationDefinition] = JsonEncoder.derived + given JsonDecoder[PresentationDefinition] = JsonDecoder.derived } diff --git a/pollux/prex/src/main/scala/org/hyperledger/identus/pollux/prex/PresentationDefinitionValidator.scala b/pollux/prex/src/main/scala/org/hyperledger/identus/pollux/prex/PresentationDefinitionValidator.scala index 9b21a17d94..d0fba75b67 100644 --- a/pollux/prex/src/main/scala/org/hyperledger/identus/pollux/prex/PresentationDefinitionValidator.scala +++ b/pollux/prex/src/main/scala/org/hyperledger/identus/pollux/prex/PresentationDefinitionValidator.scala @@ -56,10 +56,11 @@ trait PresentationDefinitionValidator { } object PresentationDefinitionValidatorImpl { - def layer: Layer[JsonSchemaError, PresentationDefinitionValidator] = + def layer: ULayer[PresentationDefinitionValidator] = ZLayer.scoped { JsonSchemaValidatorImpl.draft7Meta .map(PresentationDefinitionValidatorImpl(_)) + .orDieWith(e => Exception(s"Failed to load JSON schema draft-7 meta schema: $e")) } } diff --git a/pollux/sql-doobie/src/main/resources/sql/pollux/V27__presentation_definition_table.sql b/pollux/sql-doobie/src/main/resources/sql/pollux/V27__presentation_definition_table.sql new file mode 100644 index 0000000000..5faf02007a --- /dev/null +++ b/pollux/sql-doobie/src/main/resources/sql/pollux/V27__presentation_definition_table.sql @@ -0,0 +1,16 @@ +CREATE TABLE public.presentation_definition ( + id UUID PRIMARY KEY, + input_descriptors json NOT NULL, + name VARCHAR(300), + purpose VARCHAR(100), + format json, + wallet_id UUID NOT NULL, + created_at TIMESTAMP WITH TIME ZONE NOT NULL +); + +ALTER TABLE public.presentation_definition + ENABLE ROW LEVEL SECURITY; + +CREATE POLICY presentation_definition_wallet_isolation + ON public.presentation_definition + USING (wallet_id = current_setting('app.current_wallet_id')::UUID); diff --git a/pollux/sql-doobie/src/main/scala/org/hyperledger/identus/pollux/sql/model/db/PresentationDefinition.scala b/pollux/sql-doobie/src/main/scala/org/hyperledger/identus/pollux/sql/model/db/PresentationDefinition.scala new file mode 100644 index 0000000000..5b6d436a89 --- /dev/null +++ b/pollux/sql-doobie/src/main/scala/org/hyperledger/identus/pollux/sql/model/db/PresentationDefinition.scala @@ -0,0 +1,69 @@ +package org.hyperledger.identus.pollux.sql.model.db + +import io.getquill.* +import io.getquill.context.json.PostgresJsonExtensions +import io.getquill.doobie.DoobieContext +import io.getquill.idiom.* +import org.hyperledger.identus.pollux.prex +import org.hyperledger.identus.shared.models.WalletId + +import java.time.Instant +import java.util.UUID + +case class PresentationDefinition( + id: UUID, + input_descriptors: JsonValue[Seq[prex.InputDescriptor]], + name: Option[String], + purpose: Option[String], + format: Option[JsonValue[prex.ClaimFormat]], + createdAt: Instant, + walletId: WalletId +) + +object PresentationDefinition { + def fromModel(pd: prex.PresentationDefinition, walletId: WalletId, createdAt: Instant): PresentationDefinition = { + PresentationDefinition( + id = UUID.fromString(pd.id), + input_descriptors = JsonValue(pd.input_descriptors), + name = pd.name, + purpose = pd.purpose, + format = pd.format.map(JsonValue(_)), + createdAt = createdAt, + walletId = walletId + ) + } + + extension (pd: PresentationDefinition) { + def toModel: prex.PresentationDefinition = { + prex.PresentationDefinition( + id = pd.id.toString(), + input_descriptors = pd.input_descriptors.value, + name = pd.name, + purpose = pd.purpose, + format = pd.format.map(_.value) + ) + } + } +} + +object PresentationDefinitionSql extends DoobieContext.Postgres(SnakeCase) with PostgresJsonExtensions { + def insert(pd: PresentationDefinition) = run { + quote { + query[PresentationDefinition].insertValue(lift(pd)) + } + } + + def findById(id: UUID) = run { + quote { + query[PresentationDefinition].filter(_.id == lift(id)) + } + } + + def lookupCount() = run { quote(query[PresentationDefinition].size) } + + def lookup(offset: Int, limit: Int) = run { + quote { + query[PresentationDefinition].sortBy(_.createdAt).drop(lift(offset)).take(lift(limit)) + } + } +} diff --git a/pollux/sql-doobie/src/main/scala/org/hyperledger/identus/pollux/sql/repository/JdbcPresentationExchangeRepository.scala b/pollux/sql-doobie/src/main/scala/org/hyperledger/identus/pollux/sql/repository/JdbcPresentationExchangeRepository.scala new file mode 100644 index 0000000000..2c58dd6245 --- /dev/null +++ b/pollux/sql-doobie/src/main/scala/org/hyperledger/identus/pollux/sql/repository/JdbcPresentationExchangeRepository.scala @@ -0,0 +1,67 @@ +package org.hyperledger.identus.pollux.sql.repository + +import doobie.* +import doobie.implicits.* +import doobie.util.transactor.Transactor +import org.hyperledger.identus.pollux.core.repository.PresentationExchangeRepository +import org.hyperledger.identus.pollux.prex.PresentationDefinition +import org.hyperledger.identus.pollux.sql.model.db +import org.hyperledger.identus.pollux.sql.model.db.PresentationDefinitionSql +import org.hyperledger.identus.shared.db.ContextAwareTask +import org.hyperledger.identus.shared.db.Implicits.* +import org.hyperledger.identus.shared.models.WalletAccessContext +import zio.* +import zio.interop.catz.* + +import java.util.UUID + +class JdbcPresentationExchangeRepository(xa: Transactor[ContextAwareTask], xb: Transactor[Task]) + extends PresentationExchangeRepository { + + override def createPresentationDefinition(pd: PresentationDefinition): URIO[WalletAccessContext, Unit] = { + for { + now <- Clock.instant + walletId <- ZIO.serviceWith[WalletAccessContext](_.walletId) + row = db.PresentationDefinition.fromModel(pd, walletId, now) + _ <- PresentationDefinitionSql + .insert(row) + .transactWallet(xa) + .orDie + } yield () + } + + override def findPresentationDefinition(id: UUID): UIO[Option[PresentationDefinition]] = { + PresentationDefinitionSql + .findById(id) + .transact(xb) + .orDie + .map(_.headOption.map(_.toModel)) + } + + override def listPresentationDefinition( + offset: Option[Int], + limit: Option[Int] + ): URIO[WalletAccessContext, (Seq[PresentationDefinition], Int)] = { + val countCxnIO = PresentationDefinitionSql.lookupCount() + val pdCxnIO = PresentationDefinitionSql.lookup( + offset = offset.getOrElse(0), + limit = limit.getOrElse(100) + ) + + val effect = + for { + totalCount <- countCxnIO + rows <- pdCxnIO.map(_.map(_.toModel)) + } yield (rows, totalCount.toInt) + + effect + .transactWallet(xa) + .orDie + } + +} + +object JdbcPresentationExchangeRepository { + def layer: URLayer[Transactor[ContextAwareTask] & Transactor[Task], PresentationExchangeRepository] = + ZLayer.fromFunction(JdbcPresentationExchangeRepository(_, _)) +} diff --git a/shared/core/src/main/scala/org/hyperledger/identus/shared/models/KeyId.scala b/shared/core/src/main/scala/org/hyperledger/identus/shared/models/KeyId.scala index f6cbc60efe..185cd59732 100644 --- a/shared/core/src/main/scala/org/hyperledger/identus/shared/models/KeyId.scala +++ b/shared/core/src/main/scala/org/hyperledger/identus/shared/models/KeyId.scala @@ -1,6 +1,6 @@ package org.hyperledger.identus.shared.models -import zio.json._ +import zio.json.* opaque type KeyId = String object KeyId: