Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ lazy val D = new {
val scalaDID = Def.setting("app.fmgp" %%% "did" % V.scalaDID)
val scalaDID_imp = Def.setting("app.fmgp" %%% "did-imp" % V.scalaDID)
val scalaDID_peer = Def.setting("app.fmgp" %%% "did-method-peer" % V.scalaDID)
val scalaDID_prism = Def.setting("app.fmgp" %%% "did-method-prism" % V.scalaDID)
val scalaDID_framework = Def.setting("app.fmgp" %%% "did-framework" % V.scalaDID)
val scalaDID_protocols = Def.setting("app.fmgp" %%% "did-comm-protocols" % V.scalaDID)

Expand Down Expand Up @@ -207,6 +208,7 @@ lazy val mediator = project
.settings(
libraryDependencies += D.scalaDID_imp.value,
libraryDependencies += D.scalaDID_peer.value,
libraryDependencies += D.scalaDID_prism.value,
libraryDependencies += D.scalaDID_framework.value,
libraryDependencies += D.scalaDID_protocols.value,
libraryDependencies += D.zioHttp.value,
Expand Down Expand Up @@ -272,7 +274,7 @@ lazy val webapp = project
.settings(
libraryDependencies ++= Seq(D.laminar.value, D.waypoint.value, D.upickle.value),
libraryDependencies ++= Seq(D.zio.value, D.zioJson.value),
libraryDependencies ++= Seq(D.scalaDID.value, D.scalaDID_peer.value, D.scalaDID_protocols.value),
libraryDependencies ++= Seq(D.scalaDID.value, D.scalaDID_protocols.value),
Compile / npmDependencies ++= NPM.qrcode ++ NPM.materialDesign ++ NPM.sha256,
)
.settings(
Expand Down
114 changes: 83 additions & 31 deletions mediator/src/main/resources/application.conf
Original file line number Diff line number Diff line change
@@ -1,39 +1,91 @@
mediator = {
identity = {
keyAgreement = {
kty = "OKP"
crv = "X25519"
d = ${?KEY_AGREEMENT_D}
x = ${?KEY_AGREEMENT_X}
}
keyAuthentication = {
kty = "OKP"
crv = "Ed25519"
d = ${?KEY_AUTHENTICATION_D}
x = ${?KEY_AUTHENTICATION_X}
}
endpoints = "http://localhost:8080;ws://localhost:8080/ws"
endpoints = ${?SERVICE_ENDPOINTS}
did = "did:peer:2.Ez6LSghwSE437wnDE1pt3X6hVDUQzSjsHzinpX3XFvMjRAm7y.Vz6Mkhh1e5CEYYq6JBUcTZ6Cp2ranCWRrv7Yax3Le4N59R6dd.SeyJ0IjoiZG0iLCJzIjp7InVyaSI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODA4MCIsImEiOlsiZGlkY29tbS92MiJdfX0.SeyJ0IjoiZG0iLCJzIjp7InVyaSI6IndzOi8vbG9jYWxob3N0OjgwODAvd3MiLCJhIjpbImRpZGNvbW0vdjIiXX19"
test = {
kty = "OKP",
crv = "X25519",
d = "Z6D8LduZgZ6LnrOHPrMTS6uU2u5Btsrk1SGs4fn8M7c",
x = "Sr4SkIskjN_VdKTn0zkjYbhGTWArdUNE4j_DmUpnQGw",
kid = "did:peer:2.Ez6LSghwSE437wnDE1pt3X6hVDUQzSjsHzinpX3XFvMjRAm7y.Vz6Mkhh1e5CEYYq6JBUcTZ6Cp2ranCWRrv7Yax3Le4N59R6dd.SeyJ0IjoiZG0iLCJzIjp7InVyaSI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODA4MCIsImEiOlsiZGlkY29tbS92MiJdfX0.SeyJ0IjoiZG0iLCJzIjp7InVyaSI6IndzOi8vbG9jYWxob3N0OjgwODAvd3MiLCJhIjpbImRpZGNvbW0vdjIiXX19#key-1"
}
keyStore = [
{ # keyAgreement
kty = "OKP",
crv = "X25519",
d = ${?KEY_AGREEMENT_D},
d = "Z6D8LduZgZ6LnrOHPrMTS6uU2u5Btsrk1SGs4fn8M7c",
x = ${?KEY_AGREEMENT_X},
x = "Sr4SkIskjN_VdKTn0zkjYbhGTWArdUNE4j_DmUpnQGw",
kid = "did:peer:2.Ez6LSghwSE437wnDE1pt3X6hVDUQzSjsHzinpX3XFvMjRAm7y.Vz6Mkhh1e5CEYYq6JBUcTZ6Cp2ranCWRrv7Yax3Le4N59R6dd.SeyJ0IjoiZG0iLCJzIjp7InVyaSI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODA4MCIsImEiOlsiZGlkY29tbS92MiJdfX0.SeyJ0IjoiZG0iLCJzIjp7InVyaSI6IndzOi8vbG9jYWxob3N0OjgwODAvd3MiLCJhIjpbImRpZGNvbW0vdjIiXX19#key-1"
}
{ # keyAuthentication
kty = "OKP",
crv = "Ed25519",
d = ${?KEY_AUTHENTICATION_D},
d = "INXCnxFEl0atLIIQYruHzGd5sUivMRyQOzu87qVerug",
x = "MBjnXZxkMcoQVVL21hahWAw43RuAG-i64ipbeKKqwoA",
x = ${?KEY_AUTHENTICATION_X},
kid = "did:peer:2.Ez6LSghwSE437wnDE1pt3X6hVDUQzSjsHzinpX3XFvMjRAm7y.Vz6Mkhh1e5CEYYq6JBUcTZ6Cp2ranCWRrv7Yax3Le4N59R6dd.SeyJ0IjoiZG0iLCJzIjp7InVyaSI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODA4MCIsImEiOlsiZGlkY29tbS92MiJdfX0.SeyJ0IjoiZG0iLCJzIjp7InVyaSI6IndzOi8vbG9jYWxob3N0OjgwODAvd3MiLCJhIjpbImRpZGNvbW0vdjIiXX19#key-2"
}
]
}
server.http.port = 8080
server.http.port = ${?PORT}
database = {
# Connection string takes precedence over individual components if provided
connectionString = ${?MONGODB_CONNECTION_STRING}
# Individual components (fallback if no connection string provided)
protocol = mongodb
protocol = ${?MONGODB_PROTOCOL}
port = 27017
port = ${?MONGODB_PORT}
host = "localhost"
host = ${?MONGODB_HOST}
userName = "admin"
userName = ${?MONGODB_USER}
password = "admin"
password = ${?MONGODB_PASSWORD}
dbName = "mediator"
dbName = ${?MONGODB_DB_NAME}
}
database.connectionString = "mongodb://admin:admin@localhost:27017/mediator"
database.connectionString = ${?MONGODB_CONNECTION_STRING}
problem.report.escalateTo = "[email protected]"
problem.report.escalateTo = ${?ESCALATE_TO}
didPrismResolver = "https://raw.githubusercontent.com/FabioPinheiro/prism-vdr/refs/heads/main/mainnet/diddoc"
didPrismResolver = ${?DID_PRISM_RESOLVER}
}


# {
# "id" : "did:peer:2.Ez6LSghwSE437wnDE1pt3X6hVDUQzSjsHzinpX3XFvMjRAm7y.Vz6Mkhh1e5CEYYq6JBUcTZ6Cp2ranCWRrv7Yax3Le4N59R6dd.SeyJ0IjoiZG0iLCJzIjp7InVyaSI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODA4MCIsImEiOlsiZGlkY29tbS92MiJdfX0.SeyJ0IjoiZG0iLCJzIjp7InVyaSI6IndzOi8vbG9jYWxob3N0OjgwODAvd3MiLCJhIjpbImRpZGNvbW0vdjIiXX19",
# "authentication" : [
# {
# "id" : "did:peer:2.Ez6LSghwSE437wnDE1pt3X6hVDUQzSjsHzinpX3XFvMjRAm7y.Vz6Mkhh1e5CEYYq6JBUcTZ6Cp2ranCWRrv7Yax3Le4N59R6dd.SeyJ0IjoiZG0iLCJzIjp7InVyaSI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODA4MCIsImEiOlsiZGlkY29tbS92MiJdfX0.SeyJ0IjoiZG0iLCJzIjp7InVyaSI6IndzOi8vbG9jYWxob3N0OjgwODAvd3MiLCJhIjpbImRpZGNvbW0vdjIiXX19#key-2",
# "controller" : "did:peer:2.Ez6LSghwSE437wnDE1pt3X6hVDUQzSjsHzinpX3XFvMjRAm7y.Vz6Mkhh1e5CEYYq6JBUcTZ6Cp2ranCWRrv7Yax3Le4N59R6dd.SeyJ0IjoiZG0iLCJzIjp7InVyaSI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODA4MCIsImEiOlsiZGlkY29tbS92MiJdfX0.SeyJ0IjoiZG0iLCJzIjp7InVyaSI6IndzOi8vbG9jYWxob3N0OjgwODAvd3MiLCJhIjpbImRpZGNvbW0vdjIiXX19",
# "type" : "JsonWebKey2020",
# "publicKeyJwk" : {
# "kty" : "OKP",
# "crv" : "Ed25519",
# "x" : "MBjnXZxkMcoQVVL21hahWAw43RuAG-i64ipbeKKqwoA"
# }
# }
# ],
# "keyAgreement" : [
# {
# "id" : "did:peer:2.Ez6LSghwSE437wnDE1pt3X6hVDUQzSjsHzinpX3XFvMjRAm7y.Vz6Mkhh1e5CEYYq6JBUcTZ6Cp2ranCWRrv7Yax3Le4N59R6dd.SeyJ0IjoiZG0iLCJzIjp7InVyaSI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODA4MCIsImEiOlsiZGlkY29tbS92MiJdfX0.SeyJ0IjoiZG0iLCJzIjp7InVyaSI6IndzOi8vbG9jYWxob3N0OjgwODAvd3MiLCJhIjpbImRpZGNvbW0vdjIiXX19#key-1",
# "controller" : "did:peer:2.Ez6LSghwSE437wnDE1pt3X6hVDUQzSjsHzinpX3XFvMjRAm7y.Vz6Mkhh1e5CEYYq6JBUcTZ6Cp2ranCWRrv7Yax3Le4N59R6dd.SeyJ0IjoiZG0iLCJzIjp7InVyaSI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODA4MCIsImEiOlsiZGlkY29tbS92MiJdfX0.SeyJ0IjoiZG0iLCJzIjp7InVyaSI6IndzOi8vbG9jYWxob3N0OjgwODAvd3MiLCJhIjpbImRpZGNvbW0vdjIiXX19",
# "type" : "JsonWebKey2020",
# "publicKeyJwk" : {
# "kty" : "OKP",
# "crv" : "X25519",
# "x" : "Sr4SkIskjN_VdKTn0zkjYbhGTWArdUNE4j_DmUpnQGw"
# }
# }
# ],
# "service" : [
# {
# "id" : "did:peer:2.Ez6LSghwSE437wnDE1pt3X6hVDUQzSjsHzinpX3XFvMjRAm7y.Vz6Mkhh1e5CEYYq6JBUcTZ6Cp2ranCWRrv7Yax3Le4N59R6dd.SeyJ0IjoiZG0iLCJzIjp7InVyaSI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODA4MCIsImEiOlsiZGlkY29tbS92MiJdfX0.SeyJ0IjoiZG0iLCJzIjp7InVyaSI6IndzOi8vbG9jYWxob3N0OjgwODAvd3MiLCJhIjpbImRpZGNvbW0vdjIiXX19#service",
# "type" : "DIDCommMessaging",
# "serviceEndpoint" : {
# "uri" : "http://localhost:8080",
# "accept" : [
# "didcomm/v2"
# ]
# }
# },
# {
# "id" : "did:peer:2.Ez6LSghwSE437wnDE1pt3X6hVDUQzSjsHzinpX3XFvMjRAm7y.Vz6Mkhh1e5CEYYq6JBUcTZ6Cp2ranCWRrv7Yax3Le4N59R6dd.SeyJ0IjoiZG0iLCJzIjp7InVyaSI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODA4MCIsImEiOlsiZGlkY29tbS92MiJdfX0.SeyJ0IjoiZG0iLCJzIjp7InVyaSI6IndzOi8vbG9jYWxob3N0OjgwODAvd3MiLCJhIjpbImRpZGNvbW0vdjIiXX19#service-1",
# "type" : "DIDCommMessaging",
# "serviceEndpoint" : {
# "uri" : "ws://localhost:8080/ws",
# "accept" : [
# "didcomm/v2"
# ]
# }
# }
# ]
# }
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import fmgp.did.comm.*
import fmgp.did.comm.protocol.*
import fmgp.did.framework.TransportFactoryImp
import fmgp.did.method.peer.*
import fmgp.did.method.prism.*
import org.hyperledger.identus.mediator.db.*
import org.hyperledger.identus.mediator.protocols.*
import zio.*
Expand Down Expand Up @@ -49,44 +50,51 @@ object CurveConfig:
import CurveConfig.given

case class MediatorConfig(
endpoints: String,
keyAgreement: OKPPrivateKeyWithoutKid,
keyAuthentication: OKPPrivateKeyWithoutKid
did: DIDSubject,
keyStore: KeyStore
) {
val did = DIDPeer2.makeAgent(
Seq(keyAgreement, keyAuthentication),
endpoints
.split(";")
.toSeq
.map { endpoint => fmgp.util.Base64.encode(s"""{"t":"dm","s":{"uri":"$endpoint","a":["didcomm/v2"]}}""") }
.map(DIDPeerServiceEncodedNew(_))
)
val agentLayer: ZLayer[Any, Nothing, MediatorAgent] =
ZLayer(MediatorAgent.make(id = did.id, keyStore = did.keyStore))
ZLayer(MediatorAgent.make(id = did, keyStore = keyStore))
}
object MediatorConfig {
// val configPrivateKeyWithKid: Config[PrivateKeyWithKid] = { // hack to drop the nested name
// val tmp = Config.derived[PrivateKeyWithKid] // ECPrivateKeyWithKid OKPPrivateKeyWithKid
// tmp
// .asInstanceOf[Config.Fallback[PrivateKeyWithKid]]
// .first
// .asInstanceOf[Config.Lazy[PrivateKeyWithKid]]
// .thunk()
// .asInstanceOf[Config.Nested[PrivateKeyWithKid]]
// .config
// }

val config = {
Config
.string("did")
.mapOrFail(str =>
DIDSubject.either(str) match
case Left(value) => Left(Config.Error.InvalidData(Chunk("did"), "Fail to parse the DID: " + value.error))
case Right(value) => Right(value)
) ++
Config
.Sequence(
Config.Fallback[PrivateKeyWithKid](Config.derived[OKPPrivateKeyWithKid], Config.derived[ECPrivateKeyWithKid])
)
.map(keys => KeyStore(keys.toSet))
.nested("keyStore")
}.map((did, keyStore) => MediatorConfig(did = did, keyStore = keyStore))
}

case class DataBaseConfig(
connectionString: Option[String],
protocol: String,
host: String,
port: Option[String],
userName: String,
password: String,
dbName: String
connectionString: String,
) {
private def maybePort = port.filter(_.nonEmpty).map(":" + _).getOrElse("")
private def buildConnectionString = s"$protocol://$userName:$password@$host$maybePort/$dbName"

// Use provided connection string if available, otherwise construct from components
val finalConnectionString = connectionString.getOrElse(buildConnectionString)

val finalConnectionString = connectionString

// Display connection string with masked password
val displayConnectionString = connectionString match {
case Some(connStr) => connStr.replaceAll("://[^:]*:[^@]*@", "://***:***@") // Mask credentials in URI
case None => s"$protocol://$userName:******@$host$maybePort/$dbName"
}

override def toString: String = s"""DataBaseConfig($connectionString, $protocol, $host, $port, $userName, "******", $dbName)"""
val displayConnectionString = connectionString.replaceAll("://[^:]*:[^@]*@", "://***:***@")

override def toString: String =
s"""DataBaseConfig($displayConnectionString)"""
}

object MediatorStandalone extends ZIOAppDefault {
Expand All @@ -111,11 +119,14 @@ object MediatorStandalone extends ZIOAppDefault {
|Visit: https://github.com/hyperledger-identus/mediator""".stripMargin
)
configs = ConfigProvider.fromResourcePath()
mediatorConfig <- configs.nested("identity").nested("mediator").load(deriveConfig[MediatorConfig])
mediatorConfig <- configs
.nested("identity")
.nested("mediator")
.load(MediatorConfig.config) // deriveConfig[MediatorConfig]
agentLayer = mediatorConfig.agentLayer
_ <- ZIO.log(s"Identus Mediator APP. See https://github.com/hyperledger-identus/mediator")
_ <- ZIO.log(s"MediatorConfig: $mediatorConfig")
_ <- ZIO.log(s"DID: ${mediatorConfig.did.id.string}")
_ <- ZIO.log(s"DID: ${mediatorConfig.did.string}")
mediatorDbConfig <- configs.nested("database").nested("mediator").load(deriveConfig[DataBaseConfig])
_ <- ZIO.log(s"MediatorDb Connection String: ${mediatorDbConfig.displayConnectionString}")
port <- configs
Expand All @@ -130,12 +141,20 @@ object MediatorStandalone extends ZIOAppDefault {
.nested("mediator")
.load(Config.string("escalateTo"))
_ <- ZIO.log(s"Problem reports escalated to: $escalateTo")
transportFactory = Scope.default >>> (Client.default >>> TransportFactoryImp.layer)
httpClient = Scope.default ++ Client.default
transportFactory = httpClient >>> TransportFactoryImp.layer
mongo = AsyncDriverResource.layer >>> ReactiveMongoApi.layer(mediatorDbConfig.finalConnectionString)
repos = mongo >>> (MessageItemRepo.layer ++ UserAccountRepo.layer ++ OutboxMessageRepo.layer)
baseUrlForDIDPrismResolverVar <- configs
.nested("mediator")
.load(Config.string("didPrismResolver"))
didResolver = for {
peer <- DidPeerResolver.layerDidPeerResolver
prism <- DIDPrismResolver.layerDIDPrismResolver(baseUrlForDIDPrismResolverVar)
} yield ZEnvironment(MultiFallbackResolver(peer.get, prism.get): Resolver) // MultiParResolver(peer, prism)
myServer <- Server
.serve((MediatorAgent.didCommApp ++ DIDCommRoutes.app) @@ (Middleware.cors))
.provideSomeLayer(DidPeerResolver.layerDidPeerResolver)
.provideSomeLayer(httpClient >>> HttpUtils.layer >>> didResolver)
.provideSomeLayer(agentLayer)
.provideSomeLayer(repos)
.provideSomeLayer(Scope.default >>> ((agentLayer ++ transportFactory ++ repos) >>> OperatorImp.layer))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import com.raquo.laminar.api.L.*
import fmgp.did.*
import fmgp.did.comm.*
import fmgp.did.comm.TO
import fmgp.did.method.peer.DIDPeer
import org.scalajs.dom

import scala.scalajs.js
Expand Down
Loading