diff --git a/mediator/src/main/scala/io/iohk/atala/mediator/protocols/DiscoverFeaturesExecuter.scala b/mediator/src/main/scala/io/iohk/atala/mediator/protocols/DiscoverFeaturesExecuter.scala new file mode 100644 index 00000000..537eb7fc --- /dev/null +++ b/mediator/src/main/scala/io/iohk/atala/mediator/protocols/DiscoverFeaturesExecuter.scala @@ -0,0 +1,80 @@ +package io.iohk.atala.mediator.protocols + +import fmgp.crypto.error.FailToParse +import fmgp.did.Agent +import fmgp.did.comm.{PIURI, PlaintextMessage} +import fmgp.did.comm.protocol.discoverfeatures2._ +import io.iohk.atala.mediator.{MediatorDidError, MediatorError} +import io.iohk.atala.mediator.actions.{Action, NoReply, ProtocolExecuter, ProtocolExecuterWithServices, Reply} +import zio.ZIO + +object DiscoverFeaturesExecuter extends ProtocolExecuterWithServices[ProtocolExecuter.Services, MediatorError] { + + override def supportedPIURI: Seq[PIURI] = Seq(FeatureQuery.piuri, FeatureDisclose.piuri) + + override def program[R1 <: Agent]( + plaintextMessage: PlaintextMessage + ): ZIO[R1, MediatorError, Action] = { + // the val is from the match to be definitely stable + val piuriFeatureQuery = FeatureQuery.piuri + val piuriFeatureDisclose = FeatureDisclose.piuri + + plaintextMessage.`type` match + case `piuriFeatureQuery` => + for { + ret <- plaintextMessage.toFeatureQuery match + case Left(error) => + ZIO.logError(s"Fail in FeatureQuery: $error") *> + ZIO.fail(MediatorDidError(FailToParse(error))) + case Right(featureQuery) => + for { + _ <- ZIO.logInfo(featureQuery.toString()) + agent <- ZIO.service[Agent] + allProtocols = Seq( + FeatureDisclose.Disclose( + `feature-type` = "protocol", + id = "https://didcomm.org/routing/2.0", + roles = Some(Seq("mediator")), // sender + ), + FeatureDisclose.Disclose( + `feature-type` = "protocol", + id = "https://didcomm.org/coordinate-mediation/2.0", + roles = Some(Seq("responder")), // requester + ), + FeatureDisclose.Disclose( + `feature-type` = "protocol", + id = "https://didcomm.org/messagepickup/3.0", + roles = Some(Seq("mediator")), // recipient + ), + FeatureDisclose.Disclose( + `feature-type` = "protocol", + id = "https://didcomm.org/trust-ping/2.0", + roles = Some(Seq("receiver")), // sender + ), + FeatureDisclose.Disclose( + `feature-type` = "protocol", + id = "https://didcomm.org/discover-features/2.0", + roles = Some(Seq("responder")), // requester + ), + ) + filter = featureQuery.queries + .filter(q => q.`feature-type` == "protocol") + .map(q => scala.util.matching.Regex(q.`match`)) + discloses = filter.flatMap(reg => allProtocols.filter(e => reg.matches(e.id))).toSet + } yield FeatureDisclose( + thid = Some(featureQuery.id), + to = Set(featureQuery.from.asTO), + from = agent.id, + disclosures = discloses.toSeq, + ) + } yield Reply(ret.toPlaintextMessage) + + case `piuriFeatureDisclose` => + for { + _ <- plaintextMessage.toFeatureDisclose match + case Left(error) => ZIO.fail(MediatorDidError(FailToParse(error))) + case Right(featureDisclose) => ZIO.logInfo(featureDisclose.toString()) + } yield NoReply + } + +} diff --git a/mediator/src/test/scala/io/iohk/atala/mediator/db/AgentStub.scala b/mediator/src/test/scala/io/iohk/atala/mediator/db/AgentStub.scala index 57dde06d..d2e3bf99 100644 --- a/mediator/src/test/scala/io/iohk/atala/mediator/db/AgentStub.scala +++ b/mediator/src/test/scala/io/iohk/atala/mediator/db/AgentStub.scala @@ -45,6 +45,7 @@ object AgentStub { def bobAgentLayer: ULayer[Agent] = ZLayer.succeed(bobAgent) + /** Mediator */ val agentLayer = mediatorConfig.agentLayer } diff --git a/mediator/src/test/scala/io/iohk/atala/mediator/db/DidAccountStubSetup.scala b/mediator/src/test/scala/io/iohk/atala/mediator/db/DidAccountStubSetup.scala index 3ea4fd57..4292404d 100644 --- a/mediator/src/test/scala/io/iohk/atala/mediator/db/DidAccountStubSetup.scala +++ b/mediator/src/test/scala/io/iohk/atala/mediator/db/DidAccountStubSetup.scala @@ -1,37 +1,44 @@ package io.iohk.atala.mediator.db +import fmgp.did.DIDSubject import fmgp.did.comm.{EncryptedMessage, PlaintextMessage} import fmgp.did.method.peer.{DIDPeer2, DIDPeerServiceEncoded} //import io.iohk.atala.mediator.db.AgentStub.{keyAgreement, keyAuthentication} import zio.json.* trait DidAccountStubSetup { val alice = - "did:peer:2.Ez6LSghwSE437wnDE1pt3X6hVDUQzSjsHzinpX3XFvMjRAm7y.Vz6Mkhh1e5CEYYq6JBUcTZ6Cp2ranCWRrv7Yax3Le4N59R6dd.SeyJ0IjoiZG0iLCJzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwIiwiciI6W10sImEiOlsiZGlkY29tbS92MiJdfQ" + DIDSubject( + "did:peer:2.Ez6LSghwSE437wnDE1pt3X6hVDUQzSjsHzinpX3XFvMjRAm7y.Vz6Mkhh1e5CEYYq6JBUcTZ6Cp2ranCWRrv7Yax3Le4N59R6dd.SeyJ0IjoiZG0iLCJzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwIiwiciI6W10sImEiOlsiZGlkY29tbS92MiJdfQ" + ) val bob = - "did:peer:2.Ez6LSkGy3e2z54uP4U9HyXJXRpaF2ytsnTuVgh6SNNmCyGZQZ.Vz6Mkjdwvf9hWc6ibZndW9B97si92DSk9hWAhGYBgP9kUFk8Z.SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9ib2IuZGlkLmZtZ3AuYXBwLyIsInIiOltdLCJhIjpbImRpZGNvbW0vdjIiXX0" + DIDSubject( + "did:peer:2.Ez6LSkGy3e2z54uP4U9HyXJXRpaF2ytsnTuVgh6SNNmCyGZQZ.Vz6Mkjdwvf9hWc6ibZndW9B97si92DSk9hWAhGYBgP9kUFk8Z.SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9ib2IuZGlkLmZtZ3AuYXBwLyIsInIiOltdLCJhIjpbImRpZGNvbW0vdjIiXX0" + ) - val encryptedMessageAlice: Either[String, EncryptedMessage] = """{ - | "ciphertext": "L8wzawffzL7kbVyDcMiHgQMwlqLUqWDYOwH4f0VOFK7sJL8vO-H_JBDCADu7gvH1MDHdVJDXQmSv5dDXp6JYubagcSfBqyZGKGOQDQz-1Ir6-sqZ9K5xRPMt76dYbSswrxhaROVJvtAXyrTmN3KEv8SgP_vt8za5QU6B8cM6gp2CycJKoIhETnhVEVjHnrX0YcyzBsLhd-ZKb8e1Nlz_XSh-3cw1oIQMFjXHnU3PSjrqXcrC-4qSGpVVpHvMSOF3o2EbLGEpP-8UbI0psgSLd9a2VUF9xV55r7Bvn_zJp6tC3-KZKNLO0Rc2K-6JRgyyZjo7O_8aj7Ns6Lx0OjUXoKLiA6B79goHiv8qxJ04k5EWD_h8gt4M3_oByH_cVXH35RDK5SwNV6cVl6zRqiHUR9Ilivh6kfOLGqM2sXCKpXE78qRgHOBeOtl08JHFQO5oFkt1ob8iDqczX0nu-qwlckiibnPK1VvhFnmgLyc9lIUsi_xlCNKqIBZCKoi03xrjNobcM1dWFG7yE04nT-sSiakRNwVHBmNCyA5JhEFQ92d1xpXFGM1ojtiHCPkN5nqe7lMYVM2r7QFnN1xTHwaDWddKprW3vkz_RP7tpoPlWk6X8rLoYUvYc3MqNdbj91QMlho5rU472EX3gprIDeNV7VQiKWoAksFe1hdt62zLH8mJJjUZ3lyq4YjOmrqg7g6RArUWC6KbPgmnuJCqwigpjlwRUCBTPISzaZETAisyluIyuMW8QlRCSQdWnfPZAU2fpLBcviMODMzZTULECvRBef05Fvtd_xRCCbpKpDkGxAY", - | "protected": "eyJlcGsiOnsia3R5IjoiT0tQIiwiY3J2IjoiWDI1NTE5IiwieCI6Ikp2TXhvYXZJaUxaUWVrNDA2eXNtWThQOGpkZGFHSjVIaVNRR0ltWHZWQ2MifSwiYXB2IjoiLWNOQ3l0eFVrSHpSRE5SckV2Vm05S0VmZzhZcUtQVnVVcVg1a0VLbU9yMCIsInNraWQiOiJkaWQ6cGVlcjoyLkV6NkxTa0d5M2UyejU0dVA0VTlIeVhKWFJwYUYyeXRzblR1VmdoNlNOTm1DeUdaUVouVno2TWtqZHd2ZjloV2M2aWJabmRXOUI5N3NpOTJEU2s5aFdBaEdZQmdQOWtVRms4Wi5TZXlKMElqb2laRzBpTENKeklqb2lhSFIwY0hNNkx5OWliMkl1Wkdsa0xtWnRaM0F1WVhCd0x5SXNJbklpT2x0ZExDSmhJanBiSW1ScFpHTnZiVzB2ZGpJaVhYMCM2TFNrR3kzZTJ6NTR1UDRVOUh5WEpYUnBhRjJ5dHNuVHVWZ2g2U05ObUN5R1pRWiIsImFwdSI6IlpHbGtPbkJsWlhJNk1pNUZlalpNVTJ0SGVUTmxNbm8xTkhWUU5GVTVTSGxZU2xoU2NHRkdNbmwwYzI1VWRWWm5hRFpUVGs1dFEzbEhXbEZhTGxaNk5rMXJhbVIzZG1ZNWFGZGpObWxpV201a1Z6bENPVGR6YVRreVJGTnJPV2hYUVdoSFdVSm5VRGxyVlVack9Gb3VVMlY1U2pCSmFtOXBXa2N3YVV4RFNucEphbTlwWVVoU01HTklUVFpNZVRscFlqSkpkVnBIYkd0TWJWcDBXak5CZFZsWVFuZE1lVWx6U1c1SmFVOXNkR1JNUTBwb1NXcHdZa2x0VW5CYVIwNTJZbGN3ZG1ScVNXbFlXREFqTmt4VGEwZDVNMlV5ZWpVMGRWQTBWVGxJZVZoS1dGSndZVVl5ZVhSemJsUjFWbWRvTmxOT1RtMURlVWRhVVZvIiwidHlwIjoiYXBwbGljYXRpb24vZGlkY29tbS1lbmNyeXB0ZWQranNvbiIsImVuYyI6IkEyNTZDQkMtSFM1MTIiLCJhbGciOiJFQ0RILTFQVStBMjU2S1cifQ", - | "recipients": [{ - | "encrypted_key": "eFHcJkoUle7ZkksvZjvhJHLagF7y5B5gDQX11tc1kus2xa3Vn_QmzyVwFzScOHTCEjWRUe7r63rHBFBw0El2ukZW2tcitxr8", - | "header": { - | "kid": "did:peer:2.Ez6LSghwSE437wnDE1pt3X6hVDUQzSjsHzinpX3XFvMjRAm7y.Vz6Mkhh1e5CEYYq6JBUcTZ6Cp2ranCWRrv7Yax3Le4N59R6dd.SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9hbGljZS5kaWQuZm1ncC5hcHAvIiwiciI6W10sImEiOlsiZGlkY29tbS92MiJdfQ#6LSghwSE437wnDE1pt3X6hVDUQzSjsHzinpX3XFvMjRAm7y" - | } - | }], - | "tag": "6MUE-lIZFVRId9qX-0If18EsPcfld_a3r2gQXXq4ms4", - | "iv": "plEK7sqstAIkIxVKyfuuYg" - |}""".stripMargin.fromJson[EncryptedMessage] - val encryptedMessageBob: Either[String, EncryptedMessage] = """{ - | "ciphertext": "-dyjeU0aRQ8F87yAJFbOmmuon0UtEhQpmDQhYclMiTAqi06wH2bLTjtJNIOFG9sJ12uIyaQahPzCFBUyR2X22Oyl-1-Un0LOCAoRP584JuN19NdgKIytmSm4pg4VeSJ56SKO5D3Qe3G8XQa_7vO8O9-b_6V9mQXXZDkknNbphuiD7S53ss_VJzbgQVLRxkBrbnU1PL7yC6AhkAZNkUNCS8GGYbdEKFeRsdWjoROEnuQ1zzPN28eO3T4Wmt2APQ10vHum3Bl1RTiPRGCx3C-fSi05F-521jyP0rwyLeMZdBLruDz2IrUudtimFI3CKQ8_BcmuXTlLa1vw2hKlhk1_ppAmggW-qrjyZPiC9-XIN02OxZox5Xzba-cmg05Dj2zmEXryrxqFfyJlrV5FKSvWDfqeNAA9QNE0aUsgpKK9gOmu5pJRCuYNL96lbxdSCR4BiuX1G_ma2gagdIIY-70d22UPGcrZTw7Blet574i5U_bIDpZw4Az0UxoKNDbCDPOpn-Shojo5n_5FFbaPky0H0N99-9cx-Ns-3NMQecpupPQ9QJ-A2KWBTLYrJofLCBWv_ysqJ3Cde9fQ3xi5DTB13dhbxKVCgzdHKlwnqPC0C3mjFs_eZ1jnzBiUAKLvD_aWMwqx7y8GUhSfXlX3hImqtXaKBu2Koc1esUOvQwadHUj5pSmsNKJJcQLzsOcuYz8U9peRevrft3sy7fm9Ne2L3SSsoCFJP1N8U8bRLmyhY0CDuCNlvXxy_VFoSdPms40d1BNZObhgwO9Ca8kp1r0ITl22repvpMQYcQ83m9fkTXg", - | "protected": "eyJlcGsiOnsia3R5IjoiT0tQIiwiY3J2IjoiWDI1NTE5IiwieCI6ImNKRzZVeVJRbnhOM2RCa3ZQcndmZXZabFBwRzA0SzFyTzZHTjdnQkNyVFUifSwiYXB2IjoiLWNOQ3l0eFVrSHpSRE5SckV2Vm05S0VmZzhZcUtQVnVVcVg1a0VLbU9yMCIsInNraWQiOiJkaWQ6cGVlcjoyLkV6NkxTa0d5M2UyejU0dVA0VTlIeVhKWFJwYUYyeXRzblR1VmdoNlNOTm1DeUdaUVouVno2TWtqZHd2ZjloV2M2aWJabmRXOUI5N3NpOTJEU2s5aFdBaEdZQmdQOWtVRms4Wi5TZXlKMElqb2laRzBpTENKeklqb2lhSFIwY0hNNkx5OWliMkl1Wkdsa0xtWnRaM0F1WVhCd0x5SXNJbklpT2x0ZExDSmhJanBiSW1ScFpHTnZiVzB2ZGpJaVhYMCM2TFNrR3kzZTJ6NTR1UDRVOUh5WEpYUnBhRjJ5dHNuVHVWZ2g2U05ObUN5R1pRWiIsImFwdSI6IlpHbGtPbkJsWlhJNk1pNUZlalpNVTJ0SGVUTmxNbm8xTkhWUU5GVTVTSGxZU2xoU2NHRkdNbmwwYzI1VWRWWm5hRFpUVGs1dFEzbEhXbEZhTGxaNk5rMXJhbVIzZG1ZNWFGZGpObWxpV201a1Z6bENPVGR6YVRreVJGTnJPV2hYUVdoSFdVSm5VRGxyVlVack9Gb3VVMlY1U2pCSmFtOXBXa2N3YVV4RFNucEphbTlwWVVoU01HTklUVFpNZVRscFlqSkpkVnBIYkd0TWJWcDBXak5CZFZsWVFuZE1lVWx6U1c1SmFVOXNkR1JNUTBwb1NXcHdZa2x0VW5CYVIwNTJZbGN3ZG1ScVNXbFlXREFqTmt4VGEwZDVNMlV5ZWpVMGRWQTBWVGxJZVZoS1dGSndZVVl5ZVhSemJsUjFWbWRvTmxOT1RtMURlVWRhVVZvIiwidHlwIjoiYXBwbGljYXRpb24vZGlkY29tbS1lbmNyeXB0ZWQranNvbiIsImVuYyI6IkEyNTZDQkMtSFM1MTIiLCJhbGciOiJFQ0RILTFQVStBMjU2S1cifQ", - | "recipients": [{ - | "encrypted_key": "KCjv83os8FnpVaIUgcuYV-5TIw4VYuGIoHozQ0JVlIwK2sEkxwWg10yh0UlbbcnNVfF_OBr4OkJUczj7pB0spRhvjoDHBM_s", - | "header": { - | "kid": "did:peer:2.Ez6LSghwSE437wnDE1pt3X6hVDUQzSjsHzinpX3XFvMjRAm7y.Vz6Mkhh1e5CEYYq6JBUcTZ6Cp2ranCWRrv7Yax3Le4N59R6dd.SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9hbGljZS5kaWQuZm1ncC5hcHAvIiwiciI6W10sImEiOlsiZGlkY29tbS92MiJdfQ#6LSghwSE437wnDE1pt3X6hVDUQzSjsHzinpX3XFvMjRAm7y" - | } - | }], - | "tag": "iR0meUd8R3X5dleMywNHq5NaGJ4g0h2tok414SJ7UGI", - | "iv": "T-I0b4fIktFXVhAIFoSmQg" - |}""".stripMargin.fromJson[EncryptedMessage] + val encryptedMessageAlice: Either[String, EncryptedMessage] = + """{ + | "ciphertext": "L8wzawffzL7kbVyDcMiHgQMwlqLUqWDYOwH4f0VOFK7sJL8vO-H_JBDCADu7gvH1MDHdVJDXQmSv5dDXp6JYubagcSfBqyZGKGOQDQz-1Ir6-sqZ9K5xRPMt76dYbSswrxhaROVJvtAXyrTmN3KEv8SgP_vt8za5QU6B8cM6gp2CycJKoIhETnhVEVjHnrX0YcyzBsLhd-ZKb8e1Nlz_XSh-3cw1oIQMFjXHnU3PSjrqXcrC-4qSGpVVpHvMSOF3o2EbLGEpP-8UbI0psgSLd9a2VUF9xV55r7Bvn_zJp6tC3-KZKNLO0Rc2K-6JRgyyZjo7O_8aj7Ns6Lx0OjUXoKLiA6B79goHiv8qxJ04k5EWD_h8gt4M3_oByH_cVXH35RDK5SwNV6cVl6zRqiHUR9Ilivh6kfOLGqM2sXCKpXE78qRgHOBeOtl08JHFQO5oFkt1ob8iDqczX0nu-qwlckiibnPK1VvhFnmgLyc9lIUsi_xlCNKqIBZCKoi03xrjNobcM1dWFG7yE04nT-sSiakRNwVHBmNCyA5JhEFQ92d1xpXFGM1ojtiHCPkN5nqe7lMYVM2r7QFnN1xTHwaDWddKprW3vkz_RP7tpoPlWk6X8rLoYUvYc3MqNdbj91QMlho5rU472EX3gprIDeNV7VQiKWoAksFe1hdt62zLH8mJJjUZ3lyq4YjOmrqg7g6RArUWC6KbPgmnuJCqwigpjlwRUCBTPISzaZETAisyluIyuMW8QlRCSQdWnfPZAU2fpLBcviMODMzZTULECvRBef05Fvtd_xRCCbpKpDkGxAY", + | "protected": "eyJlcGsiOnsia3R5IjoiT0tQIiwiY3J2IjoiWDI1NTE5IiwieCI6Ikp2TXhvYXZJaUxaUWVrNDA2eXNtWThQOGpkZGFHSjVIaVNRR0ltWHZWQ2MifSwiYXB2IjoiLWNOQ3l0eFVrSHpSRE5SckV2Vm05S0VmZzhZcUtQVnVVcVg1a0VLbU9yMCIsInNraWQiOiJkaWQ6cGVlcjoyLkV6NkxTa0d5M2UyejU0dVA0VTlIeVhKWFJwYUYyeXRzblR1VmdoNlNOTm1DeUdaUVouVno2TWtqZHd2ZjloV2M2aWJabmRXOUI5N3NpOTJEU2s5aFdBaEdZQmdQOWtVRms4Wi5TZXlKMElqb2laRzBpTENKeklqb2lhSFIwY0hNNkx5OWliMkl1Wkdsa0xtWnRaM0F1WVhCd0x5SXNJbklpT2x0ZExDSmhJanBiSW1ScFpHTnZiVzB2ZGpJaVhYMCM2TFNrR3kzZTJ6NTR1UDRVOUh5WEpYUnBhRjJ5dHNuVHVWZ2g2U05ObUN5R1pRWiIsImFwdSI6IlpHbGtPbkJsWlhJNk1pNUZlalpNVTJ0SGVUTmxNbm8xTkhWUU5GVTVTSGxZU2xoU2NHRkdNbmwwYzI1VWRWWm5hRFpUVGs1dFEzbEhXbEZhTGxaNk5rMXJhbVIzZG1ZNWFGZGpObWxpV201a1Z6bENPVGR6YVRreVJGTnJPV2hYUVdoSFdVSm5VRGxyVlVack9Gb3VVMlY1U2pCSmFtOXBXa2N3YVV4RFNucEphbTlwWVVoU01HTklUVFpNZVRscFlqSkpkVnBIYkd0TWJWcDBXak5CZFZsWVFuZE1lVWx6U1c1SmFVOXNkR1JNUTBwb1NXcHdZa2x0VW5CYVIwNTJZbGN3ZG1ScVNXbFlXREFqTmt4VGEwZDVNMlV5ZWpVMGRWQTBWVGxJZVZoS1dGSndZVVl5ZVhSemJsUjFWbWRvTmxOT1RtMURlVWRhVVZvIiwidHlwIjoiYXBwbGljYXRpb24vZGlkY29tbS1lbmNyeXB0ZWQranNvbiIsImVuYyI6IkEyNTZDQkMtSFM1MTIiLCJhbGciOiJFQ0RILTFQVStBMjU2S1cifQ", + | "recipients": [{ + | "encrypted_key": "eFHcJkoUle7ZkksvZjvhJHLagF7y5B5gDQX11tc1kus2xa3Vn_QmzyVwFzScOHTCEjWRUe7r63rHBFBw0El2ukZW2tcitxr8", + | "header": { + | "kid": "did:peer:2.Ez6LSghwSE437wnDE1pt3X6hVDUQzSjsHzinpX3XFvMjRAm7y.Vz6Mkhh1e5CEYYq6JBUcTZ6Cp2ranCWRrv7Yax3Le4N59R6dd.SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9hbGljZS5kaWQuZm1ncC5hcHAvIiwiciI6W10sImEiOlsiZGlkY29tbS92MiJdfQ#6LSghwSE437wnDE1pt3X6hVDUQzSjsHzinpX3XFvMjRAm7y" + | } + | }], + | "tag": "6MUE-lIZFVRId9qX-0If18EsPcfld_a3r2gQXXq4ms4", + | "iv": "plEK7sqstAIkIxVKyfuuYg" + |}""".stripMargin.fromJson[EncryptedMessage] + val encryptedMessageBob: Either[String, EncryptedMessage] = + """{ + | "ciphertext": "-dyjeU0aRQ8F87yAJFbOmmuon0UtEhQpmDQhYclMiTAqi06wH2bLTjtJNIOFG9sJ12uIyaQahPzCFBUyR2X22Oyl-1-Un0LOCAoRP584JuN19NdgKIytmSm4pg4VeSJ56SKO5D3Qe3G8XQa_7vO8O9-b_6V9mQXXZDkknNbphuiD7S53ss_VJzbgQVLRxkBrbnU1PL7yC6AhkAZNkUNCS8GGYbdEKFeRsdWjoROEnuQ1zzPN28eO3T4Wmt2APQ10vHum3Bl1RTiPRGCx3C-fSi05F-521jyP0rwyLeMZdBLruDz2IrUudtimFI3CKQ8_BcmuXTlLa1vw2hKlhk1_ppAmggW-qrjyZPiC9-XIN02OxZox5Xzba-cmg05Dj2zmEXryrxqFfyJlrV5FKSvWDfqeNAA9QNE0aUsgpKK9gOmu5pJRCuYNL96lbxdSCR4BiuX1G_ma2gagdIIY-70d22UPGcrZTw7Blet574i5U_bIDpZw4Az0UxoKNDbCDPOpn-Shojo5n_5FFbaPky0H0N99-9cx-Ns-3NMQecpupPQ9QJ-A2KWBTLYrJofLCBWv_ysqJ3Cde9fQ3xi5DTB13dhbxKVCgzdHKlwnqPC0C3mjFs_eZ1jnzBiUAKLvD_aWMwqx7y8GUhSfXlX3hImqtXaKBu2Koc1esUOvQwadHUj5pSmsNKJJcQLzsOcuYz8U9peRevrft3sy7fm9Ne2L3SSsoCFJP1N8U8bRLmyhY0CDuCNlvXxy_VFoSdPms40d1BNZObhgwO9Ca8kp1r0ITl22repvpMQYcQ83m9fkTXg", + | "protected": "eyJlcGsiOnsia3R5IjoiT0tQIiwiY3J2IjoiWDI1NTE5IiwieCI6ImNKRzZVeVJRbnhOM2RCa3ZQcndmZXZabFBwRzA0SzFyTzZHTjdnQkNyVFUifSwiYXB2IjoiLWNOQ3l0eFVrSHpSRE5SckV2Vm05S0VmZzhZcUtQVnVVcVg1a0VLbU9yMCIsInNraWQiOiJkaWQ6cGVlcjoyLkV6NkxTa0d5M2UyejU0dVA0VTlIeVhKWFJwYUYyeXRzblR1VmdoNlNOTm1DeUdaUVouVno2TWtqZHd2ZjloV2M2aWJabmRXOUI5N3NpOTJEU2s5aFdBaEdZQmdQOWtVRms4Wi5TZXlKMElqb2laRzBpTENKeklqb2lhSFIwY0hNNkx5OWliMkl1Wkdsa0xtWnRaM0F1WVhCd0x5SXNJbklpT2x0ZExDSmhJanBiSW1ScFpHTnZiVzB2ZGpJaVhYMCM2TFNrR3kzZTJ6NTR1UDRVOUh5WEpYUnBhRjJ5dHNuVHVWZ2g2U05ObUN5R1pRWiIsImFwdSI6IlpHbGtPbkJsWlhJNk1pNUZlalpNVTJ0SGVUTmxNbm8xTkhWUU5GVTVTSGxZU2xoU2NHRkdNbmwwYzI1VWRWWm5hRFpUVGs1dFEzbEhXbEZhTGxaNk5rMXJhbVIzZG1ZNWFGZGpObWxpV201a1Z6bENPVGR6YVRreVJGTnJPV2hYUVdoSFdVSm5VRGxyVlVack9Gb3VVMlY1U2pCSmFtOXBXa2N3YVV4RFNucEphbTlwWVVoU01HTklUVFpNZVRscFlqSkpkVnBIYkd0TWJWcDBXak5CZFZsWVFuZE1lVWx6U1c1SmFVOXNkR1JNUTBwb1NXcHdZa2x0VW5CYVIwNTJZbGN3ZG1ScVNXbFlXREFqTmt4VGEwZDVNMlV5ZWpVMGRWQTBWVGxJZVZoS1dGSndZVVl5ZVhSemJsUjFWbWRvTmxOT1RtMURlVWRhVVZvIiwidHlwIjoiYXBwbGljYXRpb24vZGlkY29tbS1lbmNyeXB0ZWQranNvbiIsImVuYyI6IkEyNTZDQkMtSFM1MTIiLCJhbGciOiJFQ0RILTFQVStBMjU2S1cifQ", + | "recipients": [{ + | "encrypted_key": "KCjv83os8FnpVaIUgcuYV-5TIw4VYuGIoHozQ0JVlIwK2sEkxwWg10yh0UlbbcnNVfF_OBr4OkJUczj7pB0spRhvjoDHBM_s", + | "header": { + | "kid": "did:peer:2.Ez6LSghwSE437wnDE1pt3X6hVDUQzSjsHzinpX3XFvMjRAm7y.Vz6Mkhh1e5CEYYq6JBUcTZ6Cp2ranCWRrv7Yax3Le4N59R6dd.SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9hbGljZS5kaWQuZm1ncC5hcHAvIiwiciI6W10sImEiOlsiZGlkY29tbS92MiJdfQ#6LSghwSE437wnDE1pt3X6hVDUQzSjsHzinpX3XFvMjRAm7y" + | } + | }], + | "tag": "iR0meUd8R3X5dleMywNHq5NaGJ4g0h2tok414SJ7UGI", + | "iv": "T-I0b4fIktFXVhAIFoSmQg" + |}""".stripMargin.fromJson[EncryptedMessage] } diff --git a/mediator/src/test/scala/io/iohk/atala/mediator/db/UserAccountRepoSpec.scala b/mediator/src/test/scala/io/iohk/atala/mediator/db/UserAccountRepoSpec.scala index 6c748d8b..3a4eb9db 100644 --- a/mediator/src/test/scala/io/iohk/atala/mediator/db/UserAccountRepoSpec.scala +++ b/mediator/src/test/scala/io/iohk/atala/mediator/db/UserAccountRepoSpec.scala @@ -21,7 +21,7 @@ object UserAccountRepoSpec extends ZIOSpecDefault with DidAccountStubSetup with userAccount <- ZIO.service[UserAccountRepo] col <- userAccount.collection _ = col.indexesManager.create(index) - result <- userAccount.createOrFindDidAccount(DIDSubject(alice)) + result <- userAccount.createOrFindDidAccount(alice) } yield { assertTrue(result.isRight) } @@ -29,7 +29,7 @@ object UserAccountRepoSpec extends ZIOSpecDefault with DidAccountStubSetup with test("insert same Did should NOT fail") { for { userAccount <- ZIO.service[UserAccountRepo] - result <- userAccount.createOrFindDidAccount(DIDSubject(alice)) + result <- userAccount.createOrFindDidAccount(alice) } yield { assertTrue(result.isRight) } @@ -37,15 +37,15 @@ object UserAccountRepoSpec extends ZIOSpecDefault with DidAccountStubSetup with test("Get Did Account") { for { userAccount <- ZIO.service[UserAccountRepo] - result <- userAccount.getDidAccount(DIDSubject(alice)) + result <- userAccount.getDidAccount(alice) } yield { - assertTrue(result.isDefined) && assertTrue(result.exists(_.did == DIDSubject(alice))) + assertTrue(result.isDefined) && assertTrue(result.exists(_.did == alice)) } }, test("Get Did Account return for unknown did") { for { userAccount <- ZIO.service[UserAccountRepo] - result <- userAccount.getDidAccount(DIDSubject(bob)) + result <- userAccount.getDidAccount(bob) } yield { assertTrue(result.isEmpty) } @@ -53,8 +53,8 @@ object UserAccountRepoSpec extends ZIOSpecDefault with DidAccountStubSetup with test("Add alias to existing Did Account return right nModified value 1") { for { userAccount <- ZIO.service[UserAccountRepo] - result <- userAccount.addAlias(owner = DIDSubject(alice), newAlias = DIDSubject(bob)) - didAccount <- userAccount.getDidAccount(DIDSubject(alice)) + result <- userAccount.addAlias(owner = alice, newAlias = bob) + didAccount <- userAccount.getDidAccount(alice) } yield { val alias: Seq[String] = didAccount.map(_.alias.map(_.did)).getOrElse(Seq.empty) assertTrue(result.isRight) && @@ -66,7 +66,7 @@ object UserAccountRepoSpec extends ZIOSpecDefault with DidAccountStubSetup with test("insert/create a UserAccount for a DID that is used as a alias should fail") { for { userAccount <- ZIO.service[UserAccountRepo] - result <- userAccount.createOrFindDidAccount(DIDSubject(bob)) + result <- userAccount.createOrFindDidAccount(bob) } yield { assertTrue(result.isLeft) } @@ -74,34 +74,34 @@ object UserAccountRepoSpec extends ZIOSpecDefault with DidAccountStubSetup with test("Add owner as alias to existing Did Account return right with nModified value 1") { for { userAccount <- ZIO.service[UserAccountRepo] - result <- userAccount.addAlias(owner = DIDSubject(alice), newAlias = DIDSubject(alice)) - didAccount <- userAccount.getDidAccount(DIDSubject(alice)) + result <- userAccount.addAlias(owner = alice, newAlias = alice) + didAccount <- userAccount.getDidAccount(alice) } yield { val alias: Seq[String] = didAccount.map(_.alias.map(_.did)).getOrElse(Seq.empty) assertTrue(result.isRight) && assertTrue(result == Right(1)) && assertTrue(didAccount.isDefined) && - assertTrue(alias.sorted == Seq(alice, bob).sorted) + assertTrue(alias.sorted == Seq(alice.did, bob.did).sorted) } }, test("Add same alias to existing Did Account return right with nModified value 0") { for { userAccount <- ZIO.service[UserAccountRepo] - result <- userAccount.addAlias(owner = DIDSubject(alice), newAlias = DIDSubject(alice)) - didAccount <- userAccount.getDidAccount(DIDSubject(alice)) + result <- userAccount.addAlias(owner = alice, newAlias = alice) + didAccount <- userAccount.getDidAccount(alice) } yield { val alias: Seq[String] = didAccount.map(_.alias.map(_.did)).getOrElse(Seq.empty) assertTrue(result.isRight) && assertTrue(result == Right(0)) && assertTrue(didAccount.isDefined) && - assertTrue(alias.sorted == Seq(alice, bob).sorted) + assertTrue(alias.sorted == Seq(alice.did, bob.did).sorted) } }, test("Remove alias to existing Did Account should return right with nModified value 1 ") { for { userAccount <- ZIO.service[UserAccountRepo] - result <- userAccount.removeAlias(DIDSubject(alice), DIDSubject(bob)) - didAccount <- userAccount.getDidAccount(DIDSubject(alice)) + result <- userAccount.removeAlias(alice, bob) + didAccount <- userAccount.getDidAccount(alice) } yield { val alias: Seq[String] = didAccount.map(_.alias.map(_.did)).getOrElse(Seq.empty) assertTrue(result.isRight) && @@ -113,8 +113,8 @@ object UserAccountRepoSpec extends ZIOSpecDefault with DidAccountStubSetup with test("Remove alias to unknown or unregister alias Did should return right with noModified value 0") { for { userAccount <- ZIO.service[UserAccountRepo] - result <- userAccount.removeAlias(DIDSubject(alice), DIDSubject(bob)) - didAccount <- userAccount.getDidAccount(DIDSubject(alice)) + result <- userAccount.removeAlias(alice, bob) + didAccount <- userAccount.getDidAccount(alice) } yield { val alias: Seq[String] = didAccount.map(_.alias.map(_.did)).getOrElse(Seq.empty) assertTrue(result.isRight) && @@ -129,11 +129,11 @@ object UserAccountRepoSpec extends ZIOSpecDefault with DidAccountStubSetup with for { userAccount <- ZIO.service[UserAccountRepo] messageItem <- ZIO.service[MessageItemRepo] - result <- userAccount.addAlias(DIDSubject(alice), DIDSubject(bob)) + result <- userAccount.addAlias(alice, bob) msg <- ZIO.fromEither(encryptedMessageAlice) msgAdded <- messageItem.insert(msg) - addedToInbox <- userAccount.addToInboxes(Set(DIDSubject(bob)), msg) - didAccount <- userAccount.getDidAccount(DIDSubject(alice)) + addedToInbox <- userAccount.addToInboxes(Set(bob), msg) + didAccount <- userAccount.getDidAccount(alice) } yield { val messageMetaData: Seq[MessageMetaData] = didAccount.map(_.messagesRef).getOrElse(Seq.empty) @@ -145,7 +145,7 @@ object UserAccountRepoSpec extends ZIOSpecDefault with DidAccountStubSetup with assert(messageMetaData)( forall( hasField("hash", (m: MessageMetaData) => m.hash, equalTo(msg.sha1)) - && hasField("recipient", (m: MessageMetaData) => m.recipient, equalTo(DIDSubject(bob))) + && hasField("recipient", (m: MessageMetaData) => m.recipient, equalTo(bob)) && hasField("xRequestId", (m: MessageMetaData) => m.xRequestId, equalTo(Some(xRequestId))) ) ) @@ -156,8 +156,8 @@ object UserAccountRepoSpec extends ZIOSpecDefault with DidAccountStubSetup with for { userAccount <- ZIO.service[UserAccountRepo] msg <- ZIO.fromEither(encryptedMessageAlice) - markedDelivered <- userAccount.markAsDelivered(DIDSubject(alice), Seq(msg.sha1)) - didAccount <- userAccount.getDidAccount(DIDSubject(alice)) + markedDelivered <- userAccount.markAsDelivered(alice, Seq(msg.sha1)) + didAccount <- userAccount.getDidAccount(alice) } yield { val messageMetaData: Seq[MessageMetaData] = didAccount.map(_.messagesRef).getOrElse(Seq.empty) assertTrue(markedDelivered == 1) && diff --git a/mediator/src/test/scala/io/iohk/atala/mediator/protocols/DiscoverFeaturesExecuterSpec.scala b/mediator/src/test/scala/io/iohk/atala/mediator/protocols/DiscoverFeaturesExecuterSpec.scala new file mode 100644 index 00000000..40170e7d --- /dev/null +++ b/mediator/src/test/scala/io/iohk/atala/mediator/protocols/DiscoverFeaturesExecuterSpec.scala @@ -0,0 +1,79 @@ +package io.iohk.atala.mediator.protocols + +import fmgp.did.DIDSubject +import fmgp.did.comm.protocol.reportproblem2.{ProblemCode, ProblemReport} +import fmgp.did.comm.protocol.discoverfeatures2.* +import fmgp.did.comm.{EncryptedMessage, Operations, PlaintextMessage, SignedMessage, layerDefault} +import fmgp.did.method.peer.DidPeerResolver +import fmgp.util.Base64 +import io.iohk.atala.mediator.comm.MessageDispatcherJVM +import io.iohk.atala.mediator.db.* +import io.iohk.atala.mediator.db.MessageItemRepoSpec.encryptedMessageAlice +import io.iohk.atala.mediator.protocols.DiscoverFeaturesExecuter +import zio.* +import zio.ExecutionStrategy.Sequential +import zio.http.Client +import zio.json.* +import zio.test.* +import zio.test.Assertion.* +import fmgp.did.comm.FROM +import fmgp.did.comm.TO + +import scala.concurrent.ExecutionContext.Implicits.global +import io.iohk.atala.mediator.db.EmbeddedMongoDBInstance.* +import reactivemongo.api.bson.BSONDocument +import fmgp.did.DIDSubject.* +import fmgp.did.comm.Operations.authDecrypt +import io.iohk.atala.mediator.app.MediatorAgent +import io.iohk.atala.mediator.db.AgentStub.{bobAgent, bobAgentLayer} +object DiscoverFeaturesExecuterSpec extends ZIOSpecDefault with DidAccountStubSetup with MessageSetup { + + override def spec = suite("DiscoverFeaturesExecuterSpec")( + test("DiscoverFeatures Query message should return the disclose message containing the matched protocols") { + val executer = DiscoverFeaturesExecuter + for { + agent <- ZIO.service[MediatorAgent] + msg <- ZIO.fromEither(plaintextDiscoverFeatureRequestMessage(bobAgent.id.did, agent.id.did)) + result <- executer.execute(msg) + message <- ZIO.fromOption(result) + decryptedMessage <- authDecrypt(message.asInstanceOf[EncryptedMessage]).provideSomeLayer(bobAgentLayer) + featureDisclose <- ZIO.fromEither(decryptedMessage.asInstanceOf[PlaintextMessage].toFeatureDisclose) + } yield { + val plainText = decryptedMessage.asInstanceOf[PlaintextMessage] + assertTrue(plainText.`type` == FeatureDisclose.piuri) && + assertTrue(featureDisclose.disclosures.nonEmpty) && + assertTrue(featureDisclose.disclosures.head.id.contains("routing")) + } + } @@ TestAspect.before(setupAndClean), + test( + "DiscoverFeatures Query message doesn't match regex pattern, it should yield a disclose message with an empty body" + ) { + val executer = DiscoverFeaturesExecuter + for { + agent <- ZIO.service[MediatorAgent] + msg <- ZIO.fromEither(plaintextDiscoverFeatureRequestMessageNoMatch(bobAgent.id.did, agent.id.did)) + result <- executer.execute(msg) + message <- ZIO.fromOption(result) + decryptedMessage <- authDecrypt(message.asInstanceOf[EncryptedMessage]).provideSomeLayer(bobAgentLayer) + featureDisclose <- ZIO.fromEither(decryptedMessage.asInstanceOf[PlaintextMessage].toFeatureDisclose) + + } yield { + val plainText = decryptedMessage.asInstanceOf[PlaintextMessage] + assertTrue(plainText.`type` == FeatureDisclose.piuri) && + assertTrue(featureDisclose.disclosures.isEmpty) + + } + } @@ TestAspect.before(setupAndClean), + ).provideSomeLayer(DidPeerResolver.layerDidPeerResolver) + .provideSomeLayer(Operations.layerDefault) + .provideSomeLayer(Scope.default >>> Client.default >>> MessageDispatcherJVM.layer) + .provideSomeLayer(DidPeerResolver.layerDidPeerResolver) + .provideSomeLayer(AgentStub.agentLayer) + .provideLayerShared(dataAccessLayer) @@ TestAspect.sequential + + val dataAccessLayer = EmbeddedMongoDBInstance.layer(port, hostIp) + >>> AsyncDriverResource.layer + >>> ReactiveMongoApi.layer(connectionString) + >>> (UserAccountRepo.layer ++ MessageItemRepo.layer ++ OutboxMessageRepo.layer) + +} diff --git a/mediator/src/test/scala/io/iohk/atala/mediator/protocols/ForwardMessageExecutorSpec.scala b/mediator/src/test/scala/io/iohk/atala/mediator/protocols/ForwardMessageExecutorSpec.scala index 07129cb9..da85e4db 100644 --- a/mediator/src/test/scala/io/iohk/atala/mediator/protocols/ForwardMessageExecutorSpec.scala +++ b/mediator/src/test/scala/io/iohk/atala/mediator/protocols/ForwardMessageExecutorSpec.scala @@ -18,7 +18,6 @@ import fmgp.did.DIDSubject import scala.concurrent.ExecutionContext.Implicits.global import io.iohk.atala.mediator.db.EmbeddedMongoDBInstance.* -import io.iohk.atala.mediator.protocols.MediatorCoordinationExecuterSpec.setupAndClean import reactivemongo.api.bson.BSONDocument object ForwardMessageExecutorSpec extends ZIOSpecDefault with DidAccountStubSetup with MessageSetup { @@ -27,7 +26,7 @@ object ForwardMessageExecutorSpec extends ZIOSpecDefault with DidAccountStubSetu val executer = ForwardMessageExecuter for { userAccount <- ZIO.service[UserAccountRepo] - result <- userAccount.createOrFindDidAccount(DIDSubject(alice)) + result <- userAccount.createOrFindDidAccount(alice) msg <- ZIO.fromEither(plaintextForwardNotEnrolledDidMessage) result <- executer.execute(msg) message <- ZIO.fromOption(result) @@ -52,8 +51,8 @@ object ForwardMessageExecutorSpec extends ZIOSpecDefault with DidAccountStubSetu val executer = ForwardMessageExecuter for { userAccount <- ZIO.service[UserAccountRepo] - result <- userAccount.createOrFindDidAccount(DIDSubject(alice)) - result <- userAccount.addAlias(owner = DIDSubject(alice), newAlias = DIDSubject(alice)) + result <- userAccount.createOrFindDidAccount(alice) + result <- userAccount.addAlias(owner = alice, newAlias = alice) msg <- ZIO.fromEither(plaintextForwardEnrolledDidMessage) result <- executer.execute(msg) } yield assertTrue(result.isEmpty) @@ -66,8 +65,6 @@ object ForwardMessageExecutorSpec extends ZIOSpecDefault with DidAccountStubSetu .provideSomeLayer(AgentStub.agentLayer) .provideLayerShared(dataAccessLayer) @@ TestAspect.sequential - - val dataAccessLayer = EmbeddedMongoDBInstance.layer(port, hostIp) >>> AsyncDriverResource.layer >>> ReactiveMongoApi.layer(connectionString) diff --git a/mediator/src/test/scala/io/iohk/atala/mediator/protocols/MediatorCoordinationExecuterSpec.scala b/mediator/src/test/scala/io/iohk/atala/mediator/protocols/MediatorCoordinationExecuterSpec.scala index 25367fc6..abd8b192 100644 --- a/mediator/src/test/scala/io/iohk/atala/mediator/protocols/MediatorCoordinationExecuterSpec.scala +++ b/mediator/src/test/scala/io/iohk/atala/mediator/protocols/MediatorCoordinationExecuterSpec.scala @@ -47,8 +47,8 @@ object MediatorCoordinationExecuterSpec extends ZIOSpecDefault with DidAccountSt for { userAccount <- ZIO.service[UserAccountRepo] agent <- ZIO.service[MediatorAgent] - result <- userAccount.createOrFindDidAccount(DIDSubject(alice)) - result <- userAccount.addAlias(owner = DIDSubject(alice), newAlias = DIDSubject(aliceAgent.id.did)) + result <- userAccount.createOrFindDidAccount(alice) + result <- userAccount.addAlias(owner = alice, newAlias = DIDSubject(aliceAgent.id.did)) msg <- ZIO.fromEither(plaintextMediationRequestMessage(aliceAgent.id.did, agent.id.did)) result <- executer.execute(msg) message <- ZIO.fromOption(result) diff --git a/mediator/src/test/scala/io/iohk/atala/mediator/protocols/MessageSetup.scala b/mediator/src/test/scala/io/iohk/atala/mediator/protocols/MessageSetup.scala index 0174687c..5f630579 100644 --- a/mediator/src/test/scala/io/iohk/atala/mediator/protocols/MessageSetup.scala +++ b/mediator/src/test/scala/io/iohk/atala/mediator/protocols/MessageSetup.scala @@ -5,7 +5,9 @@ import io.iohk.atala.mediator.db.UserAccountRepo import reactivemongo.api.bson.BSONDocument import zio.ZIO import zio.json.* +import fmgp.did.comm import reactivemongo.api.indexes.{Index, IndexType} +import fmgp.did.DIDSubject trait MessageSetup { val index = Index( @@ -28,8 +30,10 @@ trait MessageSetup { } yield {} } - val mediatorDid = + val mediatorDid = DIDSubject( "did:peer:2.Ez6LSkGy3e2z54uP4U9HyXJXRpaF2ytsnTuVgh6SNNmCyGZQZ.Vz6Mkjdwvf9hWc6ibZndW9B97si92DSk9hWAhGYBgP9kUFk8Z.SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9ib2IuZGlkLmZtZ3AuYXBwLyIsInIiOltdLCJhIjpbImRpZGNvbW0vdjIiXX0" + ) + val plaintextForwardNotEnrolledDidMessage: Either[String, PlaintextMessage] = """{ | "id" : "c8f9712a-fdad-45d0-81d9-c610daaa9285", @@ -135,6 +139,40 @@ trait MessageSetup { | "typ" : "application/didcomm-plain+json" |}""".stripMargin.fromJson[PlaintextMessage] + val plaintextDiscoverFeatureRequestMessage = (didFrom: String, mediatorDid: String) => + s"""{ + | "id" : "17f9f122-f762-4ba8-9011-39b9e7efb177", + | "type" : "https://didcomm.org/discover-features/2.0/queries", + | "to" : [ + | "$mediatorDid" + | ], + | "from" : "$didFrom", + | "body" : { + | "queries": [ + | { "feature-type": "protocol", "match": ".*routing.*" } + | ] + | }, + | "return_route" : "all", + | "typ" : "application/didcomm-plain+json" + |}""".stripMargin + .fromJson[PlaintextMessage] + val plaintextDiscoverFeatureRequestMessageNoMatch = (didFrom: String, mediatorDid: String) => + s"""{ + | "id" : "17f9f122-f762-4ba8-9011-39b9e7efb177", + | "type" : "https://didcomm.org/discover-features/2.0/queries", + | "to" : [ + | "$mediatorDid" + | ], + | "from" : "$didFrom", + | "body" : { + | "queries": [ + | { "feature-type": "protocol", "match": "routing" } + | ] + | }, + | "return_route" : "all", + | "typ" : "application/didcomm-plain+json" + |}""".stripMargin + .fromJson[PlaintextMessage] val plaintextKeyListUpdateRequestMessage = (didFrom: String, mediatorDid: String, recipientDid: String) => s"""{ | "id" : "cf64e501-d524-4fd9-8314-4dc4bc652983", | "type" : "https://didcomm.org/coordinate-mediation/2.0/keylist-update",