From 376d008bed020c4147dce99b05bff7dac6d64d3a Mon Sep 17 00:00:00 2001 From: Pat Losoponkul Date: Thu, 1 Dec 2022 16:31:39 +0700 Subject: [PATCH] feat(prism-agent): add listManagedDID endpoint --- .../service/api/http/castor/schemas.yaml | 24 +++++++++++++- .../api/http/prism-agent-openapi-spec.yaml | 31 +++++++++++++++---- .../DIDRegistrarApiMarshallerImpl.scala | 10 ++++-- .../server/http/marshaller/JsonSupport.scala | 1 + .../http/model/OASDomainModelHelper.scala | 19 ++++++++++++ .../service/DIDRegistrarApiServiceImpl.scala | 12 +++++++ ...ManagedDIDState.scala => ManagedDID.scala} | 4 ++- .../walletapi/service/ManagedDIDService.scala | 13 +++++++- 8 files changed, 103 insertions(+), 11 deletions(-) rename prism-agent/service/wallet-api/src/main/scala/io/iohk/atala/agent/walletapi/model/{ManagedDIDState.scala => ManagedDID.scala} (74%) diff --git a/prism-agent/service/api/http/castor/schemas.yaml b/prism-agent/service/api/http/castor/schemas.yaml index d299b7ae67..d3a1142cc8 100644 --- a/prism-agent/service/api/http/castor/schemas.yaml +++ b/prism-agent/service/api/http/castor/schemas.yaml @@ -125,7 +125,7 @@ components: properties: did: type: string - example: did:prism:unpublished:7a3a5cd1beab57a65c18c584848029c513ca27c8edfb69ceb2c7aef3d659bf44?instance=https://offchain-storage.com" + example: did:prism:7a3a5cd1beab57a65c18c584848029c513ca27c8edfb69ceb2c7aef3d659bf44?instance=https://offchain-storage.com" updatePublicKey: type: string example: "EiBkRSeixqX-PhOij6PIpuGfPld5Nif5MxcrgtGCw-t6LA" @@ -232,6 +232,28 @@ components: description: A long-form DID for the created DID example: did:prism:1:abc123:abc123 + ListManagedDIDResponse: + type: array + items: + type: object + required: + - did + - status + properties: + did: + type: string + example: did:prism:abc + longFormDid: + type: string + description: A long-form DID. Mandatory when status is not PUBLISHED and optional when status is PUBLISHED + example: did:prism:abc:123 + status: + type: string + enum: + - CREATED + - PUBLICATION_PENDING + - PUBLISHED + Delta: type: object required: diff --git a/prism-agent/service/api/http/prism-agent-openapi-spec.yaml b/prism-agent/service/api/http/prism-agent-openapi-spec.yaml index e445144cd3..84d7ec9efc 100644 --- a/prism-agent/service/api/http/prism-agent-openapi-spec.yaml +++ b/prism-agent/service/api/http/prism-agent-openapi-spec.yaml @@ -316,6 +316,25 @@ paths: $ref: "./castor/schemas.yaml#/components/schemas/ErrorResponse" /did-registrar/dids: + get: + tags: [ "DID Registrar" ] + operationId: listManagedDid + summary: List all DIDs managed by PrismAgent. + description: List all DIDs managed by PrismAgent. + responses: + "200": + description: List managed DIDs + content: + application/json: + schema: + $ref: "./castor/schemas.yaml#/components/schemas/ListManagedDIDResponse" + "422": + description: The DID creation failed. + content: + application/json: + schema: + $ref: "./castor/schemas.yaml#/components/schemas/ErrorResponse" + post: tags: [ "DID Registrar" ] operationId: createManagedDid @@ -745,7 +764,7 @@ paths: application/json: schema: $ref: "./castor/schemas.yaml#/components/schemas/ErrorResponse" - + /issue-credentials/records: get: tags: [ "Issue Credentials Protocol" ] @@ -785,7 +804,7 @@ paths: application/json: schema: $ref: "./pollux/schemas.yaml#/components/schemas/ErrorResponse" - + /issue-credentials/records/{recordId}/accept-offer: post: tags: [ "Issue Credentials Protocol" ] @@ -978,9 +997,9 @@ paths: operationId: createConnection summary: Creates new connection and returns an invitation. description: |- - Returns new invitation object and creates new connection state record in `pending` state. - Content of invitation depends on DIDComm protocol used, here is an example of how it would look like for `AIP 1.0 connection/v1` protocol. - Once connection invitation is accepted, Agent should filter all additional attempts to accept it. + Returns new invitation object and creates new connection state record in `pending` state. + Content of invitation depends on DIDComm protocol used, here is an example of how it would look like for `AIP 1.0 connection/v1` protocol. + Once connection invitation is accepted, Agent should filter all additional attempts to accept it. We consider mult-party connections as out of scope for now. requestBody: required: true @@ -1079,4 +1098,4 @@ paths: content: application/json: schema: - $ref: "./connect/schemas.yaml#/components/schemas/ErrorResponse" + $ref: "./connect/schemas.yaml#/components/schemas/ErrorResponse" diff --git a/prism-agent/service/server/src/main/scala/io/iohk/atala/agent/server/http/marshaller/DIDRegistrarApiMarshallerImpl.scala b/prism-agent/service/server/src/main/scala/io/iohk/atala/agent/server/http/marshaller/DIDRegistrarApiMarshallerImpl.scala index 0971dd02d7..916733b725 100644 --- a/prism-agent/service/server/src/main/scala/io/iohk/atala/agent/server/http/marshaller/DIDRegistrarApiMarshallerImpl.scala +++ b/prism-agent/service/server/src/main/scala/io/iohk/atala/agent/server/http/marshaller/DIDRegistrarApiMarshallerImpl.scala @@ -7,7 +7,8 @@ import io.iohk.atala.agent.openapi.model.{ CreateManagedDIDResponse, CreateManagedDidRequest, DIDOperationResponse, - ErrorResponse + ErrorResponse, + ListManagedDIDResponseInner } import spray.json.RootJsonFormat import zio.* @@ -15,7 +16,7 @@ import zio.* object DIDRegistrarApiMarshallerImpl extends JsonSupport { val layer: ULayer[DIDRegistrarApiMarshaller] = ZLayer.succeed { - new DIDRegistrarApiMarshaller: + new DIDRegistrarApiMarshaller { override implicit def fromEntityUnmarshallerCreateManagedDidRequest : FromEntityUnmarshaller[CreateManagedDidRequest] = summon[RootJsonFormat[CreateManagedDidRequest]] @@ -25,8 +26,13 @@ object DIDRegistrarApiMarshallerImpl extends JsonSupport { override implicit def toEntityMarshallerCreateManagedDIDResponse: ToEntityMarshaller[CreateManagedDIDResponse] = summon[RootJsonFormat[CreateManagedDIDResponse]] + override implicit def toEntityMarshallerListManagedDIDResponseInnerarray + : ToEntityMarshaller[Seq[ListManagedDIDResponseInner]] = + summon[RootJsonFormat[Seq[ListManagedDIDResponseInner]]] + override implicit def toEntityMarshallerErrorResponse: ToEntityMarshaller[ErrorResponse] = summon[RootJsonFormat[ErrorResponse]] + } } } diff --git a/prism-agent/service/server/src/main/scala/io/iohk/atala/agent/server/http/marshaller/JsonSupport.scala b/prism-agent/service/server/src/main/scala/io/iohk/atala/agent/server/http/marshaller/JsonSupport.scala index 3c48ab22b5..2d898a94a7 100644 --- a/prism-agent/service/server/src/main/scala/io/iohk/atala/agent/server/http/marshaller/JsonSupport.scala +++ b/prism-agent/service/server/src/main/scala/io/iohk/atala/agent/server/http/marshaller/JsonSupport.scala @@ -43,6 +43,7 @@ trait JsonSupport extends SprayJsonSupport with DefaultJsonProtocol { given RootJsonFormat[DidOperationType] = jsonFormat0(DidOperationType.apply) given RootJsonFormat[DIDResponse] = jsonFormat2(DIDResponse.apply) given RootJsonFormat[ErrorResponse] = jsonFormat5(ErrorResponse.apply) + given RootJsonFormat[ListManagedDIDResponseInner] = jsonFormat3(ListManagedDIDResponseInner.apply) given RootJsonFormat[PublicKey] = jsonFormat5(PublicKey.apply) given RootJsonFormat[PublicKeyJwk] = jsonFormat5(PublicKeyJwk.apply) given RootJsonFormat[RecoverDIDRequest] = jsonFormat5(RecoverDIDRequest.apply) diff --git a/prism-agent/service/server/src/main/scala/io/iohk/atala/agent/server/http/model/OASDomainModelHelper.scala b/prism-agent/service/server/src/main/scala/io/iohk/atala/agent/server/http/model/OASDomainModelHelper.scala index b21badf2a0..75333f74db 100644 --- a/prism-agent/service/server/src/main/scala/io/iohk/atala/agent/server/http/model/OASDomainModelHelper.scala +++ b/prism-agent/service/server/src/main/scala/io/iohk/atala/agent/server/http/model/OASDomainModelHelper.scala @@ -14,6 +14,7 @@ import io.iohk.atala.agent.openapi.model.{ DidOperationSubmission, IssueCredentialRecord, IssueCredentialRecordCollection, + ListManagedDIDResponseInner, PublicKey, PublicKeyJwk, Service, @@ -35,6 +36,8 @@ import io.iohk.atala.mercury.model.AttachmentDescriptor import io.iohk.atala.mercury.model.Base64 import zio.ZIO import io.iohk.atala.agent.server.http.model.HttpServiceError.InvalidPayload +import io.iohk.atala.agent.walletapi.model.ManagedDIDState +import io.iohk.atala.castor.core.model.did.{LongFormPrismDID, PrismDID} import java.util.UUID import io.iohk.atala.connect.core.model.ConnectionRecord.Role @@ -202,4 +205,20 @@ trait OASDomainModelHelper { ) } + extension (didDetail: walletDomain.ManagedDIDDetail) { + def toOAS: ListManagedDIDResponseInner = { + val (longFormDID, status) = didDetail.state match { + case ManagedDIDState.Created(operation) => Some(PrismDID.buildLongFormFromOperation(operation)) -> "CREATED" + case ManagedDIDState.PublicationPending(operation, _) => + Some(PrismDID.buildLongFormFromOperation(operation)) -> "PUBLICATION_PENDING" + case ManagedDIDState.Published(_, _) => None -> "PUBLISHED" + } + ListManagedDIDResponseInner( + did = didDetail.did.toString, + longFormDid = longFormDID.map(_.toString), + status = status + ) + } + } + } diff --git a/prism-agent/service/server/src/main/scala/io/iohk/atala/agent/server/http/service/DIDRegistrarApiServiceImpl.scala b/prism-agent/service/server/src/main/scala/io/iohk/atala/agent/server/http/service/DIDRegistrarApiServiceImpl.scala index 96b06eaa4a..53775b49e2 100644 --- a/prism-agent/service/server/src/main/scala/io/iohk/atala/agent/server/http/service/DIDRegistrarApiServiceImpl.scala +++ b/prism-agent/service/server/src/main/scala/io/iohk/atala/agent/server/http/service/DIDRegistrarApiServiceImpl.scala @@ -38,6 +38,18 @@ class DIDRegistrarApiServiceImpl(service: ManagedDIDService)(using runtime: Runt } } + override def listManagedDid()(implicit + toEntityMarshallerListManagedDIDResponseInnerarray: ToEntityMarshaller[Seq[ListManagedDIDResponseInner]], + toEntityMarshallerErrorResponse: ToEntityMarshaller[ErrorResponse] + ): Route = { + val result = service.listManagedDID.map(_.map(_.toOAS)) + + onZioSuccess(result.either) { + case Left(error) => ??? // TODO: implement error handling + case Right(result) => listManagedDid200(result) + } + } + override def publishManagedDid(didRef: String)(implicit toEntityMarshallerDIDOperationResponse: ToEntityMarshaller[DIDOperationResponse], toEntityMarshallerErrorResponse: ToEntityMarshaller[ErrorResponse] diff --git a/prism-agent/service/wallet-api/src/main/scala/io/iohk/atala/agent/walletapi/model/ManagedDIDState.scala b/prism-agent/service/wallet-api/src/main/scala/io/iohk/atala/agent/walletapi/model/ManagedDID.scala similarity index 74% rename from prism-agent/service/wallet-api/src/main/scala/io/iohk/atala/agent/walletapi/model/ManagedDIDState.scala rename to prism-agent/service/wallet-api/src/main/scala/io/iohk/atala/agent/walletapi/model/ManagedDID.scala index 9c99eee987..5599723daa 100644 --- a/prism-agent/service/wallet-api/src/main/scala/io/iohk/atala/agent/walletapi/model/ManagedDIDState.scala +++ b/prism-agent/service/wallet-api/src/main/scala/io/iohk/atala/agent/walletapi/model/ManagedDID.scala @@ -1,9 +1,11 @@ package io.iohk.atala.agent.walletapi.model -import io.iohk.atala.castor.core.model.did.PrismDIDOperation +import io.iohk.atala.castor.core.model.did.{CanonicalPrismDID, PrismDIDOperation} import scala.collection.immutable.ArraySeq +final case class ManagedDIDDetail(did: CanonicalPrismDID, state: ManagedDIDState) + sealed trait ManagedDIDState object ManagedDIDState { diff --git a/prism-agent/service/wallet-api/src/main/scala/io/iohk/atala/agent/walletapi/service/ManagedDIDService.scala b/prism-agent/service/wallet-api/src/main/scala/io/iohk/atala/agent/walletapi/service/ManagedDIDService.scala index 3c8d0aae02..bd1a53916a 100644 --- a/prism-agent/service/wallet-api/src/main/scala/io/iohk/atala/agent/walletapi/service/ManagedDIDService.scala +++ b/prism-agent/service/wallet-api/src/main/scala/io/iohk/atala/agent/walletapi/service/ManagedDIDService.scala @@ -1,7 +1,13 @@ package io.iohk.atala.agent.walletapi.service import io.iohk.atala.agent.walletapi.crypto.{ECWrapper, KeyGeneratorWrapper} -import io.iohk.atala.agent.walletapi.model.{DIDPublicKeyTemplate, ECKeyPair, ManagedDIDState, ManagedDIDTemplate} +import io.iohk.atala.agent.walletapi.model.{ + DIDPublicKeyTemplate, + ECKeyPair, + ManagedDIDDetail, + ManagedDIDState, + ManagedDIDTemplate +} import io.iohk.atala.agent.walletapi.model.ECCoordinates.* import io.iohk.atala.agent.walletapi.model.error.{CreateManagedDIDError, PublishManagedDIDError} import io.iohk.atala.agent.walletapi.service.ManagedDIDService.{CreateDIDSecret, DEFAULT_MASTER_KEY_ID} @@ -50,6 +56,11 @@ final class ManagedDIDService private[walletapi] ( private val CURVE = EllipticCurve.SECP256K1 + def listManagedDID: Task[Seq[ManagedDIDDetail]] = nonSecretStorage.listManagedDID + .map(_.toSeq.map { case (did, state) => + ManagedDIDDetail(did = did.asCanonical, state = state) + }) + def publishStoredDID(did: CanonicalPrismDID): IO[PublishManagedDIDError, ScheduleDIDOperationOutcome] = { def syncDLTStateAndPersist = nonSecretStorage