diff --git a/infrastructure/local/.env b/infrastructure/local/.env index 856862357a..3861fcb7be 100644 --- a/infrastructure/local/.env +++ b/infrastructure/local/.env @@ -1,5 +1,5 @@ MERCURY_MEDIATOR_VERSION=0.2.0 IRIS_SERVICE_VERSION=0.1.0 PRISM_AGENT_VERSION=0.22.0 -PRISM_NODE_VERSION=2.0.0 +PRISM_NODE_VERSION=v2.0.0 PORT=80 diff --git a/prism-agent/service/api/http/pollux/schemas.yaml b/prism-agent/service/api/http/pollux/schemas.yaml index c94ce00a21..fdd72d3fce 100644 --- a/prism-agent/service/api/http/pollux/schemas.yaml +++ b/prism-agent/service/api/http/pollux/schemas.yaml @@ -540,16 +540,20 @@ components: type: string PresentationStatus: description: Presentation Status - required: [presentationId, status, proofs] + required: [presentationId, status, proofs, data] properties: presentationId: type: string status: type: string proofs: - type: array + type: array items: $ref: "#/components/schemas/ProofRequestAux" + data: + type: array + items: + type: string connectionId: type: string RequestPresentationAction: diff --git a/prism-agent/service/project/Dependencies.scala b/prism-agent/service/project/Dependencies.scala index b3562c592a..748c4598f1 100644 --- a/prism-agent/service/project/Dependencies.scala +++ b/prism-agent/service/project/Dependencies.scala @@ -9,7 +9,7 @@ object Dependencies { val akka = "2.6.20" val akkaHttp = "10.2.9" val castor = "0.5.1" - val pollux = "0.13.0" + val pollux = "0.14.0" val connect = "0.6.0" val bouncyCastle = "1.70" val logback = "1.4.5" diff --git a/prism-agent/service/server/src/main/scala/io/iohk/atala/agent/server/Main.scala b/prism-agent/service/server/src/main/scala/io/iohk/atala/agent/server/Main.scala index 31c6bf35e4..ef1d5d1a81 100644 --- a/prism-agent/service/server/src/main/scala/io/iohk/atala/agent/server/Main.scala +++ b/prism-agent/service/server/src/main/scala/io/iohk/atala/agent/server/Main.scala @@ -87,6 +87,8 @@ object Main extends ZIOAppDefault { app <- appComponents(didCommServicePort, restServicePort).provide( didCommAgentLayer(didCommServiceUrl), + AppModule.didJwtResolverlayer, + AppModule.didServiceLayer, DIDResolver.layer, ZioHttpClient.layer, AppModule.credentialServiceLayer, diff --git a/prism-agent/service/server/src/main/scala/io/iohk/atala/agent/server/Modules.scala b/prism-agent/service/server/src/main/scala/io/iohk/atala/agent/server/Modules.scala index d424d784c3..3d15212324 100644 --- a/prism-agent/service/server/src/main/scala/io/iohk/atala/agent/server/Modules.scala +++ b/prism-agent/service/server/src/main/scala/io/iohk/atala/agent/server/Modules.scala @@ -91,6 +91,9 @@ import io.circe.DecodingFailure import io.iohk.atala.agent.walletapi.sql.JdbcDIDSecretStorage import io.iohk.atala.resolvers.DIDResolver import io.iohk.atala.agent.walletapi.storage.DIDSecretStorage +import io.iohk.atala.pollux.vc.jwt.{DidResolver => JwtDidResolver} +import io.iohk.atala.castor.core.model.error.DIDOperationError.TooManyDidServiceAccess +import io.iohk.atala.pollux.vc.jwt.PrismDidResolver object Modules { @@ -153,13 +156,16 @@ object Modules { Server.start(port, app) } - val didCommExchangesJob - : RIO[DIDResolver & HttpClient & CredentialService & ManagedDIDService & DIDSecretStorage, Unit] = + val didCommExchangesJob: RIO[ + DIDResolver & JwtDidResolver & HttpClient & CredentialService & ManagedDIDService & DIDSecretStorage, + Unit + ] = BackgroundJobs.didCommExchanges .repeat(Schedule.spaced(10.seconds)) .unit - val presentProofExchangeJob: RIO[DIDResolver & HttpClient & PresentationService & ManagedDIDService, Unit] = + val presentProofExchangeJob + : RIO[DIDResolver & JwtDidResolver & HttpClient & PresentationService & ManagedDIDService, Unit] = BackgroundJobs.presentProofExchanges .repeat(Schedule.spaced(10.seconds)) .unit @@ -397,6 +403,9 @@ object SystemModule { object AppModule { val didOpValidatorLayer: ULayer[DIDOperationValidator] = DIDOperationValidator.layer() + val didJwtResolverlayer: URLayer[DIDService, JwtDidResolver] = + ZLayer.fromFunction(PrismDidResolver(_)) + val didServiceLayer: TaskLayer[DIDService] = (didOpValidatorLayer ++ GrpcModule.layers) >>> DIDServiceImpl.layer 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 52f00749c4..96432b1b8a 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 @@ -74,7 +74,7 @@ trait JsonSupport extends SprayJsonSupport with DefaultJsonProtocol { given RootJsonFormat[ProofRequestAux] = jsonFormat2(ProofRequestAux.apply) given RootJsonFormat[RequestPresentationInput] = jsonFormat2(RequestPresentationInput.apply) given RootJsonFormat[RequestPresentationOutput] = jsonFormat1(RequestPresentationOutput.apply) - given RootJsonFormat[PresentationStatus] = jsonFormat4(PresentationStatus.apply) + given RootJsonFormat[PresentationStatus] = jsonFormat5(PresentationStatus.apply) given RootJsonFormat[RequestPresentationAction] = jsonFormat2(RequestPresentationAction.apply) // Connections Management diff --git a/prism-agent/service/server/src/main/scala/io/iohk/atala/agent/server/http/service/PresentProofApiServiceImpl.scala b/prism-agent/service/server/src/main/scala/io/iohk/atala/agent/server/http/service/PresentProofApiServiceImpl.scala index 1e77853529..12def6a8bc 100644 --- a/prism-agent/service/server/src/main/scala/io/iohk/atala/agent/server/http/service/PresentProofApiServiceImpl.scala +++ b/prism-agent/service/server/src/main/scala/io/iohk/atala/agent/server/http/service/PresentProofApiServiceImpl.scala @@ -5,7 +5,6 @@ import io.iohk.atala.agent.openapi.model.* import akka.http.scaladsl.server.Directives.* import akka.http.scaladsl.marshalling.ToEntityMarshaller import akka.http.scaladsl.server.Route - import zio._ import scala.concurrent.Future import io.iohk.atala.agent.server.http.model.HttpServiceError @@ -24,6 +23,7 @@ import io.iohk.atala.pollux.vc.jwt.Issuer import io.iohk.atala.pollux.core.service.PresentationService import io.iohk.atala.pollux.core.model.error.PresentationError import io.iohk.atala.pollux.core.model.PresentationRecord +import io.iohk.atala.mercury.model.Base64 class PresentProofApiServiceImpl( presentationService: PresentationService, @@ -88,7 +88,18 @@ class PresentProofApiServiceImpl( presentationStatus = records.map { record => val connectionId = record.connectionId - PresentationStatus(record.id.toString, record.protocolState.toString, Seq.empty, connectionId) + val data = record.presentationData match + case Some(p) => + p.attachments.head.data match { + case Base64(data) => + val base64Decoded = new String(java.util.Base64.getDecoder().decode(data)).drop(1).dropRight(1) + println(s"Base64decode:\n\n ${base64Decoded} \n\n") + Seq(base64Decoded) + case any => ??? + } + case None => Seq.empty + + PresentationStatus(record.id.toString, record.protocolState.toString, Seq.empty, data, connectionId) } } yield presentationStatus diff --git a/prism-agent/service/server/src/main/scala/io/iohk/atala/agent/server/jobs/BackgroundJobs.scala b/prism-agent/service/server/src/main/scala/io/iohk/atala/agent/server/jobs/BackgroundJobs.scala index 1cad8d9f36..dd6bb702f4 100644 --- a/prism-agent/service/server/src/main/scala/io/iohk/atala/agent/server/jobs/BackgroundJobs.scala +++ b/prism-agent/service/server/src/main/scala/io/iohk/atala/agent/server/jobs/BackgroundJobs.scala @@ -7,10 +7,10 @@ import io.iohk.atala.pollux.core.model.IssueCredentialRecord import io.iohk.atala.pollux.core.model.error.CredentialServiceError import io.iohk.atala.pollux.core.service.CredentialService import io.iohk.atala.pollux.vc.jwt.W3cCredentialPayload -import zio.* - +import zio.Duration import java.time.Instant - +import java.time.Clock +import java.time.ZoneId import io.iohk.atala.mercury.DidComm import io.iohk.atala.mercury.MediaTypes import io.iohk.atala.mercury.MessagingService @@ -22,7 +22,7 @@ import io.iohk.atala.mercury.protocol.presentproof.RequestPresentation import io.iohk.atala.resolvers.DIDResolver import io.iohk.atala.resolvers.UniversalDidResolver import java.io.IOException - +import io.iohk.atala.pollux.vc.jwt._ import zhttp.service._ import zhttp.http._ import io.iohk.atala.pollux.vc.jwt.W3CCredential @@ -37,7 +37,7 @@ import io.iohk.atala.agent.walletapi.model.error.DIDSecretStorageError import io.iohk.atala.agent.walletapi.model.ManagedDIDTemplate import io.iohk.atala.agent.walletapi.sql.JdbcDIDSecretStorage import io.iohk.atala.pollux.vc.jwt.ES256KSigner -import io.iohk.atala.castor.core.model.did.EllipticCurve +import io.iohk.atala.castor.core.model.did._ import java.security.KeyFactory import java.security.spec.EncodedKeySpec import java.security.spec.ECPrivateKeySpec @@ -53,6 +53,9 @@ import io.circe.Json import io.circe.syntax._ import io.iohk.atala.agent.walletapi.storage.DIDSecretStorage import io.iohk.atala.agent.walletapi.model.error.CreateManagedDIDError +import io.iohk.atala.pollux.vc.jwt.JWT +import io.iohk.atala.pollux.vc.jwt.{DidResolver => JwtDidResolver} +import io.iohk.atala.agent.walletapi.model._ object BackgroundJobs { @@ -77,7 +80,10 @@ object BackgroundJobs { private[this] def performExchange( record: IssueCredentialRecord - ): URIO[DIDResolver & HttpClient & CredentialService & ManagedDIDService & DIDSecretStorage, Unit] = { + ): URIO[ + DIDResolver & JwtDidResolver & HttpClient & CredentialService & ManagedDIDService & DIDSecretStorage, + Unit + ] = { import IssueCredentialRecord._ import IssueCredentialRecord.ProtocolState._ import IssueCredentialRecord.PublicationState._ @@ -249,9 +255,16 @@ object BackgroundJobs { private[this] def createPrismDIDIssuer(): ZIO[ManagedDIDService & DIDSecretStorage, Throwable, Issuer] = { for { managedDIDService <- ZIO.service[ManagedDIDService] - longFormPrismDID <- managedDIDService.createAndStoreDID(ManagedDIDTemplate(Nil, Nil)) + longFormPrismDID <- managedDIDService.createAndStoreDID( + ManagedDIDTemplate( + Seq( + DIDPublicKeyTemplate("issuing", VerificationRelationship.Authentication) + ), + Nil + ) + ) didSecretStorage <- ZIO.service[DIDSecretStorage] - maybeECKeyPair <- didSecretStorage.getKey(longFormPrismDID.asCanonical, "master0") + maybeECKeyPair <- didSecretStorage.getKey(longFormPrismDID.asCanonical, "issuing") _ <- ZIO.logInfo(s"ECKeyPair => $maybeECKeyPair") maybeIssuer <- ZIO.succeed(maybeECKeyPair.map(ecKeyPair => { val ba = ecKeyPair.privateKey.toPaddedByteArray(EllipticCurve.SECP256K1) @@ -284,7 +297,7 @@ object BackgroundJobs { private[this] def performPresentation( record: PresentationRecord - ): URIO[DIDResolver & HttpClient & PresentationService & ManagedDIDService, Unit] = { + ): URIO[DIDResolver & JwtDidResolver & HttpClient & PresentationService & ManagedDIDService, Unit] = { import io.iohk.atala.pollux.core.model.PresentationRecord.ProtocolState._ val aux = for { @@ -332,14 +345,43 @@ object BackgroundJobs { } yield () case PresentationRecord(id, _, _, _, _, _, _, _, PresentationSent, _, _, _) => ZIO.logDebug("PresentationRecord: PresentationSent") *> ZIO.unit - case PresentationRecord(id, _, _, _, _, _, _, _, PresentationReceived, _, _, _) => + case PresentationRecord(id, _, _, _, _, _, _, _, PresentationReceived, _, _, presentation) => // Verifier ZIO.logDebug("PresentationRecord: PresentationReceived") *> ZIO.unit - for { - _ <- ZIO.log(s"PresentationRecord: PresentationPending (Send Massage)") - // TODO Verify https://input-output.atlassian.net/browse/ATL-2702 - service <- ZIO.service[PresentationService] - _ <- service.markPresentationVerified(id) - } yield () + val clock = java.time.Clock.system(ZoneId.systemDefault) + presentation match + case None => ZIO.fail(InvalidState("PresentationRecord in 'PresentationReceived' with no Presentation")) + case Some(p) => + for { + _ <- ZIO.log(s"PresentationRecord: 'PresentationReceived' ") + didResolverService <- ZIO.service[JwtDidResolver] + credentialsValidationResult <- p.attachments.head.data match { + case Base64(data) => + val base64Decoded = new String(java.util.Base64.getDecoder().decode(data)).drop(1).dropRight(1) + + println(s"Base64decode:\n\n ${base64Decoded} \n\n") + JwtPresentation.verify( + JWT(base64Decoded), + JwtPresentation.PresentationVerificationOptions( + maybeProofPurpose = Some(VerificationRelationship.Authentication), + verifySignature = false, + verifyDates = true, + leeway = Duration.Zero, + maybeCredentialOptions = Some( + CredentialVerification.CredentialVerificationOptions( + verifySignature = true, + verifyDates = false, + leeway = Duration.Zero, + maybeProofPurpose = Some(VerificationRelationship.Authentication) + ) + ) + ) + )(didResolverService)(clock) + case any => ZIO.fail(NotImplemented) + } + _ <- ZIO.log(s"CredentialsValidationResult: $credentialsValidationResult") + service <- ZIO.service[PresentationService] + _ <- service.markPresentationVerified(id) + } yield () // TODO move the state to PresentationVerified case PresentationRecord(id, _, _, _, _, _, _, _, PresentationVerified, _, _, _) => ZIO.logDebug("PresentationRecord: PresentationVerified") *> ZIO.unit diff --git a/prism-agent/service/version.sbt b/prism-agent/service/version.sbt index 31f84d3dcd..5310e30e60 100644 --- a/prism-agent/service/version.sbt +++ b/prism-agent/service/version.sbt @@ -1 +1 @@ -ThisBuild / version := "0.9.0-SNAPSHOT" +ThisBuild / version := "0.17.0-SNAPSHOT"