From 803c6db869083f62f76831f990f62595c770b147 Mon Sep 17 00:00:00 2001 From: Shota Jolbordi Date: Mon, 16 Sep 2024 01:36:38 +0400 Subject: [PATCH] Add default did services when creating a DID Signed-off-by: Shota Jolbordi --- .../identus/agent/server/MainApp.scala | 39 ++++++++++++++++++- .../walletapi/service/ManagedDIDService.scala | 2 + .../service/ManagedDIDServiceImpl.scala | 14 +++++-- ...dDIDServiceWithEventNotificationImpl.scala | 9 ++++- .../util/ManagedDIDTemplateValidator.scala | 18 ++++++++- 5 files changed, 75 insertions(+), 7 deletions(-) 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 b0309e4e94..1f23e2d28a 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 @@ -18,6 +18,11 @@ import org.hyperledger.identus.agent.walletapi.sql.{ } import org.hyperledger.identus.agent.walletapi.storage.GenericSecretStorage import org.hyperledger.identus.castor.controller.{DIDControllerImpl, DIDRegistrarControllerImpl} +import org.hyperledger.identus.castor.core.model.did.{ + Service as DidService, + ServiceEndpoint as DidServiceEndpoint, + ServiceType as DidServiceType +} import org.hyperledger.identus.castor.core.service.DIDServiceImpl import org.hyperledger.identus.castor.core.util.DIDOperationValidator import org.hyperledger.identus.connect.controller.ConnectionControllerImpl @@ -139,6 +144,38 @@ object MainApp extends ZIOAppDefault { |""".stripMargin) .ignore + appConfig <- ZIO.service[AppConfig].provide(SystemModule.configLayer) + // these services are added to any DID document by default when they are created. + defaultDidDocumentServices = Set( + DidService( + id = appConfig.agent.httpEndpoint.serviceName, + serviceEndpoint = DidServiceEndpoint + .Single( + DidServiceEndpoint.UriOrJsonEndpoint + .Uri( + DidServiceEndpoint.UriValue + .fromString(appConfig.agent.httpEndpoint.publicEndpointUrl.toString) + .toOption + .get // This will fail if URL is invalid, which will prevent app from starting since public endpoint in config is invalid + ) + ), + `type` = DidServiceType.Single(DidServiceType.Name.fromStringUnsafe("LinkedResourceV1")) + ), + DidService( + id = appConfig.pollux.statusListRegistry.serviceName, + serviceEndpoint = DidServiceEndpoint + .Single( + DidServiceEndpoint.UriOrJsonEndpoint + .Uri( + DidServiceEndpoint.UriValue + .fromString(appConfig.pollux.statusListRegistry.publicEndpointUrl.toString) + .toOption + .get + ) + ), + `type` = DidServiceType.Single(DidServiceType.Name.fromStringUnsafe("LinkedResourceV1")) + ) + ) _ <- preMigrations _ <- migrations @@ -183,7 +220,7 @@ object MainApp extends ZIOAppDefault { LinkSecretServiceImpl.layer >>> CredentialServiceImpl.layer >>> CredentialServiceNotifier.layer, DIDServiceImpl.layer, EntityServiceImpl.layer, - ManagedDIDServiceWithEventNotificationImpl.layer, + ZLayer.succeed(defaultDidDocumentServices) >>> ManagedDIDServiceWithEventNotificationImpl.layer, LinkSecretServiceImpl.layer >>> PresentationServiceImpl.layer >>> PresentationServiceNotifier.layer, VerificationPolicyServiceImpl.layer, WalletManagementServiceImpl.layer, 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 e8cba848c1..48caa375c4 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 @@ -17,6 +17,8 @@ trait ManagedDIDService { private[walletapi] def nonSecretStorage: DIDNonSecretStorage + protected def getDefaultDidDocumentServices: Set[Service] = Set.empty + def syncManagedDIDState: ZIO[WalletAccessContext, GetManagedDIDError, Unit] def syncUnconfirmedUpdateOperations: ZIO[WalletAccessContext, GetManagedDIDError, Unit] 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 b021c28d33..20aac73432 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 @@ -8,6 +8,7 @@ import org.hyperledger.identus.agent.walletapi.service.ManagedDIDService.DEFAULT import org.hyperledger.identus.agent.walletapi.storage.{DIDNonSecretStorage, DIDSecretStorage, WalletSecretStorage} import org.hyperledger.identus.agent.walletapi.util.* import org.hyperledger.identus.castor.core.model.did.* +import org.hyperledger.identus.castor.core.model.did.Service as DidDocumentService import org.hyperledger.identus.castor.core.model.error.DIDOperationError import org.hyperledger.identus.castor.core.service.DIDService import org.hyperledger.identus.castor.core.util.DIDOperationValidator @@ -24,6 +25,7 @@ import scala.language.implicitConversions * indy-wallet-sdk. */ class ManagedDIDServiceImpl private[walletapi] ( + defaultDidDocumentServices: Set[DidDocumentService], didService: DIDService, didOpValidator: DIDOperationValidator, private[walletapi] val secretStorage: DIDSecretStorage, @@ -54,6 +56,8 @@ class ManagedDIDServiceImpl private[walletapi] ( def syncUnconfirmedUpdateOperations: ZIO[WalletAccessContext, GetManagedDIDError, Unit] = syncUnconfirmedUpdateOperationsByDID(did = None) + override protected def getDefaultDidDocumentServices: Set[DidDocumentService] = defaultDidDocumentServices + override def findDIDKeyPair( did: CanonicalPrismDID, keyId: String @@ -125,9 +129,10 @@ class ManagedDIDServiceImpl private[walletapi] ( ): ZIO[WalletAccessContext, CreateManagedDIDError, LongFormPrismDID] = { val effect = for { _ <- ZIO - .fromEither(ManagedDIDTemplateValidator.validate(didTemplate)) + .fromEither(ManagedDIDTemplateValidator.validate(didTemplate, defaultDidDocumentServices)) .mapError(CreateManagedDIDError.InvalidArgument.apply) - material <- didCreateHandler.materialize(didTemplate) + newDidTemplate = didTemplate.copy(services = didTemplate.services ++ defaultDidDocumentServices) + material <- didCreateHandler.materialize(newDidTemplate) _ <- ZIO .fromEither(didOpValidator.validate(material.operation)) .mapError(CreateManagedDIDError.InvalidOperation.apply) @@ -361,11 +366,13 @@ class ManagedDIDServiceImpl private[walletapi] ( object ManagedDIDServiceImpl { val layer: RLayer[ - DIDOperationValidator & DIDService & DIDSecretStorage & DIDNonSecretStorage & WalletSecretStorage & Apollo, + Set[DidDocumentService] & DIDOperationValidator & DIDService & DIDSecretStorage & DIDNonSecretStorage & + WalletSecretStorage & Apollo, ManagedDIDService ] = { ZLayer.fromZIO { for { + defaultDidDocumentServices <- ZIO.service[Set[DidDocumentService]] didService <- ZIO.service[DIDService] didOpValidator <- ZIO.service[DIDOperationValidator] secretStorage <- ZIO.service[DIDSecretStorage] @@ -374,6 +381,7 @@ object ManagedDIDServiceImpl { apollo <- ZIO.service[Apollo] createDIDSem <- Semaphore.make(1) } yield ManagedDIDServiceImpl( + defaultDidDocumentServices, didService, didOpValidator, secretStorage, diff --git a/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/service/ManagedDIDServiceWithEventNotificationImpl.scala b/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/service/ManagedDIDServiceWithEventNotificationImpl.scala index 782ee6d9ec..6938ef3547 100644 --- a/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/service/ManagedDIDServiceWithEventNotificationImpl.scala +++ b/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/service/ManagedDIDServiceWithEventNotificationImpl.scala @@ -4,6 +4,7 @@ import org.hyperledger.identus.agent.walletapi.model.error.CommonWalletStorageEr import org.hyperledger.identus.agent.walletapi.model.ManagedDIDDetail import org.hyperledger.identus.agent.walletapi.storage.{DIDNonSecretStorage, DIDSecretStorage, WalletSecretStorage} import org.hyperledger.identus.castor.core.model.did.CanonicalPrismDID +import org.hyperledger.identus.castor.core.model.did.Service as DidDocumentService import org.hyperledger.identus.castor.core.model.error.DIDOperationError import org.hyperledger.identus.castor.core.service.DIDService import org.hyperledger.identus.castor.core.util.DIDOperationValidator @@ -13,6 +14,7 @@ import org.hyperledger.identus.shared.models.WalletAccessContext import zio.* class ManagedDIDServiceWithEventNotificationImpl( + defaultDidDocumentServices: Set[DidDocumentService], didService: DIDService, didOpValidator: DIDOperationValidator, override private[walletapi] val secretStorage: DIDSecretStorage, @@ -22,6 +24,7 @@ class ManagedDIDServiceWithEventNotificationImpl( createDIDSem: Semaphore, eventNotificationService: EventNotificationService ) extends ManagedDIDServiceImpl( + defaultDidDocumentServices, didService, didOpValidator, secretStorage, @@ -57,11 +60,12 @@ class ManagedDIDServiceWithEventNotificationImpl( object ManagedDIDServiceWithEventNotificationImpl { val layer: RLayer[ - DIDOperationValidator & DIDService & DIDSecretStorage & DIDNonSecretStorage & WalletSecretStorage & Apollo & - EventNotificationService, + Set[DidDocumentService] & DIDOperationValidator & DIDService & DIDSecretStorage & DIDNonSecretStorage & + WalletSecretStorage & Apollo & EventNotificationService, ManagedDIDService ] = ZLayer.fromZIO { for { + defaultDidDocumentServices <- ZIO.service[Set[DidDocumentService]] didService <- ZIO.service[DIDService] didOpValidator <- ZIO.service[DIDOperationValidator] secretStorage <- ZIO.service[DIDSecretStorage] @@ -71,6 +75,7 @@ object ManagedDIDServiceWithEventNotificationImpl { createDIDSem <- Semaphore.make(1) eventNotificationService <- ZIO.service[EventNotificationService] } yield ManagedDIDServiceWithEventNotificationImpl( + defaultDidDocumentServices, didService, didOpValidator, secretStorage, diff --git a/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/util/ManagedDIDTemplateValidator.scala b/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/util/ManagedDIDTemplateValidator.scala index 82abee2b7f..3e9385ae86 100644 --- a/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/util/ManagedDIDTemplateValidator.scala +++ b/cloud-agent/service/wallet-api/src/main/scala/org/hyperledger/identus/agent/walletapi/util/ManagedDIDTemplateValidator.scala @@ -3,15 +3,31 @@ package org.hyperledger.identus.agent.walletapi.util import org.hyperledger.identus.agent.walletapi.model.ManagedDIDTemplate import org.hyperledger.identus.agent.walletapi.service.ManagedDIDService import org.hyperledger.identus.castor.core.model.did.{EllipticCurve, VerificationRelationship} +import org.hyperledger.identus.castor.core.model.did.Service as DidDocumentService object ManagedDIDTemplateValidator { - def validate(template: ManagedDIDTemplate): Either[String, Unit] = + def validate( + template: ManagedDIDTemplate, + defaultDidDocumentServices: Set[DidDocumentService] = Set.empty + ): Either[String, Unit] = for { _ <- validateReservedKeyId(template) _ <- validateCurveUsage(template) + _ <- validatePresenceOfDefaultDidServices(template.services, defaultDidDocumentServices) } yield () + private def validatePresenceOfDefaultDidServices( + services: Seq[DidDocumentService], + defaultDidDocumentServices: Set[DidDocumentService] + ): Either[String, Unit] = { + + services.map(_.id).intersect(defaultDidDocumentServices.toSeq.map(_.id)) match { + case Nil => Right(()) + case x => Left(s"Default DID services cannot be overridden: ${x.mkString("[", ", ", "]")}") + } + } + private def validateReservedKeyId(template: ManagedDIDTemplate): Either[String, Unit] = { val keyIds = template.publicKeys.map(_.id) val reservedKeyIds = keyIds.filter(id => ManagedDIDService.reservedKeyIds.contains(id))