Skip to content

Commit

Permalink
feat(mercury): New Messaging Service with support for forward messagi…
Browse files Browse the repository at this point in the history
…ng (#244)

Add Messaging Service to send messages and forward if needed
Fix port when starting a webServer on AgentCli
  • Loading branch information
FabioPinheiro authored Dec 13, 2022
1 parent 9381b0d commit 7f511e0
Show file tree
Hide file tree
Showing 7 changed files with 243 additions and 95 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import io.iohk.atala.resolvers.PeerDidMediatorSecretResolver
import io.iohk.atala.resolvers.UniversalDidResolver
import io.iohk.atala.mercury.protocol.connection.*
import io.iohk.atala.mercury.protocol.invitation.v2.Invitation
import io.iohk.atala.resolvers.DIDResolver

/** AgentCli
* {{{
Expand Down Expand Up @@ -127,35 +128,12 @@ object AgentCli extends ZIOAppDefault {
reply = outOfBandLoginInvitation.reply(didCommService.myDid)
_ <- Console.printLine(s"Replying to ${outOfBandLoginInvitation.id} with $reply")

encryptedForwardMessage <- didCommService.packEncrypted(reply.makeMsg, to = reply.to)
jsonString = encryptedForwardMessage.string

serviceEndpoint = UniversalDidResolver
.resolve(reply.to.value)
.get()
.getDidCommServices()
.asScala
.toSeq
.headOption
.map(s => s.getServiceEndpoint())

_ <- Console.printLine("Sending to" + serviceEndpoint)
res <- Client
.request(
url = serviceEndpoint.get, // TODO make ERROR type
method = Method.POST,
headers = Headers("content-type" -> MediaTypes.contentTypeEncrypted),
content = Body.fromChunk(Chunk.fromArray(jsonString.getBytes)),
// ssl = ClientSSLOptions.DefaultSSL,
)
.provideSomeLayer(zio.http.Client.default)
.provideSomeLayer(zio.Scope.default)
data <- res.body.asString
_ <- Console.printLine(data)
res <- MessagingService.send(reply.makeMsg)
_ <- Console.printLine(res.bodyAsString)
} yield ()
}

def proposeAndSendCredential: ZIO[DidComm, MercuryError | IOException, Unit] = {
def proposeAndSendCredential: ZIO[DidComm & DIDResolver & HttpClient, MercuryError | IOException, Unit] = {
for {

_ <- Console.printLine("Propose Credential")
Expand Down Expand Up @@ -193,11 +171,11 @@ object AgentCli extends ZIOAppDefault {
msg = proposeCredential.makeMessage
_ <- Console.printLine("Sending: " + msg)

_ <- sendMessage(msg)
_ <- MessagingService.send(msg)
} yield ()
}

def presentProof: ZIO[DidComm, MercuryError | IOException, Unit] = {
def presentProof: ZIO[DidComm & DIDResolver & HttpClient, MercuryError | IOException, Unit] = {
for {
_ <- Console.printLine("Present Proof")
didCommService <- ZIO.service[DidComm]
Expand All @@ -223,11 +201,11 @@ object AgentCli extends ZIOAppDefault {
)
msg = requestPresentation.makeMessage
_ <- Console.printLine("Sending: " + msg)
_ <- sendMessage(msg)
_ <- MessagingService.send(msg)
} yield ()
}

def connect: ZIO[DidComm, MercuryError | IOException, Unit] = {
def connect: ZIO[DidComm & DIDResolver & HttpClient, MercuryError | IOException, Unit] = {

import io.iohk.atala.mercury.protocol.invitation.OutOfBand
import io.circe._, io.circe.parser._
Expand All @@ -250,52 +228,12 @@ object AgentCli extends ZIOAppDefault {
)
msg = connectionRequest.makeMessage
_ <- Console.printLine("Sending: " + msg)
_ <- sendMessage(msg)
_ <- MessagingService.send(msg)

} yield ()
}

/** Encrypt and send a Message via HTTP
*
* TODO Move this method to another model
*/
def sendMessage(msg: Message): ZIO[DidComm, MercuryException, Unit] = { // TODO Throwable
for {
didCommService <- ZIO.service[DidComm]

encryptedForwardMessage <- didCommService.packEncrypted(msg, to = msg.to.head) // TODO head
jsonString = encryptedForwardMessage.string

serviceEndpoint = UniversalDidResolver
.resolve(msg.to.head.value) // TODO head
.get()
.getDidCommServices()
.asScala
.toSeq
.headOption
.map(s => s.getServiceEndpoint())
.get // TODO make ERROR type

_ <- Console.printLine("Sending to" + serviceEndpoint)

res <- Client
.request(
url = serviceEndpoint,
method = Method.POST,
headers = Headers("content-type" -> MediaTypes.contentTypeEncrypted),
content = Body.fromChunk(Chunk.fromArray(jsonString.getBytes)),
// ssl = ClientSSLOptions.DefaultSSL,
)
.provideSomeLayer(zio.http.Client.default)
.provideSomeLayer(zio.Scope.default)
.catchNonFatalOrDie { ex => ZIO.fail(SendMessage(ex)) }
data <- res.body.asString
.catchNonFatalOrDie { ex => ZIO.fail(ParseResponse(ex)) }
_ <- Console.printLine(data)
} yield ()
}

def webServer(port: Int): HttpApp[DidComm, Throwable] = {
def webServer: HttpApp[DidComm & DIDResolver & HttpClient, Throwable] = {
val header = "content-type" -> MediaTypes.contentTypeEncrypted
Http
.collectZIO[Request] {
Expand All @@ -311,12 +249,14 @@ object AgentCli extends ZIOAppDefault {
}
.map(str => Response.text(str))
case Method.GET -> !! / "test" => ZIO.succeed(Response.text("Test ok!"))
case req => ZIO.succeed(Response.text(s"The request must be a POST to root with the Header $header"))
case req =>
ZIO.logWarning(s"Recive a not DID Comm v2 messagem: ${req}") *>
ZIO.succeed(Response.text(s"The request must be a POST to root with the Header $header"))
}

}

def startEndpoint = for {
def startEndpoint: ZIO[DidComm & DIDResolver & HttpClient, IOException, Unit] = for {
_ <- Console.printLine("Setup a endpoint")
didCommService <- ZIO.service[DidComm]

Expand All @@ -337,8 +277,18 @@ object AgentCli extends ZIOAppDefault {
case "" => ZIO.succeed(defualtPort)
case str => ZIO.succeed(str.toIntOption.getOrElse(defualtPort))
}
_ <- Server.serve(webServer(port)).debug.fork
_ <- Console.printLine("Endpoint Started")
server = {
val config = ServerConfig(address = new java.net.InetSocketAddress(port))
ServerConfig.live(config)(using Trace.empty) >>> Server.live
}
_ <- Server
.serve(webServer)
.provideSomeLayer(server)
.debug
.flatMap(e => Console.printLine("Endpoint stop"))
.catchAll { case ex => Console.printLine(s"Endpoint FAIL ${ex.getMessage()}") }
.fork
_ <- Console.printLine(s"Endpoint Started of port '$port'")
} yield ()

def run = for {
Expand All @@ -365,29 +315,30 @@ object AgentCli extends ZIOAppDefault {
} yield (peer)

didCommLayer = agentLayer(agentDID)
layers: ZLayer[Any, Nothing, AgentServiceAny & HttpClient] = didCommLayer ++ ZioHttpClient.layer
layers: ZLayer[Any, Nothing, AgentServiceAny & DIDResolver & HttpClient] =
didCommLayer ++ DIDResolver.layer ++ ZioHttpClient.layer

_ <- options(
Seq(
"none" -> ZIO.unit,
"Show DID" -> Console.printLine(agentDID),
"Get DID Document" -> Console.printLine("DID Document:") *> Console.printLine(agentDID.getDIDDocument),
"Start WebServer endpoint" -> startEndpoint.provide(zio.http.Server.default, didCommLayer),
"Start WebServer endpoint" -> startEndpoint.provide(layers),
"Ask for Mediation Coordinate" -> askForMediation.provide(layers),
"Generate login invitation" -> generateLoginInvitation.provide(didCommLayer),
"Login with DID" -> loginInvitation.provide(didCommLayer),
"Propose Credential" -> proposeAndSendCredential.provide(didCommLayer),
"Present Proof" -> presentProof.provide(didCommLayer),
"Login with DID" -> loginInvitation.provide(layers),
"Propose Credential" -> proposeAndSendCredential.provide(layers),
"Present Proof" -> presentProof.provide(layers),
"Generate Connection invitation" -> generateConnectionInvitation.provide(didCommLayer),
"Connect" -> connect.provide(didCommLayer),
"Connect" -> connect.provide(layers),
)
).repeatWhile((_) => true)

} yield ()

def webServerProgram(
jsonString: String
): ZIO[DidComm, MercuryThrowable, String] = { // TODO Throwable
): ZIO[DidComm & DIDResolver & HttpClient, MercuryThrowable, String] = { // TODO Throwable
import io.iohk.atala.mercury.DidComm.*
ZIO.logAnnotate("request-id", java.util.UUID.randomUUID.toString()) {
for {
Expand All @@ -413,7 +364,7 @@ object AgentCli extends ZIOAppDefault {

didCommService <- ZIO.service[DidComm]
msgToSend = offer.makeMessage
_ <- sendMessage(msgToSend)
_ <- MessagingService.send(msgToSend)
} yield ("OfferCredential Sent")

case s if s == OfferCredential.`type` => // Holder
Expand All @@ -426,7 +377,7 @@ object AgentCli extends ZIOAppDefault {

didCommService <- ZIO.service[DidComm]
msgToSend = requestCredential.makeMessage
_ <- sendMessage(msgToSend)
_ <- MessagingService.send(msgToSend)
} yield ("RequestCredential Sent")

case s if s == RequestCredential.`type` => // Issuer
Expand All @@ -438,7 +389,7 @@ object AgentCli extends ZIOAppDefault {

didCommService <- ZIO.service[DidComm]
msgToSend = issueCredential.makeMessage
_ <- sendMessage(msgToSend)
_ <- MessagingService.send(msgToSend)
} yield ("IssueCredential Sent")

case s if s == IssueCredential.`type` => // Holder
Expand All @@ -457,7 +408,7 @@ object AgentCli extends ZIOAppDefault {
presentation = Presentation.makePresentationFromRequest(msg)
didCommService <- ZIO.service[DidComm]
msgToSend = presentation.makeMessage
_ <- sendMessage(msgToSend)
_ <- MessagingService.send(msgToSend)
} yield ("Presentation Sent")
case s if s == Presentation.`type` => // Verifier
for {
Expand All @@ -478,7 +429,7 @@ object AgentCli extends ZIOAppDefault {
// _ <- ZIO.logInfo(s"My new DID => $peer")
connectionResponse = ConnectionResponse.makeResponseFromRequest(msg)
msgToSend = connectionResponse.makeMessage
_ <- sendMessage(msgToSend)
_ <- MessagingService.send(msgToSend)
} yield ("Connection Request Sent")
case s if s == ConnectionResponse.`type` => // Invitee
for {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import io.iohk.atala.mercury.DidComm

case class AgentService[A <: Agent](didComm: DIDComm, did: A) extends AgentServiceAny(didComm, did.id)

//TODO FIX THE NAME !!!
class AgentServiceAny(didComm: DIDComm, val myDid: DidId) extends DidComm {

override def packSigned(msg: Message): UIO[SignedMesage] = {
Expand All @@ -20,16 +21,22 @@ class AgentServiceAny(didComm: DIDComm, val myDid: DidId) extends DidComm {
}

override def packEncrypted(msg: Message, to: DidId): UIO[EncryptedMessage] = {

assert(msg.from == Some(myDid), s"ERROR in packEncrypted: ${msg.from} must be == to ${myDid}")

val params = new PackEncryptedParams.Builder(msg, to.value)
.from(myDid.value)
.forward(false)
.build()

didComm.packEncrypted(params)
ZIO.succeed(didComm.packEncrypted(params))
}

override def packEncryptedForward(msg: Message, to: DidId): UIO[EncryptedMessage] = {
assert(msg.from == Some(myDid), s"ERROR in packEncrypted: ${msg.from} must be == to ${myDid}")
val params = new PackEncryptedParams.Builder(msg, to.value)
.from(myDid.value)
.forward(true)
.build()
didComm.packEncrypted(params)
ZIO.succeed(didComm.packEncrypted(params))
}

Expand Down
Loading

0 comments on commit 7f511e0

Please sign in to comment.