Skip to content

Commit

Permalink
feat : mediator Trust ping kotlin example (#11)
Browse files Browse the repository at this point in the history
Signed-off-by: Shailesh Patil <53746241+mineme0110@users.noreply.github.com>
Signed-off-by: mineme0110 <shailesh.patil@iohk.io>
  • Loading branch information
mineme0110 committed May 1, 2024
1 parent 9b61bf3 commit 4555ae0
Show file tree
Hide file tree
Showing 3 changed files with 376 additions and 3 deletions.
2 changes: 1 addition & 1 deletion docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ services:
image: ghcr.io/input-output-hk/mediator:0.1.1-SNAPSHOT
ports:
- 8080:8080
network_mode: host
network_mode: host #hash on mac remove this the default is bridge we can use host.docker.internal
environment:
# Creates the identity: "did:peer:2.Ez6LSghwSE437wnDE1pt3X6hVDUQzSjsHzinpX3XFvMjRAm7y.Vz6Mkhh1e5CEYYq6JBUcTZ6Cp2ranCWRrv7Yax3Le4N59R6dd.SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9rOHMtaW50LmF0YWxhcHJpc20uaW8vbWVkaWF0b3IiLCJyIjpbXSwiYSI6WyJkaWRjb21tL3YyIl19"
- KEY_AGREEMENT_D=Z6D8LduZgZ6LnrOHPrMTS6uU2u5Btsrk1SGs4fn8M7c
Expand Down
373 changes: 373 additions & 0 deletions make-trust-ping-example-kotlin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,373 @@
# Test Mediator (Trust Ping)


Start the mediator from repo using sbt
```sbt
sbt mediator/run
```
Using Docker
***if you have mac os comment the the line
#network_mode: host in docker-compose.yaml***

```shell
docker:publishLocal # Compile and create the mediator image
docker-compose up #docker run -p 8080:8080 ghcr.io/input-output-hk/mediator:0.1.0-SNAPSHOT
```


### Required Dependencies for e.g. add to your build.gradle.kts

```kotlin
dependencies {
implementation("org.didcommx:didcomm:0.3.0")
implementation("org.didcommx:peerdid:0.3.0")
implementation("io.ktor:ktor-server-netty:2.3.0")
implementation("io.ktor:ktor-client-apache:2.3.0")
}
```kotlin


### Create a Listener.kt for listening to mediator reply. for e.g. copy the below code in Listener.kt

```kotlin
import io.ktor.http.*
import io.ktor.server.application.*
import io.ktor.server.engine.*
import io.ktor.server.netty.*
import io.ktor.server.request.*
import io.ktor.server.response.*
import io.ktor.server.routing.*

abstract class Listener {

private var receivedResponse: String? = null

fun route(application: Application) {
application.routing {
post("/") {
val json = call.receiveText()
receivedResponse = json
call.respond(HttpStatusCode.OK, "Data received")
}
}
}

fun startListening(port: Int = 9999) {
embeddedServer(Netty, port = 9999, module = {route(this)}).start(wait = false)
}

fun receivedResponse(): String? {
return receivedResponse
}

}

```kotlin

### Create a DidAgent.kt for e.g. copy the below code in DidAgent.kt

```kotlin
import com.nimbusds.jose.jwk.OctetKeyPair
import org.didcommx.didcomm.common.VerificationMaterial
import org.didcommx.didcomm.common.VerificationMaterialFormat
import org.didcommx.didcomm.common.VerificationMethodType
import org.didcommx.didcomm.diddoc.DIDDocResolver
import org.didcommx.didcomm.secret.Secret
import org.didcommx.didcomm.secret.SecretResolverInMemory
import org.didcommx.peerdid.VerificationMaterialFormatPeerDID
import org.didcommx.peerdid.VerificationMaterialPeerDID
import org.didcommx.peerdid.VerificationMethodTypePeerDID
import org.didcommx.peerdid.core.*

data class DidId(val value: String)

interface DidAgent {
val did: DidId
val jwkForKeyAgreement: List<OctetKeyPair>
val jwkForKeyAuthentication: List<OctetKeyPair>
}


data class PeerDID(
override val did: DidId,
override val jwkForKeyAgreement: List<OctetKeyPair>,
override val jwkForKeyAuthentication: List<OctetKeyPair>,
) : DidAgent, Listener() {
val didDocument: String
get() = org.didcommx.peerdid.resolvePeerDID(did.value, VerificationMaterialFormatPeerDID.JWK)

fun getSecretResolverInMemory(): SecretResolverInMemory {

fun validateRawKeyLength(key: ByteArray) {
// for all supported key types now (ED25519 and X25510) the expected size is 32
if (key.size != 32)
throw IllegalArgumentException("Invalid key $key")
}

fun createMultibaseEncnumbasis(key: VerificationMaterialPeerDID<out VerificationMethodTypePeerDID>): String {
val decodedKey = when (key.format) {
VerificationMaterialFormatPeerDID.BASE58 -> fromBase58(key.value.toString())
VerificationMaterialFormatPeerDID.MULTIBASE -> fromMulticodec(fromBase58Multibase(key.value.toString()).second).second
VerificationMaterialFormatPeerDID.JWK -> fromJwk(key)
}
validateRawKeyLength(decodedKey)
return toBase58Multibase(toMulticodec(decodedKey, key.type))
}

val keyAgreement =
AgentPeerService.keyAgreemenFromPublicJWK(this.jwkForKeyAgreement.first()) // TODO Fix first()
val keyAuthentication =
AgentPeerService.keyAuthenticationFromPublicJWK(this.jwkForKeyAuthentication.first()) // TODO Fix first()

val keyIdAgreement = createMultibaseEncnumbasis(keyAgreement).drop(1)
val keyIdAuthentication = createMultibaseEncnumbasis(keyAuthentication).drop(1)

val secretKeyAgreement = Secret(
"${this.did.value}#$keyIdAgreement",
VerificationMethodType.JSON_WEB_KEY_2020,
VerificationMaterial(VerificationMaterialFormat.JWK, this.jwkForKeyAgreement.first().toJSONString())
)
val secretKeyAuthentication = Secret(
"${this.did.value}#$keyIdAuthentication",
VerificationMethodType.JSON_WEB_KEY_2020,
VerificationMaterial(VerificationMaterialFormat.JWK, this.jwkForKeyAuthentication.first().toJSONString())
)

return SecretResolverInMemory(
mutableMapOf(
"${this.did.value}#$keyIdAgreement" to secretKeyAgreement,
"${this.did.value}#$keyIdAuthentication" to secretKeyAuthentication,
).toMap()
)
}

fun getDidDocResolverInMemory(): DIDDocResolver {
return DIDDocResolverPeerDID()
}

fun getServiceEndpoint(): String {
return DIDDocResolverPeerDID().resolve(this.did.value).get().didCommServices.map { it.serviceEndpoint }.first()
}
}

```kotlin

### Create an AgentPeerService.kt, for e.g. copy the below code in AgentPeerService.kt

```kotlin
import com.nimbusds.jose.jwk.Curve
import com.nimbusds.jose.jwk.OctetKeyPair
import com.nimbusds.jose.jwk.gen.OctetKeyPairGenerator
import org.didcommx.peerdid.VerificationMaterialFormatPeerDID
import org.didcommx.peerdid.VerificationMaterialPeerDID
import org.didcommx.peerdid.VerificationMethodTypeAgreement
import org.didcommx.peerdid.VerificationMethodTypeAuthentication

object AgentPeerService {

fun createServiceJson(serviceEndpoint: String): String {
return """
{
"type": "DIDCommMessaging",
"serviceEndpoint": "$serviceEndpoint",
"routingKeys": [],
"accept": ["didcomm/v2"]
}
"""
}

fun makeNewJwkKeyX25519(): OctetKeyPair = OctetKeyPairGenerator(Curve.X25519).generate()
fun makeNewJwkKeyEd25519(): OctetKeyPair = OctetKeyPairGenerator(Curve.Ed25519).generate()
fun keyAgreemenFromPublicJWK(key: OctetKeyPair): VerificationMaterialPeerDID<VerificationMethodTypeAgreement> =
VerificationMaterialPeerDID(
VerificationMaterialFormatPeerDID.JWK,
key.toPublicJWK(),
VerificationMethodTypeAgreement.JSON_WEB_KEY_2020
)

fun keyAuthenticationFromPublicJWK(key: OctetKeyPair): VerificationMaterialPeerDID<VerificationMethodTypeAuthentication> =
VerificationMaterialPeerDID(
VerificationMaterialFormatPeerDID.JWK,
key.toPublicJWK(),
VerificationMethodTypeAuthentication.JSON_WEB_KEY_2020
)

fun makePeerDid(
jwkForKeyAgreement: OctetKeyPair = makeNewJwkKeyX25519(),
jwkForKeyAuthentication: OctetKeyPair = makeNewJwkKeyEd25519(),
serviceEndpoint: String? = null
): PeerDID {
println("**************************jwkForKeyAgreement***********************************************************")
println(jwkForKeyAgreement)
println("**************************jwkForKeyAgreement***********************************************************")
println("************************************jwkForKeyAuthentication*************************************************")
println(jwkForKeyAuthentication)
println("************************************jwkForKeyAuthentication*************************************************")

val did = org.didcommx.peerdid.createPeerDIDNumalgo2(
listOf(keyAgreemenFromPublicJWK(jwkForKeyAgreement)),
listOf(keyAuthenticationFromPublicJWK(jwkForKeyAuthentication)),
serviceEndpoint?.let { createServiceJson(serviceEndpoint) }
)
return PeerDID(DidId(did), listOf(jwkForKeyAgreement), listOf(jwkForKeyAuthentication))
}

fun makeAgent(
serviceEndpoint: String? = null
): PeerDID {
return makePeerDid(
makeNewJwkKeyX25519(),
makeNewJwkKeyEd25519(),
serviceEndpoint = serviceEndpoint
)
}

fun makeAgentFromPeerDid(
did: String
): PeerDID {
return PeerDID(DidId(did), listOf(), listOf())
}
}

```kotlin

### Create a DidDocResolver.kt for e.g. copy the below code in DidDocResolver.kt

```kotlin
import org.didcommx.didcomm.common.VerificationMaterial
import org.didcommx.didcomm.common.VerificationMaterialFormat
import org.didcommx.didcomm.common.VerificationMethodType
import org.didcommx.didcomm.diddoc.DIDCommService
import org.didcommx.didcomm.diddoc.DIDDoc
import org.didcommx.didcomm.diddoc.DIDDocResolver
import org.didcommx.didcomm.diddoc.VerificationMethod
import org.didcommx.didcomm.utils.toJson
import org.didcommx.peerdid.DIDCommServicePeerDID
import org.didcommx.peerdid.DIDDocPeerDID
import org.didcommx.peerdid.VerificationMaterialFormatPeerDID
import org.didcommx.peerdid.resolvePeerDID
import java.util.*

class DIDDocResolverPeerDID : DIDDocResolver {

override fun resolve(did: String): Optional<DIDDoc> {
val didDocJson = resolvePeerDID(did, format = VerificationMaterialFormatPeerDID.JWK)
val didDoc = DIDDocPeerDID.fromJson(didDocJson)
return Optional.ofNullable(
DIDDoc(
did = did,
keyAgreements = didDoc.agreementKids,
authentications = didDoc.authenticationKids,
verificationMethods = (didDoc.authentication + didDoc.keyAgreement).map {
VerificationMethod(
id = it.id,
type = VerificationMethodType.JSON_WEB_KEY_2020,
controller = it.controller,
verificationMaterial = VerificationMaterial(
format = VerificationMaterialFormat.JWK,
value = toJson(it.verMaterial.value)
)
)
},
didCommServices = didDoc.service?.mapNotNull {
when (it) {
is DIDCommServicePeerDID ->
DIDCommService(
id = it.id,
serviceEndpoint = it.serviceEndpoint,
routingKeys = it.routingKeys,
accept = it.accept
)

else -> null
}
}
?: emptyList()
)
)
}
}
```kotlin



### This is your Main.kt for e.g. copy the below code in Main.kt

```kotlin
import io.ktor.client.*
import io.ktor.client.engine.apache.*
import io.ktor.client.request.*
import io.ktor.client.statement.*
import io.ktor.http.*
import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import org.didcommx.didcomm.DIDComm
import org.didcommx.didcomm.message.Message
import org.didcommx.didcomm.model.PackEncryptedParams

fun main(args: Array<String>) {

//For mac user: if you are running the mediator using docker replace localhost with host.docker.internal
// serviceEndpoint = "http://host.docker.internal:9999/"
val alice = AgentPeerService.makeAgent(serviceEndpoint = "http://localhost:9999/")
println(alice.did.value)
println(alice.didDocument)

val mediatorDID =
"did:peer:2.Ez6LSghwSE437wnDE1pt3X6hVDUQzSjsHzinpX3XFvMjRAm7y.Vz6Mkhh1e5CEYYq6JBUcTZ6Cp2ranCWRrv7Yax3Le4N59R6dd.SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9rOHMtaW50LmF0YWxhcHJpc20uaW8vbWVkaWF0b3IiLCJyIjpbXSwiYSI6WyJkaWRjb21tL3YyIl19"

val mediator = AgentPeerService.makeAgentFromPeerDid(mediatorDID)
val mediatorServiceEndpoint = "http://localhost:8080" // mediator.getServiceEndpoint()

val didComm = DIDComm(mediator.getDidDocResolverInMemory(), alice.getSecretResolverInMemory())

val messageTrustPing = Message.builder(
id = "1234567890",
body = mapOf("response_requested" to true),
type = "https://didcomm.org/trust-ping/2.0/ping"
).from(alice.did.value)
.to(listOf(mediator.did.value))
.build()

//Encrypt Message
val packResult = didComm.packEncrypted(
PackEncryptedParams.builder(messageTrustPing, mediatorDID)
.from(alice.did.value)
.build()
)
println("*************************************************************************************")
println(packResult.packedMessage)
println("*************************************************************************************")

// Start the listener in a separate coroutine
runBlocking {
val completion = CompletableDeferred<Unit>()

val clientListener = launch(Dispatchers.Default) {
alice.startListening(9999)
}
clientListener.join()
launch(Dispatchers.Default) {
val client = HttpClient(Apache)
val response: HttpResponse = client.post(mediatorServiceEndpoint) {
contentType(ContentType.Application.Json)
setBody(packResult.packedMessage)
}
println("Client Received reply: $response")
val json = alice.receivedResponse()
println("Received JSON: $json")
// Make an assertion that the response is successful if needed
// ...
client.close()
completion.complete(Unit)
}

completion.await()

// Stop the listener
clientListener.cancel()
}
}
```kotlin
4 changes: 2 additions & 2 deletions make-trust-ping-example.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ val agent = DIDPeer2.makeAgent(
x = "MBjnXZxkMcoQVVL21hahWAw43RuAG-i64ipbeKKqwoA",
kid = None
)
),
Seq(DIDPeerServiceEncoded(s = "http://localhost:5000/"))
), // //For mac user: if you are running the mediator using docker replace localhost with host.docker.internal
Seq(DIDPeerServiceEncoded(s = "http://localhost:5000/"))
)

val mediator = "did:peer:2.Ez6LSghwSE437wnDE1pt3X6hVDUQzSjsHzinpX3XFvMjRAm7y.Vz6Mkhh1e5CEYYq6JBUcTZ6Cp2ranCWRrv7Yax3Le4N59R6dd.SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9rOHMtaW50LmF0YWxhcHJpc20uaW8vbWVkaWF0b3IiLCJyIjpbXSwiYSI6WyJkaWRjb21tL3YyIl19"
Expand Down

0 comments on commit 4555ae0

Please sign in to comment.