From 38e36d7727579bf73abb4cdeb489ea60cf7c84a8 Mon Sep 17 00:00:00 2001 From: aminbenmansour Date: Mon, 16 Oct 2023 03:26:30 +0100 Subject: [PATCH 01/49] feat(keri): setting environment for KERI We relied on keripy, the python implementation of KERI from WebOfTrust --- backend.Dockerfile | 25 +++++++++++++++++++++++++ requirements.txt | 6 ++++++ 2 files changed, 31 insertions(+) create mode 100644 requirements.txt diff --git a/backend.Dockerfile b/backend.Dockerfile index 17c6310..a0f27de 100644 --- a/backend.Dockerfile +++ b/backend.Dockerfile @@ -9,6 +9,31 @@ RUN gradle clean installDist FROM docker.io/eclipse-temurin:17 +SHELL ["/bin/bash", "-c"] + +RUN apt update && \ + apt upgrade -y + +# installing crypto lib dependencies for KERI +RUN apt install -y libsodium23 && \ + apt install -y libsodium-dev && \ + apt install -y libffi-dev + +# setup Rust for blake3 dependency build +RUN curl https://sh.rustup.rs -sSf | sh -s -- -y && \ + source "$HOME/.cargo/env" + +# installing keripy directly from source (published 1.0.0 is bugged) +WORKDIR /keripy +RUN apt install git -y && \ + git clone -b development https://github.com/WebOfTrust/keripy.git . && \ + git checkout 4185296affb2348d19af6009be04f682a3e19360 + +RUN apt install pip -y && \ + source "$HOME/.cargo/env" &&pip install -r requirements.txt && \ + mkdir -p /usr/local/var/keri && \ + pip install -e . + COPY --from=buildstage /work/build/install/ / WORKDIR /waltid-web-wallet diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..2d25598 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,6 @@ +lmdb>=0.98 +pysodium>=0.7.5 +blake3>=0.1.5 +msgpack>=1.0.0 +simplejson>=3.17.0 +cbor2>=5.1.0 \ No newline at end of file From 6ff49b20c676397cce868df3786cbf1aacf390b4 Mon Sep 17 00:00:00 2001 From: aminbenmansour Date: Tue, 17 Oct 2023 12:52:39 +0100 Subject: [PATCH 02/49] feat(witnesses): configurations to expose witnesses configuration Caveat: Localhost is hard-coded, in a production environment we need to inject the actual IP address --- config/keri/cf/main/wan-witness.json | 8 ++++++++ config/keri/cf/main/wes-witness.json | 8 ++++++++ config/keri/cf/main/wil-witness.json | 8 ++++++++ 3 files changed, 24 insertions(+) create mode 100644 config/keri/cf/main/wan-witness.json create mode 100644 config/keri/cf/main/wes-witness.json create mode 100644 config/keri/cf/main/wil-witness.json diff --git a/config/keri/cf/main/wan-witness.json b/config/keri/cf/main/wan-witness.json new file mode 100644 index 0000000..29dd295 --- /dev/null +++ b/config/keri/cf/main/wan-witness.json @@ -0,0 +1,8 @@ +{ + "wan": { + "dt": "2022-01-20T12:57:59.823350+00:00", + "curls": ["tcp://127.0.0.1:5632/", "http://127.0.0.1:5642/"] + }, + "dt": "2022-01-20T12:57:59.823350+00:00", + "iurls": [] +} \ No newline at end of file diff --git a/config/keri/cf/main/wes-witness.json b/config/keri/cf/main/wes-witness.json new file mode 100644 index 0000000..c71308a --- /dev/null +++ b/config/keri/cf/main/wes-witness.json @@ -0,0 +1,8 @@ +{ + "wes": { + "dt": "2022-01-20T12:57:59.823350+00:00", + "curls": ["tcp://127.0.0.1:5634/", "http://127.0.0.1:5644/"] + }, + "dt": "2022-01-20T12:57:59.823350+00:00", + "iurls": [] +} \ No newline at end of file diff --git a/config/keri/cf/main/wil-witness.json b/config/keri/cf/main/wil-witness.json new file mode 100644 index 0000000..f1869bf --- /dev/null +++ b/config/keri/cf/main/wil-witness.json @@ -0,0 +1,8 @@ +{ + "wil": { + "dt": "2022-01-20T12:57:59.823350+00:00", + "curls": ["tcp://127.0.0.1:5633/", "http://127.0.0.1:5643/"] + }, + "dt": "2022-01-20T12:57:59.823350+00:00", + "iurls": [] +} \ No newline at end of file From 1659fef0661f2f6edcfa3ead8c2e719b5a7dfc55 Mon Sep 17 00:00:00 2001 From: aminbenmansour Date: Tue, 17 Oct 2023 13:03:13 +0100 Subject: [PATCH 03/49] feat(witnesses): initialize and start witnesses --- config/keri/scripts/witnesses.sh | 35 ++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 config/keri/scripts/witnesses.sh diff --git a/config/keri/scripts/witnesses.sh b/config/keri/scripts/witnesses.sh new file mode 100644 index 0000000..65f8654 --- /dev/null +++ b/config/keri/scripts/witnesses.sh @@ -0,0 +1,35 @@ +#!/bin/bash + +CONFIG_DIR="config" + +# initiating witnesses +kli init --name wan --salt 0AB3YW5uLXRoZS13aXRuZXNz --nopasscode \ + --config-dir "${CONFIG_DIR}" \ + --config-file main/wan-witness + +kli witness start --name wan --alias wan -T 5632 -H 5642 \ + --config-dir "${CONFIG_DIR}" \ + --config-file wan-witness & +WAN_WITNESS_PID=$! + + +kli init --name wil --salt 0AB3aWxsLXRoZS13aXRuZXNz --nopasscode \ + --config-dir "${CONFIG_DIR}" \ + --config-file main/wil-witness + + +kli witness start --name wil --alias wil -T 5633 -H 5643 \ + --config-dir "${CONFIG_DIR}" \ + --config-file wil-witness & +WIL_WITNESS_PID=$! + + +kli init --name wes --salt 0AB3ZXNzLXRoZS13aXRuZXNz --nopasscode \ + --config-dir "${CONFIG_DIR}" \ + --config-file main/wes-witness + + +kli witness start --name wes --alias wes -T 5634 -H 5644 \ + --config-dir "${CONFIG_DIR}" \ + --config-file wes-witness & +WES_WITNESS_PID=$! \ No newline at end of file From ae0de76795111c8cf35300d947d10b0b84f5f1d2 Mon Sep 17 00:00:00 2001 From: aminbenmansour Date: Tue, 17 Oct 2023 13:03:41 +0100 Subject: [PATCH 04/49] feat(init): initialization config Applied when creating a keystore and a database (kli init) --- config/keri/cf/controller-oobi-bootstrap.json | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 config/keri/cf/controller-oobi-bootstrap.json diff --git a/config/keri/cf/controller-oobi-bootstrap.json b/config/keri/cf/controller-oobi-bootstrap.json new file mode 100644 index 0000000..5c18eba --- /dev/null +++ b/config/keri/cf/controller-oobi-bootstrap.json @@ -0,0 +1,8 @@ +{ + "dt": "2022-01-20T12:57:59.823350+00:00", + "iurls": [ + "http://127.0.0.1:5642/oobi/BBilc4-L3tFUnfM_wJr4S4OJanAv_VmF_dJNN6vkf2Ha", + "http://127.0.0.1:5643/oobi/BLskRTInXnMxWaGqcpSyMgo0nYbalW99cGZESrz3zapM", + "http://127.0.0.1:5644/oobi/BIKKuvBwpmDVA4Ds-EpL5bt9OqPzWPja2LigFYZN2YfX" + ] +} From e490a377a4c9f209e3977a676b71ad23ce6188dd Mon Sep 17 00:00:00 2001 From: aminbenmansour Date: Tue, 17 Oct 2023 13:08:24 +0100 Subject: [PATCH 05/49] feat(incept): creating a new entity in KERI by initializing a new KEL Applied at the inception event (kli incept) --- config/keri/cf/inception-config.json | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 config/keri/cf/inception-config.json diff --git a/config/keri/cf/inception-config.json b/config/keri/cf/inception-config.json new file mode 100644 index 0000000..b60b409 --- /dev/null +++ b/config/keri/cf/inception-config.json @@ -0,0 +1,13 @@ +{ + "transferable": true, + "wits": [ + "BBilc4-L3tFUnfM_wJr4S4OJanAv_VmF_dJNN6vkf2Ha", + "BLskRTInXnMxWaGqcpSyMgo0nYbalW99cGZESrz3zapM", + "BIKKuvBwpmDVA4Ds-EpL5bt9OqPzWPja2LigFYZN2YfX" + ], + "toad": 3, + "icount": 1, + "ncount": 1, + "isith": "1", + "nsith": "1" +} \ No newline at end of file From 880e922635db4e3637d3865f7e723c6a79416d24 Mon Sep 17 00:00:00 2001 From: aminbenmansour Date: Tue, 24 Oct 2023 07:54:55 +0100 Subject: [PATCH 06/49] feat(logging): add a logging dependency --- build.gradle.kts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/build.gradle.kts b/build.gradle.kts index 1bea40d..858c82f 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -137,4 +137,7 @@ dependencies { testImplementation("io.kotest:kotest-assertions-core:5.5.5") testImplementation("io.kotest.extensions:kotest-assertions-ktor:2.0.0")*/ testImplementation("io.ktor:ktor-server-tests-jvm:$ktorVersion") + + // Logging + implementation("io.github.oshai:kotlin-logging:5.1.0") } From 029c45e7c4665b90d98f6c64fe97eba1014cbc02 Mon Sep 17 00:00:00 2001 From: aminbenmansour Date: Tue, 24 Oct 2023 07:56:21 +0100 Subject: [PATCH 07/49] fix(config): populate file with witnesses to designate --- config/keri/cf/controller-oobi-bootstrap.json | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 config/keri/cf/controller-oobi-bootstrap.json diff --git a/config/keri/cf/controller-oobi-bootstrap.json b/config/keri/cf/controller-oobi-bootstrap.json old mode 100644 new mode 100755 From 4877505ecd5188cfd16ad5bbf2f6f4179e6c9e69 Mon Sep 17 00:00:00 2001 From: aminbenmansour Date: Tue, 24 Oct 2023 07:59:18 +0100 Subject: [PATCH 08/49] feat(init): create a service for initializing an entity --- .../service/dto/KeriUserManagementObjects.kt | 14 +++ .../id/walt/service/keri/KeriInitService.kt | 90 +++++++++++++++++++ .../keri/interfaces/KeriInitInterface.kt | 9 ++ 3 files changed, 113 insertions(+) create mode 100644 src/main/kotlin/id/walt/service/dto/KeriUserManagementObjects.kt create mode 100644 src/main/kotlin/id/walt/service/keri/KeriInitService.kt create mode 100644 src/main/kotlin/id/walt/service/keri/interfaces/KeriInitInterface.kt diff --git a/src/main/kotlin/id/walt/service/dto/KeriUserManagementObjects.kt b/src/main/kotlin/id/walt/service/dto/KeriUserManagementObjects.kt new file mode 100644 index 0000000..24ad3b7 --- /dev/null +++ b/src/main/kotlin/id/walt/service/dto/KeriUserManagementObjects.kt @@ -0,0 +1,14 @@ +package id.walt.service.dto + +import kotlinx.serialization.Serializable + +@Serializable +data class KeriCreateDbRequest ( + val passcode: String +) + +@Serializable +data class KeriCreateDbResponse ( + val salt: String, + val witnesses: List +) diff --git a/src/main/kotlin/id/walt/service/keri/KeriInitService.kt b/src/main/kotlin/id/walt/service/keri/KeriInitService.kt new file mode 100644 index 0000000..2134e53 --- /dev/null +++ b/src/main/kotlin/id/walt/service/keri/KeriInitService.kt @@ -0,0 +1,90 @@ +package id.walt.service.keri + +import id.walt.service.dto.KeriCreateDbResponse +import id.walt.service.keri.interfaces.KeriInitInterface +import java.io.BufferedReader +import java.io.IOException +import java.io.InputStreamReader + +class KeriInitService: KeriInitInterface { + + private val CONFIG_DIR = "config" + private val OOBI_FILE = "controller-oobi-bootstrap.json" + override fun generateSalt(): String { + val command: List = listOf("kli", "salt") + var salt: String = "" + try { + val processBuilder = ProcessBuilder(command) + val process = processBuilder.start() + + + val reader = BufferedReader(InputStreamReader(process.inputStream)) + + var line: String? + while (reader.readLine().also { line = it } != null) { + salt += line + } + + val errorReader = BufferedReader(InputStreamReader(process.errorStream)) + var errorLine: String? + while (errorReader.readLine().also { errorLine = it } != null) { + System.err.println(errorLine) + } + process.waitFor() + + } catch(e: IOException ) { + e.printStackTrace() + } catch (e: InterruptedException) { + e.printStackTrace() + } + if (salt.isBlank()) { + throw IllegalArgumentException("KERI: Salt could not be generated") + } else { + return salt.trimEnd('\n') + } + } + + + override fun createKeystoreDatabase(name: String, passcode: String): KeriCreateDbResponse { + val salt: String = generateSalt() + val witnessesOOBIs = mutableListOf() + + val command: List = listOf( + "kli", "init", + "--name" ,name, + "--salt", salt, + "--passcode", passcode, + "--config-dir", CONFIG_DIR, + "--config-file", OOBI_FILE + ) + + try { + val processBuilder = ProcessBuilder(command) + val process = processBuilder.start() + + val reader = BufferedReader(InputStreamReader(process.inputStream)) + var line: String? + + while (reader.readLine().also { line = it } != null) { + println(line) + if(line!!.startsWith("http")) { + witnessesOOBIs.add(line!!.split(" ")[0]) + } + } + + val errorReader = BufferedReader(InputStreamReader(process.errorStream)) + var errorLine: String? + while (errorReader.readLine().also { errorLine = it } != null) { + System.err.println(errorLine) + } + process.waitFor() + + } catch(e: IOException) { + e.printStackTrace() + } catch (e: InterruptedException) { + e.printStackTrace() + } + + return KeriCreateDbResponse(salt, witnessesOOBIs) + } +} \ No newline at end of file diff --git a/src/main/kotlin/id/walt/service/keri/interfaces/KeriInitInterface.kt b/src/main/kotlin/id/walt/service/keri/interfaces/KeriInitInterface.kt new file mode 100644 index 0000000..1765283 --- /dev/null +++ b/src/main/kotlin/id/walt/service/keri/interfaces/KeriInitInterface.kt @@ -0,0 +1,9 @@ +package id.walt.service.keri.interfaces + +import id.walt.service.dto.KeriCreateDbResponse + +interface KeriInitInterface { + + fun generateSalt(): String; + fun createKeystoreDatabase(name: String, passcode: String): KeriCreateDbResponse; +} \ No newline at end of file From cdc6214f814cea724d5e26ff107a61275fb0ec81 Mon Sep 17 00:00:00 2001 From: aminbenmansour Date: Tue, 24 Oct 2023 08:03:22 +0100 Subject: [PATCH 09/49] feat(init): exposing KERI controller --- src/main/kotlin/id/walt/Application.kt | 2 ++ .../id/walt/web/controllers/KeriController.kt | 31 +++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 src/main/kotlin/id/walt/web/controllers/KeriController.kt diff --git a/src/main/kotlin/id/walt/Application.kt b/src/main/kotlin/id/walt/Application.kt index 8b38788..9ea76ca 100644 --- a/src/main/kotlin/id/walt/Application.kt +++ b/src/main/kotlin/id/walt/Application.kt @@ -69,4 +69,6 @@ fun Application.module() { history() account() nfts() + + keri() } diff --git a/src/main/kotlin/id/walt/web/controllers/KeriController.kt b/src/main/kotlin/id/walt/web/controllers/KeriController.kt new file mode 100644 index 0000000..be635a8 --- /dev/null +++ b/src/main/kotlin/id/walt/web/controllers/KeriController.kt @@ -0,0 +1,31 @@ +package id.walt.web.controllers + +import id.walt.service.dto.KeriCreateDbRequest +import id.walt.service.keri.KeriInitService +import io.github.smiley4.ktorswaggerui.dsl.post +import io.github.smiley4.ktorswaggerui.dsl.route +import io.ktor.http.* +import io.ktor.server.application.* +import io.ktor.server.request.* +import io.ktor.server.response.* + +fun Application.keri() = walletRoute { + route("keri", { + tags = listOf("Key Event Receipt Infrastructure (KERI)") + }) { + + post("db/{name}", { + summary = "Create an encrypted database and keystore for an entity" + }) { + val name = call.parameters["name"] ?: return@post call.respond(HttpStatusCode.BadRequest) + val dto = call.receive() + val response = KeriInitService().createKeystoreDatabase(name, dto.passcode) + + + call.respond(HttpStatusCode.Created, response) + + + } + + } +} \ No newline at end of file From 3ad6bd4007f45935e42895cdf90251935a6c8b32 Mon Sep 17 00:00:00 2001 From: aminbenmansour Date: Tue, 24 Oct 2023 08:09:08 +0100 Subject: [PATCH 10/49] doc(init): describe swagger request and response with OpenApi --- .../id/walt/web/controllers/KeriController.kt | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/main/kotlin/id/walt/web/controllers/KeriController.kt b/src/main/kotlin/id/walt/web/controllers/KeriController.kt index be635a8..78dce7d 100644 --- a/src/main/kotlin/id/walt/web/controllers/KeriController.kt +++ b/src/main/kotlin/id/walt/web/controllers/KeriController.kt @@ -1,6 +1,7 @@ package id.walt.web.controllers import id.walt.service.dto.KeriCreateDbRequest +import id.walt.service.dto.KeriCreateDbResponse import id.walt.service.keri.KeriInitService import io.github.smiley4.ktorswaggerui.dsl.post import io.github.smiley4.ktorswaggerui.dsl.route @@ -16,6 +17,32 @@ fun Application.keri() = walletRoute { post("db/{name}", { summary = "Create an encrypted database and keystore for an entity" + + request { + pathParameter("name") { + description = "keystore name and file location of KERI keystore" + example = "waltid" + } + + body { + description = "22 character encryption passcode for keystore" + } + + } + response { + HttpStatusCode.Created to { + body { + description = "The salt for generating keys and the list of designated witnesses" + example("application/json", KeriCreateDbResponse(salt = "0123456789abcdefghijk", witnesses = listOf( + "http://127.0.0.1:5642/oobi/BBilc4-L3tFUnfM_wJr4S4OJanAv_VmF_dJNN6vkf2Ha", + "http://127.0.0.1:5643/oobi/BLskRTInXnMxWaGqcpSyMgo0nYbalW99cGZESrz3zapM", + "http://127.0.0.1:5644/oobi/BIKKuvBwpmDVA4Ds-EpL5bt9OqPzWPja2LigFYZN2YfX" + ))) { + summary = "Example of a CreateDatabaseRequest" + } + } + } + } }) { val name = call.parameters["name"] ?: return@post call.respond(HttpStatusCode.BadRequest) val dto = call.receive() From cfa84ed36af3adbcd43c9769e02e10f5cc0c2e8d Mon Sep 17 00:00:00 2001 From: aminbenmansour Date: Wed, 25 Oct 2023 12:17:15 +0100 Subject: [PATCH 11/49] feat(incept): expose an inception endpoint to create a controller --- config/keri/{cf => }/inception-config.json | 2 +- .../service/dto/KeriUserManagementObjects.kt | 12 +++ .../walt/service/keri/KeriInceptionService.kt | 73 +++++++++++++++++++ .../keri/interfaces/KeriInceptionInterface.kt | 7 ++ .../id/walt/web/controllers/KeriController.kt | 15 ++++ 5 files changed, 108 insertions(+), 1 deletion(-) rename config/keri/{cf => }/inception-config.json (99%) create mode 100644 src/main/kotlin/id/walt/service/keri/KeriInceptionService.kt create mode 100644 src/main/kotlin/id/walt/service/keri/interfaces/KeriInceptionInterface.kt diff --git a/config/keri/cf/inception-config.json b/config/keri/inception-config.json similarity index 99% rename from config/keri/cf/inception-config.json rename to config/keri/inception-config.json index b60b409..850aca0 100644 --- a/config/keri/cf/inception-config.json +++ b/config/keri/inception-config.json @@ -10,4 +10,4 @@ "ncount": 1, "isith": "1", "nsith": "1" -} \ No newline at end of file +} diff --git a/src/main/kotlin/id/walt/service/dto/KeriUserManagementObjects.kt b/src/main/kotlin/id/walt/service/dto/KeriUserManagementObjects.kt index 24ad3b7..f56566d 100644 --- a/src/main/kotlin/id/walt/service/dto/KeriUserManagementObjects.kt +++ b/src/main/kotlin/id/walt/service/dto/KeriUserManagementObjects.kt @@ -12,3 +12,15 @@ data class KeriCreateDbResponse ( val salt: String, val witnesses: List ) + +@Serializable +data class KeriInceptionRequest ( + val alias: String, + val passcode: String +) +@Serializable +data class KeriInceptionResponse ( + val aid: String, + val did: String, + val publicKeys: List +) diff --git a/src/main/kotlin/id/walt/service/keri/KeriInceptionService.kt b/src/main/kotlin/id/walt/service/keri/KeriInceptionService.kt new file mode 100644 index 0000000..9ffb778 --- /dev/null +++ b/src/main/kotlin/id/walt/service/keri/KeriInceptionService.kt @@ -0,0 +1,73 @@ +package id.walt.service.keri + +import id.walt.service.dto.KeriInceptionResponse +import id.walt.service.keri.interfaces.KeriInceptionInterface +import java.io.BufferedReader +import java.io.IOException +import java.io.InputStreamReader + +class KeriInceptionService: KeriInceptionInterface { + + private val CONFIG_DIR = "config" + private val INCEPTION_FILE = "inception-config.json" + override fun inceptController(name: String, alias: String, passcode: String): KeriInceptionResponse { + var prefix = "" + val publicKeys = mutableListOf() + + val inceptCommand: List = listOf( + "kli", "incept", + "--name" ,name, + "--alias", alias, + "--passcode", passcode, + "--file", "$CONFIG_DIR/keri/$INCEPTION_FILE" + ) + + // kli status --name waltid --alias waltid-alias | awk '/Identifier:/ {print $2}' + val statusCommand: List = listOf( + "kli", "status", + "--name" ,name, + "--alias", alias, + "--passcode", passcode + ) + + try { + val processBuilder = ProcessBuilder(inceptCommand) + val process = processBuilder.start() + process.waitFor() + + val statusProcessBuilder = ProcessBuilder(statusCommand) + val statusProcess = statusProcessBuilder.start() + + val prefixInputReader = BufferedReader(InputStreamReader(statusProcess.inputStream)) + + var line: String? + var capturingPublicKeys = false + while (prefixInputReader.readLine().also { line = it } != null) { + if (line?.contains("Identifier:") == true) { + prefix = line!!.split(" ")[1] + } + + if (line?.startsWith("Public Keys:") == true) { + capturingPublicKeys = true + continue + } + + if (capturingPublicKeys && line?.isNotBlank() == true) { + publicKeys.add(line!!.trim().split(" ")[1]) + } else if (capturingPublicKeys && line?.isBlank() == true) { + break + } + } + + statusProcess.waitFor() + + } catch(e: IOException) { + e.printStackTrace() + } catch (e: InterruptedException) { + e.printStackTrace() + } + + return KeriInceptionResponse(prefix, "did:keri:$prefix", publicKeys) + } + +} \ No newline at end of file diff --git a/src/main/kotlin/id/walt/service/keri/interfaces/KeriInceptionInterface.kt b/src/main/kotlin/id/walt/service/keri/interfaces/KeriInceptionInterface.kt new file mode 100644 index 0000000..574950f --- /dev/null +++ b/src/main/kotlin/id/walt/service/keri/interfaces/KeriInceptionInterface.kt @@ -0,0 +1,7 @@ +package id.walt.service.keri.interfaces + +import id.walt.service.dto.KeriInceptionResponse + +interface KeriInceptionInterface { + fun inceptController(name: String, alias: String, passcode: String): KeriInceptionResponse; +} \ No newline at end of file diff --git a/src/main/kotlin/id/walt/web/controllers/KeriController.kt b/src/main/kotlin/id/walt/web/controllers/KeriController.kt index 78dce7d..8c7a708 100644 --- a/src/main/kotlin/id/walt/web/controllers/KeriController.kt +++ b/src/main/kotlin/id/walt/web/controllers/KeriController.kt @@ -2,6 +2,8 @@ package id.walt.web.controllers import id.walt.service.dto.KeriCreateDbRequest import id.walt.service.dto.KeriCreateDbResponse +import id.walt.service.dto.KeriInceptionRequest +import id.walt.service.keri.KeriInceptionService import id.walt.service.keri.KeriInitService import io.github.smiley4.ktorswaggerui.dsl.post import io.github.smiley4.ktorswaggerui.dsl.route @@ -54,5 +56,18 @@ fun Application.keri() = walletRoute { } + post("incept/{name}", { + summary = "Initialize a prefix" + }) { + val name = call.parameters["name"] ?: return@post call.respond(HttpStatusCode.BadRequest) + val dto = call.receive() + val response = KeriInceptionService().inceptController(name, dto.alias, dto.passcode) + + + call.respond(HttpStatusCode.Created, response) + + + } + } } \ No newline at end of file From 272ab9845a2497fb34b749de722d8ca5bc21a91f Mon Sep 17 00:00:00 2001 From: aminbenmansour Date: Wed, 25 Oct 2023 13:11:15 +0100 Subject: [PATCH 12/49] docs(incept): describe request and response formats with examples --- .../id/walt/web/controllers/KeriController.kt | 28 ++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/id/walt/web/controllers/KeriController.kt b/src/main/kotlin/id/walt/web/controllers/KeriController.kt index 8c7a708..13578e2 100644 --- a/src/main/kotlin/id/walt/web/controllers/KeriController.kt +++ b/src/main/kotlin/id/walt/web/controllers/KeriController.kt @@ -3,6 +3,7 @@ package id.walt.web.controllers import id.walt.service.dto.KeriCreateDbRequest import id.walt.service.dto.KeriCreateDbResponse import id.walt.service.dto.KeriInceptionRequest +import id.walt.service.dto.KeriInceptionResponse import id.walt.service.keri.KeriInceptionService import id.walt.service.keri.KeriInitService import io.github.smiley4.ktorswaggerui.dsl.post @@ -57,7 +58,32 @@ fun Application.keri() = walletRoute { } post("incept/{name}", { - summary = "Initialize a prefix" + summary = "Create an inception event to initiate a controller" + + request { + pathParameter("name") { + description = "keystore name and file location of KERI keystore" + example = "waltid" + } + + body { + description = "Required data for the inception of a controller" + example("application/json", KeriInceptionRequest(alias = "waltid-alias", passcode = "0123456789abcdefghijk")) + } + + } + response { + HttpStatusCode.Created to { + body { + description = "The identifiers of the controller. An AID, DID and public keys" + example("application/json", KeriInceptionResponse(aid = "EPjNBI4spoZ3lU5OCtNO4QgJmhIw7P1T-JOtwit36do4", did = "did:keri:EPjNBI4spoZ3lU5OCtNO4QgJmhIw7P1T-JOtwit36do4", publicKeys = listOf( + "DOERpUwwYCSyWH8e8yLJDKZpvEly_oJ8QJPw2wH3qRVQ" + ))) { + summary = "Example of creating an inception event (First event in a Key Event Log (KEL))" + } + } + } + } }) { val name = call.parameters["name"] ?: return@post call.respond(HttpStatusCode.BadRequest) val dto = call.receive() From 87ffc0f004e68b91a87277b4002f9192d06e9722 Mon Sep 17 00:00:00 2001 From: aminbenmansour Date: Thu, 26 Oct 2023 03:27:26 +0100 Subject: [PATCH 13/49] test(keri): ensuring the kli CLI (KERIpy) is installed --- .../kotlin/id/walt/service/TestKeriUtility.kt | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 src/test/kotlin/id/walt/service/TestKeriUtility.kt diff --git a/src/test/kotlin/id/walt/service/TestKeriUtility.kt b/src/test/kotlin/id/walt/service/TestKeriUtility.kt new file mode 100644 index 0000000..d2e96c3 --- /dev/null +++ b/src/test/kotlin/id/walt/service/TestKeriUtility.kt @@ -0,0 +1,23 @@ +package id.walt.service + + +import org.junit.Test +import kotlin.test.assertEquals + +class TestKeriUtility { + @Test + fun testKliVersionCommand() { + val command = "kli" + val exitCode = runShellCommand(command) + + assertEquals(0, exitCode, "Command '$command' should exit with code 0") + } + + private fun runShellCommand(command: String): Int { + val processBuilder = ProcessBuilder("/bin/bash", "-c", command) + val process = processBuilder.start() + + // Wait for the command to complete + return process.waitFor() + } +} \ No newline at end of file From b841fc59f1c9e3d776ddb660a2b720cacd76f251 Mon Sep 17 00:00:00 2001 From: aminbenmansour Date: Thu, 26 Oct 2023 03:35:00 +0100 Subject: [PATCH 14/49] ci(test): adding test step --- .github/workflows/build.yml | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 00ca09e..2d5bea8 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,4 +1,4 @@ -name: Build on every push +name: Build and Test on every push on: push: @@ -8,10 +8,9 @@ on: - '**' - '!main' - jobs: build: - name: "Build" + name: "Build and Test" runs-on: "ubuntu-latest" steps: - uses: actions/checkout@v3 @@ -44,3 +43,9 @@ jobs: uses: eskatos/gradle-command-action@v1.3.3 with: arguments: build --no-daemon + + # Add the test step below + - name: Running gradle test + uses: eskatos/gradle-command-action@v1.3.3 + with: + arguments: test --no-daemon From 02a9148e9c3c448632acb40eb9935d70e0dd3250 Mon Sep 17 00:00:00 2001 From: aminbenmansour Date: Fri, 27 Oct 2023 16:22:03 +0100 Subject: [PATCH 15/49] chore(acdc): vLEI schemas, credentials and data OOBIs caching script --- config/keri/acdc/credentials/.gitkeep | 0 config/keri/acdc/oobis/.gitkeep | 0 config/keri/acdc/schemas/.gitkeep | 0 config/keri/scripts/vlei.sh | 7 +++++++ 4 files changed, 7 insertions(+) create mode 100644 config/keri/acdc/credentials/.gitkeep create mode 100644 config/keri/acdc/oobis/.gitkeep create mode 100644 config/keri/acdc/schemas/.gitkeep create mode 100755 config/keri/scripts/vlei.sh diff --git a/config/keri/acdc/credentials/.gitkeep b/config/keri/acdc/credentials/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/config/keri/acdc/oobis/.gitkeep b/config/keri/acdc/oobis/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/config/keri/acdc/schemas/.gitkeep b/config/keri/acdc/schemas/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/config/keri/scripts/vlei.sh b/config/keri/scripts/vlei.sh new file mode 100755 index 0000000..a5a5532 --- /dev/null +++ b/config/keri/scripts/vlei.sh @@ -0,0 +1,7 @@ +#! /bin/bash + +# A vLEI server makes schemas, credentials and data OOBIs (added through durls field) discoverable by other entities + +CONFIG_DIR="config/keri/acdc" + +vLEI-server -p 7723 --schema-dir "${CONFIG_DIR}/schemas" --cred-dir "${CONFIG_DIR}/credentials" --oobi-dir "${CONFIG_DIR}/oobis" \ No newline at end of file From c34aaaad2e2f90f9b9bb242a565f3f3d1560f5b2 Mon Sep 17 00:00:00 2001 From: aminbenmansour Date: Sat, 28 Oct 2023 04:57:11 +0100 Subject: [PATCH 16/49] chore(keri): add vLEI dependency --- backend.Dockerfile | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/backend.Dockerfile b/backend.Dockerfile index a0f27de..503000f 100644 --- a/backend.Dockerfile +++ b/backend.Dockerfile @@ -34,6 +34,12 @@ RUN apt install pip -y && \ mkdir -p /usr/local/var/keri && \ pip install -e . +# vLEI spec leverage `did:keri` to make acdc schemas, credentials and OOBIs (through durls field) discoverable +WORKDIR /vLEI +RUN git clone -b dev https://github.com/WebOfTrust/vLEI.git . && \ + git checkout ed982313dab86bfada3825857601a10d71ce9631 && \ + pip install -e ./ + COPY --from=buildstage /work/build/install/ / WORKDIR /waltid-web-wallet From cf86e5c715a28dcddbda9acd9c225f682fd8e09d Mon Sep 17 00:00:00 2001 From: aminbenmansour Date: Mon, 30 Oct 2023 02:19:10 +0100 Subject: [PATCH 17/49] chore(acdc): a schema template and data requisites for a basic ACDC --- .../keri/acdc/credentials/attributes/.gitkeep | 0 .../credentials/attributes/parent-test.json | 3 + .../acdc/schemas/custom-parent-schema.json | 81 +++++++++++++++++++ 3 files changed, 84 insertions(+) create mode 100644 config/keri/acdc/credentials/attributes/.gitkeep create mode 100644 config/keri/acdc/credentials/attributes/parent-test.json create mode 100644 config/keri/acdc/schemas/custom-parent-schema.json diff --git a/config/keri/acdc/credentials/attributes/.gitkeep b/config/keri/acdc/credentials/attributes/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/config/keri/acdc/credentials/attributes/parent-test.json b/config/keri/acdc/credentials/attributes/parent-test.json new file mode 100644 index 0000000..b295d69 --- /dev/null +++ b/config/keri/acdc/credentials/attributes/parent-test.json @@ -0,0 +1,3 @@ +{ + "customAttribute": "test" +} \ No newline at end of file diff --git a/config/keri/acdc/schemas/custom-parent-schema.json b/config/keri/acdc/schemas/custom-parent-schema.json new file mode 100644 index 0000000..2629839 --- /dev/null +++ b/config/keri/acdc/schemas/custom-parent-schema.json @@ -0,0 +1,81 @@ +{ + "$id": "", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Custom Parent Credential", + "description": "A parent custom schema that have no dependencies. All attributes are under key 'a'", + "type": "object", + "credentialType": "CustomParentCredential", + "version": "1.0.0", + "properties": { + "v": { + "description": "Credential Version", + "type": "string" + }, + "d": { + "description": "Credential SAID", + "type": "string" + }, + "u": { + "description": "One time use nonce - optional", + "type": "string" + }, + "i": { + "description": "Issuer AID", + "type": "string" + }, + "ri": { + "description": "Credential Registry Identifier", + "type": "string" + }, + "s": { + "description": "Schema SAID", + "type": "string" + }, + "a": { + "oneOf": [ + { + "description": "Attributes block SAID", + "type": "string" + }, + { + "$id": "", + "description": "Attributes block", + "type": "object", + "properties": { + "d": { + "description": "Attributes block SAID", + "type": "string" + }, + "i": { + "description": "Issuee AID", + "type": "string" + }, + "dt": { + "description": "Issuance date time", + "type": "string", + "format": "date-time" + }, + "customAttribute": { + "description": "As d, i and dt are required properties, customAttribute is the one that we defined that actually make our ACDC unique. We can define multiple other attributes", + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "i", + "customAttribute" + ] + } + ] + } + }, + "additionalProperties": false, + "required": [ + "v", + "i", + "ri", + "s", + "d", + "a" + ] +} From a51694780826c265209eec2f90eccc80d378c573 Mon Sep 17 00:00:00 2001 From: aminbenmansour Date: Mon, 30 Oct 2023 02:20:26 +0100 Subject: [PATCH 18/49] chore(acdc): a schema template with edges and rules --- .../credentials/attributes/child-test.json | 6 + config/keri/acdc/credentials/edges/.gitkeep | 0 .../acdc/credentials/edges/child-edge.json | 1 + config/keri/acdc/credentials/rules/.gitkeep | 0 .../acdc/credentials/rules/child-rule.json | 1 + ...stom-child-schema-wth-edges-and-rules.json | 176 ++++++++++++++++++ 6 files changed, 184 insertions(+) create mode 100644 config/keri/acdc/credentials/attributes/child-test.json create mode 100644 config/keri/acdc/credentials/edges/.gitkeep create mode 100644 config/keri/acdc/credentials/edges/child-edge.json create mode 100644 config/keri/acdc/credentials/rules/.gitkeep create mode 100644 config/keri/acdc/credentials/rules/child-rule.json create mode 100644 config/keri/acdc/schemas/custom-child-schema-wth-edges-and-rules.json diff --git a/config/keri/acdc/credentials/attributes/child-test.json b/config/keri/acdc/credentials/attributes/child-test.json new file mode 100644 index 0000000..4437587 --- /dev/null +++ b/config/keri/acdc/credentials/attributes/child-test.json @@ -0,0 +1,6 @@ +{ + "requester": { + "customObjectAttribute": "Test" + }, + "customAttribute": 2 +} diff --git a/config/keri/acdc/credentials/edges/.gitkeep b/config/keri/acdc/credentials/edges/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/config/keri/acdc/credentials/edges/child-edge.json b/config/keri/acdc/credentials/edges/child-edge.json new file mode 100644 index 0000000..9cb3df6 --- /dev/null +++ b/config/keri/acdc/credentials/edges/child-edge.json @@ -0,0 +1 @@ +{"d": "", "requester": {"n": "", "s": ""}} \ No newline at end of file diff --git a/config/keri/acdc/credentials/rules/.gitkeep b/config/keri/acdc/credentials/rules/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/config/keri/acdc/credentials/rules/child-rule.json b/config/keri/acdc/credentials/rules/child-rule.json new file mode 100644 index 0000000..bef3884 --- /dev/null +++ b/config/keri/acdc/credentials/rules/child-rule.json @@ -0,0 +1 @@ +{"d": "", "privacyDisclaimer": {"l": "It is the sole responsibility of Holders of a CustomChildCredential to present that credential in a privacy-preserving manner using the mechanisms provided in the Issuance and Presentation Exchange (IPEX) protocol specification and the Authentic Chained Data Container (ACDC) specification. https://github.com/WebOfTrust/IETF-IPEX and https://github.com/trustoverip/tswg-acdc-specification."}} \ No newline at end of file diff --git a/config/keri/acdc/schemas/custom-child-schema-wth-edges-and-rules.json b/config/keri/acdc/schemas/custom-child-schema-wth-edges-and-rules.json new file mode 100644 index 0000000..ce594f3 --- /dev/null +++ b/config/keri/acdc/schemas/custom-child-schema-wth-edges-and-rules.json @@ -0,0 +1,176 @@ +{ + "$id": "", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Custom Child Credential", + "description": "A child custom schema means that it will have dependencies to the parent schema. It will also include rules to act as a Ricardian Contract", + "type": "object", + "credentialType": "CustomChildCredential", + "version": "1.0.0", + "properties": { + "v": { + "description": "Credential Version", + "type": "string" + }, + "d": { + "description": "Credential SAID", + "type": "string" + }, + "u": { + "description": "One time use nonce - optional", + "type": "string" + }, + "i": { + "description": "Issuer AID", + "type": "string" + }, + "ri": { + "description": "Credential Registry Identifier", + "type": "string" + }, + "s": { + "description": "Schema SAID", + "type": "string" + }, + "a": { + "oneOf": [ + { + "description": "Attributes block SAID", + "type": "string" + }, + { + "$id": "", + "description": "Attributes block", + "type": "object", + "properties": { + "d": { + "description": "Attributes block SAID", + "type": "string" + }, + "i": { + "description": "Issuee AID", + "type": "string" + }, + "dt": { + "description": "Issuance date time", + "type": "string", + "format": "date-time" + }, + "requester": { + "description": "Defining tightly related attributes together in one object. This is helpful for SD and enhances IPEX protocol interactions depending on the use case!", + "type": "object", + "properties": { + "customObjectAttribute": { + "description": "First custom attribute, it usually comes with", + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "customObjectAttribute" + ] + }, + "customAttribute": { + "customAttribute": "A custom attribute like we defined earlier", + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "i", + "requester", + "customAttribute" + ] + } + ] + }, + "e": { + "oneOf": [ + { + "description": "Edges block SAID", + "type": "string" + }, + { + "$id": "", + "description": "Edges block", + "type": "object", + "properties": { + "d": { + "description": "Edges block SAID", + "type": "string" + }, + "exampleEdge": { + "description": "The custom parent schema which the authorizer is responding to.", + "type": "object", + "properties": { + "n": { + "description": "SAID of the CustomParentCredential ACDC", + "type": "string" + }, + "s": { + "description": "SAID of CustomParentCredential ACDC schema", + "type": "string", + "const": "" + } + }, + "additionalProperties": false, + "required": [ + "n", + "s" + ] + } + }, + "additionalProperties": false, + "required": [ + "d", + "exampleEdge" + ] + } + ] + }, + "r": { + "oneOf": [ + { + "description": "Rules block SAID", + "type": "string" + }, + { + "$id": "", + "description": "Rules block", + "type": "object", + "properties": { + "d": { + "description": "Rules block SAID", + "type": "string" + }, + "privacyDisclaimer": { + "description": "Privacy Disclaimer", + "type": "object", + "properties": { + "l": { + "description": "Associated legal language", + "type": "string", + "const": "It is the sole responsibility of Holders of a CustomChildCredential to present that credential in a privacy-preserving manner using the mechanisms provided in the Issuance and Presentation Exchange (IPEX) protocol specification and the Authentic Chained Data Container (ACDC) specification. https://github.com/WebOfTrust/IETF-IPEX and https://github.com/trustoverip/tswg-acdc-specification." + } + } + } + }, + "additionalProperties": false, + "required": [ + "d", + "privacyDisclaimer" + ] + } + ] + } + }, + "additionalProperties": false, + "required": [ + "v", + "i", + "ri", + "s", + "d", + "a", + "e" + ] +} From 19f846d2a2a92015e095fdf3ce00b5433d069cef Mon Sep 17 00:00:00 2001 From: aminbenmansour Date: Mon, 30 Oct 2023 03:32:47 +0100 Subject: [PATCH 19/49] refact(vlei): changing file structure of acdc schemas --- config/keri/acdc/{ => cache}/credentials/.gitkeep | 0 .../acdc/{credentials/attributes => cache/oobis}/.gitkeep | 0 config/keri/acdc/{credentials/edges => data}/.gitkeep | 0 .../keri/acdc/{credentials/rules => data/attributes}/.gitkeep | 0 .../acdc/{credentials => data}/attributes/child-test.json | 0 .../acdc/{credentials => data}/attributes/parent-test.json | 0 config/keri/acdc/{oobis => data/edges}/.gitkeep | 0 config/keri/acdc/{credentials => data}/edges/child-edge.json | 0 config/keri/acdc/data/rules/.gitkeep | 0 config/keri/acdc/{credentials => data}/rules/child-rule.json | 0 config/keri/scripts/vlei.sh | 3 ++- src/test/kotlin/config/keri/acdc/vlei/ServerTestvLEI.kt | 4 ++++ 12 files changed, 6 insertions(+), 1 deletion(-) rename config/keri/acdc/{ => cache}/credentials/.gitkeep (100%) rename config/keri/acdc/{credentials/attributes => cache/oobis}/.gitkeep (100%) rename config/keri/acdc/{credentials/edges => data}/.gitkeep (100%) rename config/keri/acdc/{credentials/rules => data/attributes}/.gitkeep (100%) rename config/keri/acdc/{credentials => data}/attributes/child-test.json (100%) rename config/keri/acdc/{credentials => data}/attributes/parent-test.json (100%) rename config/keri/acdc/{oobis => data/edges}/.gitkeep (100%) rename config/keri/acdc/{credentials => data}/edges/child-edge.json (100%) create mode 100644 config/keri/acdc/data/rules/.gitkeep rename config/keri/acdc/{credentials => data}/rules/child-rule.json (100%) create mode 100644 src/test/kotlin/config/keri/acdc/vlei/ServerTestvLEI.kt diff --git a/config/keri/acdc/credentials/.gitkeep b/config/keri/acdc/cache/credentials/.gitkeep similarity index 100% rename from config/keri/acdc/credentials/.gitkeep rename to config/keri/acdc/cache/credentials/.gitkeep diff --git a/config/keri/acdc/credentials/attributes/.gitkeep b/config/keri/acdc/cache/oobis/.gitkeep similarity index 100% rename from config/keri/acdc/credentials/attributes/.gitkeep rename to config/keri/acdc/cache/oobis/.gitkeep diff --git a/config/keri/acdc/credentials/edges/.gitkeep b/config/keri/acdc/data/.gitkeep similarity index 100% rename from config/keri/acdc/credentials/edges/.gitkeep rename to config/keri/acdc/data/.gitkeep diff --git a/config/keri/acdc/credentials/rules/.gitkeep b/config/keri/acdc/data/attributes/.gitkeep similarity index 100% rename from config/keri/acdc/credentials/rules/.gitkeep rename to config/keri/acdc/data/attributes/.gitkeep diff --git a/config/keri/acdc/credentials/attributes/child-test.json b/config/keri/acdc/data/attributes/child-test.json similarity index 100% rename from config/keri/acdc/credentials/attributes/child-test.json rename to config/keri/acdc/data/attributes/child-test.json diff --git a/config/keri/acdc/credentials/attributes/parent-test.json b/config/keri/acdc/data/attributes/parent-test.json similarity index 100% rename from config/keri/acdc/credentials/attributes/parent-test.json rename to config/keri/acdc/data/attributes/parent-test.json diff --git a/config/keri/acdc/oobis/.gitkeep b/config/keri/acdc/data/edges/.gitkeep similarity index 100% rename from config/keri/acdc/oobis/.gitkeep rename to config/keri/acdc/data/edges/.gitkeep diff --git a/config/keri/acdc/credentials/edges/child-edge.json b/config/keri/acdc/data/edges/child-edge.json similarity index 100% rename from config/keri/acdc/credentials/edges/child-edge.json rename to config/keri/acdc/data/edges/child-edge.json diff --git a/config/keri/acdc/data/rules/.gitkeep b/config/keri/acdc/data/rules/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/config/keri/acdc/credentials/rules/child-rule.json b/config/keri/acdc/data/rules/child-rule.json similarity index 100% rename from config/keri/acdc/credentials/rules/child-rule.json rename to config/keri/acdc/data/rules/child-rule.json diff --git a/config/keri/scripts/vlei.sh b/config/keri/scripts/vlei.sh index a5a5532..76b53de 100755 --- a/config/keri/scripts/vlei.sh +++ b/config/keri/scripts/vlei.sh @@ -1,7 +1,8 @@ #! /bin/bash # A vLEI server makes schemas, credentials and data OOBIs (added through durls field) discoverable by other entities +# Caveat: This script should be run from the root directory CONFIG_DIR="config/keri/acdc" -vLEI-server -p 7723 --schema-dir "${CONFIG_DIR}/schemas" --cred-dir "${CONFIG_DIR}/credentials" --oobi-dir "${CONFIG_DIR}/oobis" \ No newline at end of file +vLEI-server -p 7723 --schema-dir "${CONFIG_DIR}/schemas/saidified" --cred-dir "${CONFIG_DIR}/cache/credentials" --oobi-dir "${CONFIG_DIR}/cache/oobis" \ No newline at end of file diff --git a/src/test/kotlin/config/keri/acdc/vlei/ServerTestvLEI.kt b/src/test/kotlin/config/keri/acdc/vlei/ServerTestvLEI.kt new file mode 100644 index 0000000..4d40889 --- /dev/null +++ b/src/test/kotlin/config/keri/acdc/vlei/ServerTestvLEI.kt @@ -0,0 +1,4 @@ +package config.keri.acdc.vlei + +class ServerTestvLEI { +} \ No newline at end of file From 3d853457db407ac5ba6e2c3a2e5d96cabe0396f9 Mon Sep 17 00:00:00 2001 From: aminbenmansour Date: Mon, 30 Oct 2023 03:39:52 +0100 Subject: [PATCH 20/49] test(vlei): testing if the vlei server is up and running Caveat: This should be automated when deployed, changing localhost to actual host value --- build.gradle.kts | 3 ++ .../config/keri/acdc/vlei/ServerTestvLEI.kt | 29 +++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/build.gradle.kts b/build.gradle.kts index 858c82f..80c647a 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -40,6 +40,7 @@ dependencies { exclude("com.sksamuel.hoplite", "hoplite-yaml") exclude("com.sksamuel.hoplite", "hoplite-hikaricp") } + testImplementation("org.junit.jupiter:junit-jupiter:5.8.1") /* -- KTOR -- */ @@ -137,6 +138,8 @@ dependencies { testImplementation("io.kotest:kotest-assertions-core:5.5.5") testImplementation("io.kotest.extensions:kotest-assertions-ktor:2.0.0")*/ testImplementation("io.ktor:ktor-server-tests-jvm:$ktorVersion") + testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.7.2") + testImplementation("org.junit.jupiter:junit-jupiter:5.9.2") // Logging implementation("io.github.oshai:kotlin-logging:5.1.0") diff --git a/src/test/kotlin/config/keri/acdc/vlei/ServerTestvLEI.kt b/src/test/kotlin/config/keri/acdc/vlei/ServerTestvLEI.kt index 4d40889..05e3719 100644 --- a/src/test/kotlin/config/keri/acdc/vlei/ServerTestvLEI.kt +++ b/src/test/kotlin/config/keri/acdc/vlei/ServerTestvLEI.kt @@ -1,4 +1,33 @@ package config.keri.acdc.vlei +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.async +import kotlinx.coroutines.runBlocking +import kotlin.test.assertTrue +import java.net.InetSocketAddress +import java.net.Socket +import org.junit.Test class ServerTestvLEI { + @Test + fun testServerAvailability() = runBlocking { + val host = "localhost" + val port = 7723 + + val serverAvailable = async(Dispatchers.IO) { + isServerAvailable(host, port) + } + + assertTrue(serverAvailable.await(), "The server on $host:$port is not available.") + } + + private fun isServerAvailable(host: String, port: Int): Boolean { + return try { + Socket().use { socket -> + socket.connect(InetSocketAddress(host, port), 2000) + true + } + } catch (e: Exception) { + false + } + } } \ No newline at end of file From 33870f832d4fd4b8b822f535d6e042f85f93fb0d Mon Sep 17 00:00:00 2001 From: aminbenmansour Date: Mon, 30 Oct 2023 10:40:41 +0100 Subject: [PATCH 21/49] fix(vlei): applying file structure changes previously mentioned in vlei bash shell script --- config/keri/acdc/schemas/{ => raw}/.gitkeep | 0 .../{ => raw}/custom-child-schema-wth-edges-and-rules.json | 0 config/keri/acdc/schemas/{ => raw}/custom-parent-schema.json | 0 config/keri/acdc/schemas/saidified/.gitkeep | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename config/keri/acdc/schemas/{ => raw}/.gitkeep (100%) rename config/keri/acdc/schemas/{ => raw}/custom-child-schema-wth-edges-and-rules.json (100%) rename config/keri/acdc/schemas/{ => raw}/custom-parent-schema.json (100%) create mode 100644 config/keri/acdc/schemas/saidified/.gitkeep diff --git a/config/keri/acdc/schemas/.gitkeep b/config/keri/acdc/schemas/raw/.gitkeep similarity index 100% rename from config/keri/acdc/schemas/.gitkeep rename to config/keri/acdc/schemas/raw/.gitkeep diff --git a/config/keri/acdc/schemas/custom-child-schema-wth-edges-and-rules.json b/config/keri/acdc/schemas/raw/custom-child-schema-wth-edges-and-rules.json similarity index 100% rename from config/keri/acdc/schemas/custom-child-schema-wth-edges-and-rules.json rename to config/keri/acdc/schemas/raw/custom-child-schema-wth-edges-and-rules.json diff --git a/config/keri/acdc/schemas/custom-parent-schema.json b/config/keri/acdc/schemas/raw/custom-parent-schema.json similarity index 100% rename from config/keri/acdc/schemas/custom-parent-schema.json rename to config/keri/acdc/schemas/raw/custom-parent-schema.json diff --git a/config/keri/acdc/schemas/saidified/.gitkeep b/config/keri/acdc/schemas/saidified/.gitkeep new file mode 100644 index 0000000..e69de29 From eed9e23de15ce75534b69401e5dd1fd1de7f50a9 Mon Sep 17 00:00:00 2001 From: aminbenmansour Date: Mon, 30 Oct 2023 10:43:25 +0100 Subject: [PATCH 22/49] feat(acdc): add section for managing credentials --- build.gradle.kts | 1 + src/main/kotlin/id/walt/Application.kt | 1 + 2 files changed, 2 insertions(+) diff --git a/build.gradle.kts b/build.gradle.kts index 80c647a..03285e8 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -79,6 +79,7 @@ dependencies { // Kotlinx.serialization implementation("io.ktor:ktor-serialization-kotlinx-json:$ktorVersion") + implementation("com.google.code.gson:gson:2.10.1") // Date implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.4.1") diff --git a/src/main/kotlin/id/walt/Application.kt b/src/main/kotlin/id/walt/Application.kt index 9ea76ca..29721d0 100644 --- a/src/main/kotlin/id/walt/Application.kt +++ b/src/main/kotlin/id/walt/Application.kt @@ -71,4 +71,5 @@ fun Application.module() { nfts() keri() + acdc() } From 46af64e3215ef36245497d9df8554baca3b9c9bd Mon Sep 17 00:00:00 2001 From: aminbenmansour Date: Mon, 30 Oct 2023 10:44:46 +0100 Subject: [PATCH 23/49] feat(acdc): implement SAID spec --- .../service/dto/AcdcManagemementObjects.kt | 14 ++++ .../walt/service/keri/AcdcSaidifyService.kt | 74 +++++++++++++++++++ .../keri/interfaces/AcdcSaidifyInterface.kt | 7 ++ .../id/walt/web/controllers/AcdcController.kt | 34 +++++++++ 4 files changed, 129 insertions(+) create mode 100644 src/main/kotlin/id/walt/service/dto/AcdcManagemementObjects.kt create mode 100644 src/main/kotlin/id/walt/service/keri/AcdcSaidifyService.kt create mode 100644 src/main/kotlin/id/walt/service/keri/interfaces/AcdcSaidifyInterface.kt create mode 100644 src/main/kotlin/id/walt/web/controllers/AcdcController.kt diff --git a/src/main/kotlin/id/walt/service/dto/AcdcManagemementObjects.kt b/src/main/kotlin/id/walt/service/dto/AcdcManagemementObjects.kt new file mode 100644 index 0000000..4deb822 --- /dev/null +++ b/src/main/kotlin/id/walt/service/dto/AcdcManagemementObjects.kt @@ -0,0 +1,14 @@ +package id.walt.service.dto + +import kotlinx.serialization.Serializable + +@Serializable +data class AcdcSaidifyRequest ( + val filename: String +) + +@Serializable +data class AcdcSaidifyResponse ( + val said: String, + val file: String +) \ No newline at end of file diff --git a/src/main/kotlin/id/walt/service/keri/AcdcSaidifyService.kt b/src/main/kotlin/id/walt/service/keri/AcdcSaidifyService.kt new file mode 100644 index 0000000..61a7330 --- /dev/null +++ b/src/main/kotlin/id/walt/service/keri/AcdcSaidifyService.kt @@ -0,0 +1,74 @@ +package id.walt.service.keri + +import id.walt.service.dto.AcdcSaidifyResponse +import id.walt.service.keri.interfaces.AcdcSaidifyInterface +import java.io.BufferedReader +import java.io.IOException +import java.io.InputStreamReader +import java.io.File + +class AcdcSaidifyService: AcdcSaidifyInterface { + override fun saidify(file: String): AcdcSaidifyResponse { + var said = ""; + var content = "" + + val command: List = listOf( + "kli", "saidify", + "--file", file + ) + + try { + val processBuilder = ProcessBuilder(command) + val process = processBuilder.start() + + val errorReader = BufferedReader(InputStreamReader(process.errorStream)) + var errorLine: String? + while (errorReader.readLine().also { errorLine = it } != null) { + System.err.println(errorLine) + } + + process.waitFor() + + content = readFileContent(file) + said = extractSAID(file)!! + println("####################") + println(said) + println("####################") + + } catch(e: IOException) { + e.printStackTrace() + } catch (e: InterruptedException) { + e.printStackTrace() + } + return AcdcSaidifyResponse(said=said, file=content) + } + + private fun readFileContent(fileName: String): String { + try { + val file = File(fileName) + if (file.exists()) { + return file.readText() + } + } catch (e: Exception) { + e.printStackTrace() + } + return "" + } + + private fun extractSAID(fileName: String): String? { + val pattern = "\"d\":\\s*\"([^\"]+)\"".toRegex() + try { + val file = File(fileName) + if (file.exists()) { + val fileContent = file.readText() + val matchResult = pattern.find(fileContent) + + return matchResult?.groupValues?.getOrNull(1) + + } + } catch (e: Exception) { + e.printStackTrace() + } + return null + } +} \ No newline at end of file diff --git a/src/main/kotlin/id/walt/service/keri/interfaces/AcdcSaidifyInterface.kt b/src/main/kotlin/id/walt/service/keri/interfaces/AcdcSaidifyInterface.kt new file mode 100644 index 0000000..dd858a1 --- /dev/null +++ b/src/main/kotlin/id/walt/service/keri/interfaces/AcdcSaidifyInterface.kt @@ -0,0 +1,7 @@ +package id.walt.service.keri.interfaces + +import id.walt.service.dto.AcdcSaidifyResponse + +interface AcdcSaidifyInterface { + fun saidify(file: String): AcdcSaidifyResponse; +} \ No newline at end of file diff --git a/src/main/kotlin/id/walt/web/controllers/AcdcController.kt b/src/main/kotlin/id/walt/web/controllers/AcdcController.kt new file mode 100644 index 0000000..4ee4936 --- /dev/null +++ b/src/main/kotlin/id/walt/web/controllers/AcdcController.kt @@ -0,0 +1,34 @@ +package id.walt.web.controllers + +import id.walt.service.dto.* +import id.walt.service.keri.AcdcSaidifyService +import io.github.smiley4.ktorswaggerui.dsl.post +import io.github.smiley4.ktorswaggerui.dsl.route +import io.ktor.http.* +import io.ktor.server.application.* +import io.ktor.server.request.* +import io.ktor.server.response.* + +fun Application.acdc() = walletRoute { + route("acdc", { + tags = listOf("Authentic Chain Data Containers (ACDC) Management") + }) { + + + post("saidify", { + summary = "Populate file with Self-Addressing IDentifier (SAID)" + }) { + val dto = call.receive() + val response = AcdcSaidifyService().saidify(dto.filename) + + if (response.said == "") { + call.respond(HttpStatusCode.InternalServerError) + } else { + call.respond(HttpStatusCode.Created, response) + } + + + } + + } +} \ No newline at end of file From f151696b5baf90ca7a70608ce85564678c192107 Mon Sep 17 00:00:00 2001 From: aminbenmansour Date: Mon, 30 Oct 2023 10:52:01 +0100 Subject: [PATCH 24/49] doc(said): openapi documentation for said request/response --- .../id/walt/web/controllers/AcdcController.kt | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/id/walt/web/controllers/AcdcController.kt b/src/main/kotlin/id/walt/web/controllers/AcdcController.kt index 4ee4936..9d51ccb 100644 --- a/src/main/kotlin/id/walt/web/controllers/AcdcController.kt +++ b/src/main/kotlin/id/walt/web/controllers/AcdcController.kt @@ -13,10 +13,29 @@ fun Application.acdc() = walletRoute { route("acdc", { tags = listOf("Authentic Chain Data Containers (ACDC) Management") }) { - - post("saidify", { summary = "Populate file with Self-Addressing IDentifier (SAID)" + + request { + body { + description = "File name, type the full file location and name with extension" + } + } + + response { + HttpStatusCode.Created to { + body { + description = "The SAID and a fully saidified file" + example("application/json", AcdcSaidifyResponse(said = "EFLhmGcItk9WPXWvdV_X9XtGwfg4IJR4TLUSTHXMgWhi", file= "\"{\\\"d\\\": " + + "\\\"EFLhmGcItk9WPXWvdV_X9XtGwfg4IJR4TLUSTHXMgWhi\\\", \\\"privacyDisclaimer\\\": {\\\"l\\\": \\\"It is the sole responsibility " + + "of Holders of a CustomChildCredential to present that credential in a privacy-preserving manner using the mechanisms " + + "provided in the Issuance and Presentation Exchange (IPEX) protocol specification and the Authentic Chained Data " + + "Container (ACDC) specification. https://github.com/WebOfTrust/IETF-IPEX and https://github.com/trustoverip/tswg-acdc-specification.\\\"}}\"")) { + summary = "Example of a Saidifying a file" + } + } + } + } }) { val dto = call.receive() val response = AcdcSaidifyService().saidify(dto.filename) From 7bebd31781050d8ea6f73a402380120b17c66786 Mon Sep 17 00:00:00 2001 From: aminbenmansour Date: Tue, 31 Oct 2023 06:51:43 +0100 Subject: [PATCH 25/49] docs(registry): openapi docs for request and response --- .../id/walt/config/DatabaseConfiguration.kt | 2 +- .../service/dto/KeriUserManagementObjects.kt | 4 ++ .../walt/service/keri/KeriRegistryService.kt | 51 ++++++++++++++++++ .../keri/interfaces/KeriRegistryInterface.kt | 7 +++ .../id/walt/web/controllers/KeriController.kt | 53 ++++++++++++++++--- 5 files changed, 110 insertions(+), 7 deletions(-) create mode 100644 src/main/kotlin/id/walt/service/keri/KeriRegistryService.kt create mode 100644 src/main/kotlin/id/walt/service/keri/interfaces/KeriRegistryInterface.kt diff --git a/src/main/kotlin/id/walt/config/DatabaseConfiguration.kt b/src/main/kotlin/id/walt/config/DatabaseConfiguration.kt index 3eca5b3..59bec49 100644 --- a/src/main/kotlin/id/walt/config/DatabaseConfiguration.kt +++ b/src/main/kotlin/id/walt/config/DatabaseConfiguration.kt @@ -4,7 +4,7 @@ import com.zaxxer.hikari.HikariDataSource data class DatabaseConfiguration( val database: String, - val recreate_schema: Boolean = false + val recreate_schema: Boolean = true ) : WalletConfig data class DatasourceConfiguration( diff --git a/src/main/kotlin/id/walt/service/dto/KeriUserManagementObjects.kt b/src/main/kotlin/id/walt/service/dto/KeriUserManagementObjects.kt index f56566d..52a0c15 100644 --- a/src/main/kotlin/id/walt/service/dto/KeriUserManagementObjects.kt +++ b/src/main/kotlin/id/walt/service/dto/KeriUserManagementObjects.kt @@ -24,3 +24,7 @@ data class KeriInceptionResponse ( val did: String, val publicKeys: List ) +@Serializable +data class KeriRegistryInceptionResponse ( + val scid: String +) diff --git a/src/main/kotlin/id/walt/service/keri/KeriRegistryService.kt b/src/main/kotlin/id/walt/service/keri/KeriRegistryService.kt new file mode 100644 index 0000000..13c49ee --- /dev/null +++ b/src/main/kotlin/id/walt/service/keri/KeriRegistryService.kt @@ -0,0 +1,51 @@ +package id.walt.service.keri + +import id.walt.service.dto.KeriRegistryInceptionResponse +import id.walt.service.keri.interfaces.KeriRegistryInterface +import java.io.BufferedReader +import java.io.IOException +import java.io.InputStreamReader + +class KeriRegistryService: KeriRegistryInterface { + override fun incept(keystore: String, alias: String, registry: String, passcode: String): KeriRegistryInceptionResponse { + var scid = "" + + val command: List = listOf( + "kli", "vc", + "registry", "incept", + "--name", keystore, + "--alias", alias, + "--registry-name", registry, + "--passcode", passcode + ) + + try { + val processBuilder = ProcessBuilder(command) + val process = processBuilder.start() + + val reader = BufferedReader(InputStreamReader(process.inputStream)) + var line: String? + + while (reader.readLine().also { line = it } != null) { + if(line!!.startsWith("Registry: ")) { + val index: Int = line!!.indexOf('(') + scid = line!!.substring(index + 1, line!!.length - 2) + } + } + + val errorReader = BufferedReader(InputStreamReader(process.errorStream)) + var errorLine: String? + while (errorReader.readLine().also { errorLine = it } != null) { + System.err.println(errorLine) + } + process.waitFor() + + } catch(e: IOException) { + e.printStackTrace() + } catch (e: InterruptedException) { + e.printStackTrace() + } + + return KeriRegistryInceptionResponse(scid) + } +} \ No newline at end of file diff --git a/src/main/kotlin/id/walt/service/keri/interfaces/KeriRegistryInterface.kt b/src/main/kotlin/id/walt/service/keri/interfaces/KeriRegistryInterface.kt new file mode 100644 index 0000000..426ef1c --- /dev/null +++ b/src/main/kotlin/id/walt/service/keri/interfaces/KeriRegistryInterface.kt @@ -0,0 +1,7 @@ +package id.walt.service.keri.interfaces + +import id.walt.service.dto.KeriRegistryInceptionResponse + +interface KeriRegistryInterface { + fun incept(keystore: String, alias: String, registry: String, passcode: String): KeriRegistryInceptionResponse; +} \ No newline at end of file diff --git a/src/main/kotlin/id/walt/web/controllers/KeriController.kt b/src/main/kotlin/id/walt/web/controllers/KeriController.kt index 13578e2..b7dc76d 100644 --- a/src/main/kotlin/id/walt/web/controllers/KeriController.kt +++ b/src/main/kotlin/id/walt/web/controllers/KeriController.kt @@ -1,11 +1,9 @@ package id.walt.web.controllers -import id.walt.service.dto.KeriCreateDbRequest -import id.walt.service.dto.KeriCreateDbResponse -import id.walt.service.dto.KeriInceptionRequest -import id.walt.service.dto.KeriInceptionResponse +import id.walt.service.dto.* import id.walt.service.keri.KeriInceptionService import id.walt.service.keri.KeriInitService +import id.walt.service.keri.KeriRegistryService import io.github.smiley4.ktorswaggerui.dsl.post import io.github.smiley4.ktorswaggerui.dsl.route import io.ktor.http.* @@ -89,11 +87,54 @@ fun Application.keri() = walletRoute { val dto = call.receive() val response = KeriInceptionService().inceptController(name, dto.alias, dto.passcode) - call.respond(HttpStatusCode.Created, response) + } + post("keystore/{keystore}/alias/{alias}/registry/{registry}", { + summary = "Create a registry to manage credentials" - } + request { + pathParameter("keystore") { + description = "keystore name and file location of KERI keystore" + example = "waltid" + } + + pathParameter("alias") { + description = "human readable alias for the AID" + example = "waltid-alias" + } + + pathParameter("registry") { + description = "name of the registry that handles the Transaction Event Logs (TEL) to handle ACDC credentials" + example = "waltid-registry" + } + + body { + description = "Required data for the inception of a controller" + example("application/json", KeriCreateDbRequest(passcode = "0123456789abcdefghijk")) + } + } + response { + HttpStatusCode.Created to { + body { + description = "The Self-Certifying IDentifier (SCID) of the registry" + example("application/json", KeriRegistryInceptionResponse(scid = "ECoM0vzkc9sWvKdr08bLlHH2d_pik-ZCbSNzQRd2RoBU" + )) { + summary = "Example of creating an inception of a Registry in KERI" + } + } + } + } + }) { + val keystore = call.parameters["keystore"] ?: return@post call.respond(HttpStatusCode.BadRequest) + val alias = call.parameters["alias"] ?: return@post call.respond(HttpStatusCode.BadRequest) + val registry = call.parameters["registry"] ?: return@post call.respond(HttpStatusCode.BadRequest) + + val dto = call.receive() + val response = KeriRegistryService().incept(keystore, alias, registry, dto.passcode) + + call.respond(HttpStatusCode.Created, response) + } } } \ No newline at end of file From be97c1a5e692ea9172630d3541db27993b80c4c3 Mon Sep 17 00:00:00 2001 From: aminbenmansour Date: Tue, 31 Oct 2023 07:16:16 +0100 Subject: [PATCH 26/49] fix(config): return to default --- src/main/kotlin/id/walt/config/DatabaseConfiguration.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/id/walt/config/DatabaseConfiguration.kt b/src/main/kotlin/id/walt/config/DatabaseConfiguration.kt index 59bec49..3eca5b3 100644 --- a/src/main/kotlin/id/walt/config/DatabaseConfiguration.kt +++ b/src/main/kotlin/id/walt/config/DatabaseConfiguration.kt @@ -4,7 +4,7 @@ import com.zaxxer.hikari.HikariDataSource data class DatabaseConfiguration( val database: String, - val recreate_schema: Boolean = true + val recreate_schema: Boolean = false ) : WalletConfig data class DatasourceConfiguration( From 3ccd1960deeb53130a1f3202004f84458a3d94f1 Mon Sep 17 00:00:00 2001 From: aminbenmansour Date: Tue, 31 Oct 2023 15:44:23 +0100 Subject: [PATCH 27/49] feat(ipex): define interface containing all methods --- .../service/dto/AcdcManagemementObjects.kt | 15 ++++- .../service/keri/interfaces/IpexInterface.kt | 59 +++++++++++++++++++ 2 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 src/main/kotlin/id/walt/service/keri/interfaces/IpexInterface.kt diff --git a/src/main/kotlin/id/walt/service/dto/AcdcManagemementObjects.kt b/src/main/kotlin/id/walt/service/dto/AcdcManagemementObjects.kt index 4deb822..a90524f 100644 --- a/src/main/kotlin/id/walt/service/dto/AcdcManagemementObjects.kt +++ b/src/main/kotlin/id/walt/service/dto/AcdcManagemementObjects.kt @@ -11,4 +11,17 @@ data class AcdcSaidifyRequest ( data class AcdcSaidifyResponse ( val said: String, val file: String -) \ No newline at end of file +) + +@Serializable +data class IpexSaid ( + val said: String +) + +enum class IPEX_EVENT(val type: String) { + APPLY("apply"), + OFFER("offer"), + AGREE("agree"), + GRANT("grant"), + SUBMIT("submit") +} \ No newline at end of file diff --git a/src/main/kotlin/id/walt/service/keri/interfaces/IpexInterface.kt b/src/main/kotlin/id/walt/service/keri/interfaces/IpexInterface.kt new file mode 100644 index 0000000..93dd33e --- /dev/null +++ b/src/main/kotlin/id/walt/service/keri/interfaces/IpexInterface.kt @@ -0,0 +1,59 @@ +package id.walt.service.keri.interfaces + +import id.walt.service.dto.IPEX_EVENT +import id.walt.service.dto.IpexSaid + +/** + * IPEX protocol is a protocol for the issuance and presentation of ACDCs + * that enable contractually protected disclosure. A discloser of an ACDC + * may initially disclose the content of the ACDC partially or selectively + * and may reveal more content after the disclosee agrees to contractual terms. + * + * + * The Workflow of IPEX is the following: + * Step 1: Apply [Disclosee] + * Step 2A: Spurn [Discloser] + * Step 2B: Offer [Discloser] + * Step 3A: Spurn [Disclosee] + * Step 3B: Agree [Disclosee] + * Step 4A: Spurn [Discloser] + * Step 4B: Grant [Discloser] + * Step 5: Admit [Disclosee] + */ +interface IpexInterface { + /** + * Accept a credential being issued or presented in response to an IPEX grant + */ + fun admit(keystore: String, alias: String, passcode: String, said: String, message: String?); + + /** + * Reply to IPEX offer message acknowledged willingness to accept offered credential + */ + fun agree(): IpexSaid; + + /** + * Request a credential from another party by initiating an IPEX exchange + */ + fun apply(): IpexSaid; + + /** + * Reply to IPEX agree message or initiate an IPEX exchange with a credential issuance or presentation + */ + fun grant(keystore: String, alias: String, passcode: String, said: String, recipient: String, message: String?); + + /** + * List notifications related to IPEX protocol messages + */ + fun list(keystore: String, alias: String, passcode: String, type: IPEX_EVENT, verbose: Boolean, poll: Boolean, sent: Boolean); + + /** + * Reply to IPEX apply message or initiate an IPEX exchange with an offer for a credential with certain characteristics + */ + fun offer(): IpexSaid; + + /** + * Reject an IPEX apply, offer, agree or grant message + */ + fun spurn(keystore: String, alias: String, passcode: String, said: String, message: String?); +} + From 061b63e4b6f83928216151a6b36443b61b89ca54 Mon Sep 17 00:00:00 2001 From: aminbenmansour Date: Tue, 31 Oct 2023 18:30:55 +0100 Subject: [PATCH 28/49] feat(apex): add apply, offer and agree endpoints (too similar results but different) --- .../id/walt/service/keri/IpexService.kt | 114 ++++++++++++++++++ .../id/walt/web/controllers/AcdcController.kt | 48 ++++++++ 2 files changed, 162 insertions(+) create mode 100644 src/main/kotlin/id/walt/service/keri/IpexService.kt diff --git a/src/main/kotlin/id/walt/service/keri/IpexService.kt b/src/main/kotlin/id/walt/service/keri/IpexService.kt new file mode 100644 index 0000000..a5e17a8 --- /dev/null +++ b/src/main/kotlin/id/walt/service/keri/IpexService.kt @@ -0,0 +1,114 @@ +package id.walt.service.keri + +import id.walt.service.dto.AcdcSaidifyResponse +import id.walt.service.dto.IPEX_EVENT +import id.walt.service.dto.IpexSaid +import id.walt.service.keri.interfaces.IpexInterface +import java.io.BufferedReader +import java.io.IOException +import java.io.InputStreamReader + +class IpexService: IpexInterface { + override fun admit(keystore: String, alias: String, passcode: String, said: String, message: String?) { + TODO("Not yet implemented") + } + + override fun agree(): IpexSaid { + var said: String = "" + val command: List = listOf( + "kli", "ipex", + "agree" + ) + + try { + val processBuilder = ProcessBuilder(command) + val process = processBuilder.start() + + val reader = BufferedReader(InputStreamReader(process.inputStream)) + said= reader.readLine()!!.trimEnd('\n') + + process.waitFor() + + } catch(e: IOException) { + e.printStackTrace() + } catch (e: InterruptedException) { + e.printStackTrace() + } + return IpexSaid(said=said) + } + + override fun apply(): IpexSaid { + var said: String = "" + val command: List = listOf( + "kli", "ipex", + "apply" + ) + + try { + val processBuilder = ProcessBuilder(command) + val process = processBuilder.start() + + val reader = BufferedReader(InputStreamReader(process.inputStream)) + said= reader.readLine()!!.trimEnd('\n') + + process.waitFor() + + } catch(e: IOException) { + e.printStackTrace() + } catch (e: InterruptedException) { + e.printStackTrace() + } + return IpexSaid(said=said) + } + + override fun grant( + keystore: String, + alias: String, + passcode: String, + said: String, + recipient: String, + message: String? + ) { + TODO("Not yet implemented") + } + + override fun list( + keystore: String, + alias: String, + passcode: String, + type: IPEX_EVENT, + verbose: Boolean, + poll: Boolean, + sent: Boolean + ) { + TODO("Not yet implemented") + } + + override fun offer(): IpexSaid { + var said: String = "" + val command: List = listOf( + "kli", "ipex", + "offer" + ) + + try { + val processBuilder = ProcessBuilder(command) + val process = processBuilder.start() + + val reader = BufferedReader(InputStreamReader(process.inputStream)) + said= reader.readLine()!!.trimEnd('\n') + + process.waitFor() + + } catch(e: IOException) { + e.printStackTrace() + } catch (e: InterruptedException) { + e.printStackTrace() + } + return IpexSaid(said=said) + } + + override fun spurn(keystore: String, alias: String, passcode: String, said: String, message: String?) { + TODO("Not yet implemented") + } +} \ No newline at end of file diff --git a/src/main/kotlin/id/walt/web/controllers/AcdcController.kt b/src/main/kotlin/id/walt/web/controllers/AcdcController.kt index 9d51ccb..c66fc16 100644 --- a/src/main/kotlin/id/walt/web/controllers/AcdcController.kt +++ b/src/main/kotlin/id/walt/web/controllers/AcdcController.kt @@ -2,6 +2,7 @@ package id.walt.web.controllers import id.walt.service.dto.* import id.walt.service.keri.AcdcSaidifyService +import id.walt.service.keri.IpexService import io.github.smiley4.ktorswaggerui.dsl.post import io.github.smiley4.ktorswaggerui.dsl.route import io.ktor.http.* @@ -45,8 +46,55 @@ fun Application.acdc() = walletRoute { } else { call.respond(HttpStatusCode.Created, response) } + } + + post("ipex/apply", { + summary = "Disclosee: Request a credential from another party by initiating an IPEX exchange" + + response { + HttpStatusCode.OK to { + body { + example("application/json", IpexSaid(said = "EFLhmGcItk9WPXWvdV_X9XtGwfg4IJR4TLUSTHXMgWhi")) { + } + } + } + } + }) { + val response = IpexService().apply() + call.respond(HttpStatusCode.OK, response) + } + + post("ipex/offer", { + summary = "Discloser: Reply to IPEX apply message or initiate an IPEX exchange with an offer for a credential with certain characteristics" + + response { + HttpStatusCode.OK to { + body { + example("application/json", IpexSaid(said = "AIq50EHA8J634LNlpq7_b8PkL17OV5KcAae91cMp8g7h")) { + } + } + } + } + }) { + val response = IpexService().offer() + call.respond(HttpStatusCode.OK, response) + } + post("ipex/agree", { + summary = "Disclosee: Reply to IPEX offer message acknowledged willingness to accept offered credential" + response { + HttpStatusCode.OK to { + body { + example("application/json", IpexSaid(said = "AGjwWfC9LlDCCsSPdPomRmMZOIIeqPfHIA5V3hjyzf7D")) { + } + } + } + } + + }) { + val response = IpexService().agree() + call.respond(HttpStatusCode.OK, response) } } From 5af32f11050ba51f14e2d046e287ec266d265dd7 Mon Sep 17 00:00:00 2001 From: aminbenmansour Date: Tue, 31 Oct 2023 18:32:01 +0100 Subject: [PATCH 29/49] chore(saidify): remove redundant console printing --- src/main/kotlin/id/walt/service/keri/AcdcSaidifyService.kt | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main/kotlin/id/walt/service/keri/AcdcSaidifyService.kt b/src/main/kotlin/id/walt/service/keri/AcdcSaidifyService.kt index 61a7330..4cf4398 100644 --- a/src/main/kotlin/id/walt/service/keri/AcdcSaidifyService.kt +++ b/src/main/kotlin/id/walt/service/keri/AcdcSaidifyService.kt @@ -31,9 +31,6 @@ class AcdcSaidifyService: AcdcSaidifyInterface { content = readFileContent(file) said = extractSAID(file)!! - println("####################") - println(said) - println("####################") } catch(e: IOException) { e.printStackTrace() From 2f77cf9f1dd3adfca62d5cca319c42b8619d897c Mon Sep 17 00:00:00 2001 From: aminbenmansour Date: Tue, 31 Oct 2023 20:29:34 +0100 Subject: [PATCH 30/49] feat(grant): implement grant step in ipex --- .../service/dto/AcdcManagemementObjects.kt | 8 ++++ .../id/walt/service/keri/IpexService.kt | 39 ++++++++++++++++++- .../service/keri/interfaces/IpexInterface.kt | 2 +- .../id/walt/web/controllers/AcdcController.kt | 21 ++++++++++ 4 files changed, 67 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/id/walt/service/dto/AcdcManagemementObjects.kt b/src/main/kotlin/id/walt/service/dto/AcdcManagemementObjects.kt index a90524f..33dcf37 100644 --- a/src/main/kotlin/id/walt/service/dto/AcdcManagemementObjects.kt +++ b/src/main/kotlin/id/walt/service/dto/AcdcManagemementObjects.kt @@ -18,6 +18,14 @@ data class IpexSaid ( val said: String ) +@Serializable +data class IpexGrant ( + val passcode: String, + val credentialSaid: String, + val recipient: String, + val message: String? = null +) + enum class IPEX_EVENT(val type: String) { APPLY("apply"), OFFER("offer"), diff --git a/src/main/kotlin/id/walt/service/keri/IpexService.kt b/src/main/kotlin/id/walt/service/keri/IpexService.kt index a5e17a8..602982a 100644 --- a/src/main/kotlin/id/walt/service/keri/IpexService.kt +++ b/src/main/kotlin/id/walt/service/keri/IpexService.kt @@ -9,6 +9,9 @@ import java.io.IOException import java.io.InputStreamReader class IpexService: IpexInterface { + + // GRANT=$(kli ipex list --name holder --alias holder --poll --said) + // kli ipex admit --name holder --alias holder --said "${GRANT}" override fun admit(keystore: String, alias: String, passcode: String, said: String, message: String?) { TODO("Not yet implemented") } @@ -61,6 +64,7 @@ class IpexService: IpexInterface { return IpexSaid(said=said) } + // kli ipex grant --name issuer --alias issuer --said "${SAID}" --recipient ELjSFdrTdCebJlmvbFNX9-TLhR2PO0_60al1kQp5_e6k override fun grant( keystore: String, alias: String, @@ -68,8 +72,39 @@ class IpexService: IpexInterface { said: String, recipient: String, message: String? - ) { - TODO("Not yet implemented") + ): IpexSaid { + var result = "" + val command: List = listOf( + "kli", "ipex", + "grant", + "--name", keystore, + "--alias", alias, + "--passcode", passcode, + "--said", said, + "--recipient", recipient + ) + try { + val processBuilder = ProcessBuilder(command) + val process = processBuilder.start() + + val reader = BufferedReader(InputStreamReader(process.inputStream)) + result = reader.readLine()!!.trimEnd('\n') + + val errorReader = BufferedReader(InputStreamReader(process.errorStream)) + var errorLine: String? + while (errorReader.readLine().also { errorLine = it } != null) { + System.err.println(errorLine) + } + + process.waitFor() + } catch(e: IOException) { + e.printStackTrace() + } catch (e: InterruptedException) { + e.printStackTrace() + } + + + return IpexSaid(said=result) } override fun list( diff --git a/src/main/kotlin/id/walt/service/keri/interfaces/IpexInterface.kt b/src/main/kotlin/id/walt/service/keri/interfaces/IpexInterface.kt index 93dd33e..97ffb45 100644 --- a/src/main/kotlin/id/walt/service/keri/interfaces/IpexInterface.kt +++ b/src/main/kotlin/id/walt/service/keri/interfaces/IpexInterface.kt @@ -39,7 +39,7 @@ interface IpexInterface { /** * Reply to IPEX agree message or initiate an IPEX exchange with a credential issuance or presentation */ - fun grant(keystore: String, alias: String, passcode: String, said: String, recipient: String, message: String?); + fun grant(keystore: String, alias: String, passcode: String, said: String, recipient: String, message: String?): IpexSaid; /** * List notifications related to IPEX protocol messages diff --git a/src/main/kotlin/id/walt/web/controllers/AcdcController.kt b/src/main/kotlin/id/walt/web/controllers/AcdcController.kt index c66fc16..8e8e729 100644 --- a/src/main/kotlin/id/walt/web/controllers/AcdcController.kt +++ b/src/main/kotlin/id/walt/web/controllers/AcdcController.kt @@ -97,5 +97,26 @@ fun Application.acdc() = walletRoute { call.respond(HttpStatusCode.OK, response) } + post("ipex/grant/keystore/{keystore}/alias/{alias}", { + summary = "" + + response { + HttpStatusCode.OK to { + body { + example("application/json", IpexSaid(said = "AGjwWfC9LlDCCsSPdPomRmMZOIIeqPfHIA5V3hjyzf7D")) { + } + } + } + } + + }) { + val keystore = call.parameters["keystore"] ?: return@post call.respond(HttpStatusCode.BadRequest) + val alias = call.parameters["alias"] ?: return@post call.respond(HttpStatusCode.BadRequest) + + val dto = call.receive() + val response = IpexService().grant(keystore, alias, dto.passcode, dto.credentialSaid, dto.recipient, dto.message) + call.respond(HttpStatusCode.OK, response) + } + } } \ No newline at end of file From eea8805f6a39e198f2905da3632cdd210e5f9eb8 Mon Sep 17 00:00:00 2001 From: aminbenmansour Date: Tue, 31 Oct 2023 21:43:51 +0100 Subject: [PATCH 31/49] feat(resolve): resolve out of band introductions through dns urls --- .../service/dto/KeriUserManagementObjects.kt | 7 +++ .../id/walt/service/keri/KeriOobiService.kt | 39 +++++++++++++++++ .../keri/interfaces/KeriOobiInterface.kt | 6 +++ .../id/walt/web/controllers/KeriController.kt | 43 +++++++++++++++++-- 4 files changed, 91 insertions(+), 4 deletions(-) create mode 100644 src/main/kotlin/id/walt/service/keri/KeriOobiService.kt create mode 100644 src/main/kotlin/id/walt/service/keri/interfaces/KeriOobiInterface.kt diff --git a/src/main/kotlin/id/walt/service/dto/KeriUserManagementObjects.kt b/src/main/kotlin/id/walt/service/dto/KeriUserManagementObjects.kt index f56566d..36e6cec 100644 --- a/src/main/kotlin/id/walt/service/dto/KeriUserManagementObjects.kt +++ b/src/main/kotlin/id/walt/service/dto/KeriUserManagementObjects.kt @@ -24,3 +24,10 @@ data class KeriInceptionResponse ( val did: String, val publicKeys: List ) + +@Serializable +data class KeriOobiResolveRequest ( + val passcode: String, + val oobiAlias: String, + val url: String +) diff --git a/src/main/kotlin/id/walt/service/keri/KeriOobiService.kt b/src/main/kotlin/id/walt/service/keri/KeriOobiService.kt new file mode 100644 index 0000000..ce8bb4e --- /dev/null +++ b/src/main/kotlin/id/walt/service/keri/KeriOobiService.kt @@ -0,0 +1,39 @@ +package id.walt.service.keri + +import id.walt.service.dto.KeriCreateDbResponse +import id.walt.service.keri.interfaces.KeriOobiInterface +import java.io.BufferedReader +import java.io.IOException +import java.io.InputStreamReader + +class KeriOobiService: KeriOobiInterface { + override fun generate(keystore: String, alias: String, role: String, passcode: String): String { + TODO("Not yet implemented") + } + + override fun resolve(keystore: String, passcode: String, oobiAlias: String, url: String): Boolean { + var status = 0 + val command: List = listOf( + "kli", "oobi", + "resolve", + "--name", keystore, + "--passcode", passcode, + "--oobi-alias", oobiAlias, + "--oobi", url + ) + + try { + val processBuilder = ProcessBuilder(command) + val process = processBuilder.start() + + status = process.waitFor() + + } catch(e: IOException) { + e.printStackTrace() + } catch (e: InterruptedException) { + e.printStackTrace() + } + + return status == 0 + } +} \ No newline at end of file diff --git a/src/main/kotlin/id/walt/service/keri/interfaces/KeriOobiInterface.kt b/src/main/kotlin/id/walt/service/keri/interfaces/KeriOobiInterface.kt new file mode 100644 index 0000000..e697c92 --- /dev/null +++ b/src/main/kotlin/id/walt/service/keri/interfaces/KeriOobiInterface.kt @@ -0,0 +1,6 @@ +package id.walt.service.keri.interfaces + +interface KeriOobiInterface { + fun generate(keystore: String, alias: String, role: String, passcode: String): String; + fun resolve(keystore: String, passcode: String, oobiAlias: String, url: String): Boolean; +} \ No newline at end of file diff --git a/src/main/kotlin/id/walt/web/controllers/KeriController.kt b/src/main/kotlin/id/walt/web/controllers/KeriController.kt index 13578e2..966d458 100644 --- a/src/main/kotlin/id/walt/web/controllers/KeriController.kt +++ b/src/main/kotlin/id/walt/web/controllers/KeriController.kt @@ -1,11 +1,9 @@ package id.walt.web.controllers -import id.walt.service.dto.KeriCreateDbRequest -import id.walt.service.dto.KeriCreateDbResponse -import id.walt.service.dto.KeriInceptionRequest -import id.walt.service.dto.KeriInceptionResponse +import id.walt.service.dto.* import id.walt.service.keri.KeriInceptionService import id.walt.service.keri.KeriInitService +import id.walt.service.keri.KeriOobiService import io.github.smiley4.ktorswaggerui.dsl.post import io.github.smiley4.ktorswaggerui.dsl.route import io.ktor.http.* @@ -95,5 +93,42 @@ fun Application.keri() = walletRoute { } + post("oobi/resolve/keystore/{keystore}/oobiAlias/{oobiAlias}", { + summary = "Resolve the provided OOBI" + + request { + pathParameter("keystore") { + description = "keystore name and file location of KERI keystore" + example = "waltid" + } + + pathParameter("oobiAlias") { + description = "human-readable alternative for KERI" + example = "waltid-alias" + } + + body { + description = "Required data for resolving an OOBI" + example("application/json", KeriOobiResolveRequest(passcode = "0123456789abcdefghijk", oobiAlias = "holder", url = "http://127.0.0.1:5642/oobi/EL" + + "jSFdrTdCebJlmvbFNX9-TLhR2PO0_60al1kQp5_e6k/witness/BBilc4-L3tFUnfM_wJr4S4OJanAv_VmF_dJNN6vkf2Ha")) + } + + } + response { + HttpStatusCode.Created to { + body { + description = "A boolean, whether the OOBI was resolved or not" + } + } + } + }) { + val keystore = call.parameters["keystore"] ?: return@post call.respond(HttpStatusCode.BadRequest) + val oobiAlias = call.parameters["oobiAlias"] ?: return@post call.respond(HttpStatusCode.BadRequest) + val dto = call.receive() + val response = KeriOobiService().resolve(keystore, dto.passcode, oobiAlias, dto.url) + + call.respond(HttpStatusCode.Created, response) + } + } } \ No newline at end of file From 7f8af8c0d4f67011982bc578857e478f84f4f73a Mon Sep 17 00:00:00 2001 From: aminbenmansour Date: Wed, 1 Nov 2023 11:44:02 +0100 Subject: [PATCH 32/49] feat(list): get ipex notificattions --- .../service/dto/AcdcManagemementObjects.kt | 10 +++++ .../id/walt/service/keri/IpexService.kt | 41 ++++++++++++++++--- .../service/keri/interfaces/IpexInterface.kt | 10 ++++- .../id/walt/web/controllers/AcdcController.kt | 32 +++++++++++++++ 4 files changed, 87 insertions(+), 6 deletions(-) diff --git a/src/main/kotlin/id/walt/service/dto/AcdcManagemementObjects.kt b/src/main/kotlin/id/walt/service/dto/AcdcManagemementObjects.kt index 33dcf37..cd7486f 100644 --- a/src/main/kotlin/id/walt/service/dto/AcdcManagemementObjects.kt +++ b/src/main/kotlin/id/walt/service/dto/AcdcManagemementObjects.kt @@ -26,6 +26,16 @@ data class IpexGrant ( val message: String? = null ) +@Serializable +data class IpexList ( + val passcode: String, + val schema: String, + val type: IPEX_EVENT? = null, + val poll: Boolean = true, + val said: Boolean = true, + val sent: Boolean = false, + val verbose: Boolean = false +) enum class IPEX_EVENT(val type: String) { APPLY("apply"), OFFER("offer"), diff --git a/src/main/kotlin/id/walt/service/keri/IpexService.kt b/src/main/kotlin/id/walt/service/keri/IpexService.kt index 602982a..9bdd630 100644 --- a/src/main/kotlin/id/walt/service/keri/IpexService.kt +++ b/src/main/kotlin/id/walt/service/keri/IpexService.kt @@ -1,6 +1,5 @@ package id.walt.service.keri -import id.walt.service.dto.AcdcSaidifyResponse import id.walt.service.dto.IPEX_EVENT import id.walt.service.dto.IpexSaid import id.walt.service.keri.interfaces.IpexInterface @@ -107,16 +106,48 @@ class IpexService: IpexInterface { return IpexSaid(said=result) } + // GRANT=$(kli ipex list --name holder --alias holder --poll --said) override fun list( keystore: String, alias: String, passcode: String, - type: IPEX_EVENT, + schema: String, + type: IPEX_EVENT?, verbose: Boolean, poll: Boolean, - sent: Boolean - ) { - TODO("Not yet implemented") + sent: Boolean, + said: Boolean + ): IpexSaid { + var result = "" + + val command: MutableList = mutableListOf( + "kli", "ipex", + "grant", + "--name", keystore, + "--alias", alias, + "--passcode", passcode, + "--schema", schema + ) + + command.takeIf { poll }?.add("--poll") + command.takeIf { sent }?.add("--sent") + command.takeIf { said }?.add("--said") + + try { + val processBuilder = ProcessBuilder(command) + val process = processBuilder.start() + + val reader = BufferedReader(InputStreamReader(process.inputStream)) + result= reader.readLine()!!.trimEnd('\n') + + process.waitFor() + + } catch(e: IOException) { + e.printStackTrace() + } catch (e: InterruptedException) { + e.printStackTrace() + } + return IpexSaid(said=result) } override fun offer(): IpexSaid { diff --git a/src/main/kotlin/id/walt/service/keri/interfaces/IpexInterface.kt b/src/main/kotlin/id/walt/service/keri/interfaces/IpexInterface.kt index 97ffb45..20e0024 100644 --- a/src/main/kotlin/id/walt/service/keri/interfaces/IpexInterface.kt +++ b/src/main/kotlin/id/walt/service/keri/interfaces/IpexInterface.kt @@ -44,7 +44,15 @@ interface IpexInterface { /** * List notifications related to IPEX protocol messages */ - fun list(keystore: String, alias: String, passcode: String, type: IPEX_EVENT, verbose: Boolean, poll: Boolean, sent: Boolean); + fun list(keystore: String, + alias: String, + passcode: String, + schema: String, + type: IPEX_EVENT?, + verbose: Boolean, + poll: Boolean, + sent: Boolean, + said: Boolean): IpexSaid; /** * Reply to IPEX apply message or initiate an IPEX exchange with an offer for a credential with certain characteristics diff --git a/src/main/kotlin/id/walt/web/controllers/AcdcController.kt b/src/main/kotlin/id/walt/web/controllers/AcdcController.kt index 8e8e729..5316e2b 100644 --- a/src/main/kotlin/id/walt/web/controllers/AcdcController.kt +++ b/src/main/kotlin/id/walt/web/controllers/AcdcController.kt @@ -3,6 +3,7 @@ package id.walt.web.controllers import id.walt.service.dto.* import id.walt.service.keri.AcdcSaidifyService import id.walt.service.keri.IpexService +import io.github.smiley4.ktorswaggerui.dsl.get import io.github.smiley4.ktorswaggerui.dsl.post import io.github.smiley4.ktorswaggerui.dsl.route import io.ktor.http.* @@ -118,5 +119,36 @@ fun Application.acdc() = walletRoute { call.respond(HttpStatusCode.OK, response) } + get("ipex/list/keystore/{keystore}/alias/{alias}", { + summary = "" + + response { + HttpStatusCode.OK to { + body { + example("application/json", IpexSaid(said = "AGjwWfC9LlDCCsSPdPomRmMZOIIeqPfHIA5V3hjyzf7D")) { + } + } + } + } + + }) { + val keystore = call.parameters["keystore"] ?: return@get call.respond(HttpStatusCode.BadRequest) + val alias = call.parameters["alias"] ?: return@get call.respond(HttpStatusCode.BadRequest) + + val dto = call.receive() + val response = IpexService().list(keystore, + alias, + dto.passcode, + dto.schema, + dto.type, + dto.verbose, + dto.poll, + dto.sent, + dto.said + ) + call.respond(HttpStatusCode.OK, response) + } + } + } \ No newline at end of file From 2a2ff4b2c3251c02220364cbb3f5908e38739cd4 Mon Sep 17 00:00:00 2001 From: aminbenmansour Date: Wed, 1 Nov 2023 11:52:03 +0100 Subject: [PATCH 33/49] docs(list): openapi request docs --- .../id/walt/web/controllers/AcdcController.kt | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/main/kotlin/id/walt/web/controllers/AcdcController.kt b/src/main/kotlin/id/walt/web/controllers/AcdcController.kt index 5316e2b..59cd0b4 100644 --- a/src/main/kotlin/id/walt/web/controllers/AcdcController.kt +++ b/src/main/kotlin/id/walt/web/controllers/AcdcController.kt @@ -122,6 +122,31 @@ fun Application.acdc() = walletRoute { get("ipex/list/keystore/{keystore}/alias/{alias}", { summary = "" + request { + pathParameter("keystore") { + description = "keystore name and file location of KERI keystore" + example = "waltid" + } + + pathParameter("alias") { + description = "human readable alias for the identifier to whom the credential was issued" + example = "waltid-alias" + } + + body { + description = "Required data for listing an event" + example("application/json", IpexList( + passcode = "0123456789abcdefghijk", + schema = "m2rz53livjpiINfPYRIO_VWje6VfhF6CtHJcbzyyNtE", + type = IPEX_EVENT.GRANT, + poll = true, + said = true, + sent = false, + verbose = false + )) + } + } + response { HttpStatusCode.OK to { body { From f37b736a4ecf7ac77e923609eac0a0663d911fcb Mon Sep 17 00:00:00 2001 From: aminbenmansour Date: Wed, 1 Nov 2023 14:18:46 +0100 Subject: [PATCH 34/49] feat(admit): Accept a credential being issued or presented in response to an IPEX grant --- .../service/dto/AcdcManagemementObjects.kt | 8 ++++ .../id/walt/service/keri/IpexService.kt | 39 ++++++++++++++++--- .../service/keri/interfaces/IpexInterface.kt | 2 +- .../id/walt/web/controllers/AcdcController.kt | 16 +++++++- 4 files changed, 56 insertions(+), 9 deletions(-) diff --git a/src/main/kotlin/id/walt/service/dto/AcdcManagemementObjects.kt b/src/main/kotlin/id/walt/service/dto/AcdcManagemementObjects.kt index cd7486f..928de5e 100644 --- a/src/main/kotlin/id/walt/service/dto/AcdcManagemementObjects.kt +++ b/src/main/kotlin/id/walt/service/dto/AcdcManagemementObjects.kt @@ -26,6 +26,13 @@ data class IpexGrant ( val message: String? = null ) +@Serializable +data class IpexAdmit ( + val passcode: String, + val said: String, + val message: String? = null +) + @Serializable data class IpexList ( val passcode: String, @@ -36,6 +43,7 @@ data class IpexList ( val sent: Boolean = false, val verbose: Boolean = false ) + enum class IPEX_EVENT(val type: String) { APPLY("apply"), OFFER("offer"), diff --git a/src/main/kotlin/id/walt/service/keri/IpexService.kt b/src/main/kotlin/id/walt/service/keri/IpexService.kt index 9bdd630..1a9832b 100644 --- a/src/main/kotlin/id/walt/service/keri/IpexService.kt +++ b/src/main/kotlin/id/walt/service/keri/IpexService.kt @@ -8,11 +8,40 @@ import java.io.IOException import java.io.InputStreamReader class IpexService: IpexInterface { + override fun admit(keystore: String, alias: String, passcode: String, said: String, message: String?): String { + var result: String = "" + val command: MutableList = mutableListOf( + "kli", "ipex", + "admit", + "--name", keystore, + "--alias", alias, + "--passcode", passcode, + "--said", said + ) - // GRANT=$(kli ipex list --name holder --alias holder --poll --said) - // kli ipex admit --name holder --alias holder --said "${GRANT}" - override fun admit(keystore: String, alias: String, passcode: String, said: String, message: String?) { - TODO("Not yet implemented") + if (message != null) { + command.add("--message"); command.add(message) + } + + try { + val processBuilder = ProcessBuilder(command) + val process = processBuilder.start() + + val reader = BufferedReader(InputStreamReader(process.inputStream)) + var line: String? + while (reader.readLine().also { line = it } != null) { + result+=line + } + + process.waitFor() + + } catch(e: IOException) { + e.printStackTrace() + } catch (e: InterruptedException) { + e.printStackTrace() + } + + return result } override fun agree(): IpexSaid { @@ -63,7 +92,6 @@ class IpexService: IpexInterface { return IpexSaid(said=said) } - // kli ipex grant --name issuer --alias issuer --said "${SAID}" --recipient ELjSFdrTdCebJlmvbFNX9-TLhR2PO0_60al1kQp5_e6k override fun grant( keystore: String, alias: String, @@ -106,7 +134,6 @@ class IpexService: IpexInterface { return IpexSaid(said=result) } - // GRANT=$(kli ipex list --name holder --alias holder --poll --said) override fun list( keystore: String, alias: String, diff --git a/src/main/kotlin/id/walt/service/keri/interfaces/IpexInterface.kt b/src/main/kotlin/id/walt/service/keri/interfaces/IpexInterface.kt index 20e0024..6b2b686 100644 --- a/src/main/kotlin/id/walt/service/keri/interfaces/IpexInterface.kt +++ b/src/main/kotlin/id/walt/service/keri/interfaces/IpexInterface.kt @@ -24,7 +24,7 @@ interface IpexInterface { /** * Accept a credential being issued or presented in response to an IPEX grant */ - fun admit(keystore: String, alias: String, passcode: String, said: String, message: String?); + fun admit(keystore: String, alias: String, passcode: String, said: String, message: String?): String; /** * Reply to IPEX offer message acknowledged willingness to accept offered credential diff --git a/src/main/kotlin/id/walt/web/controllers/AcdcController.kt b/src/main/kotlin/id/walt/web/controllers/AcdcController.kt index 59cd0b4..e79bb09 100644 --- a/src/main/kotlin/id/walt/web/controllers/AcdcController.kt +++ b/src/main/kotlin/id/walt/web/controllers/AcdcController.kt @@ -119,8 +119,19 @@ fun Application.acdc() = walletRoute { call.respond(HttpStatusCode.OK, response) } + post("ipex/admit/keystore/{keystore}/alias/{alias}", { + summary = "Accept a credential being issued or presented in response to an IPEX grant" + }) { + val keystore = call.parameters["keystore"] ?: return@post call.respond(HttpStatusCode.BadRequest) + val alias = call.parameters["alias"] ?: return@post call.respond(HttpStatusCode.BadRequest) + + val dto = call.receive() + val response = IpexService().admit(keystore, alias, dto.passcode, dto.said, dto.message) + call.respond(HttpStatusCode.OK, response) + } + get("ipex/list/keystore/{keystore}/alias/{alias}", { - summary = "" + summary = "List notifications related to IPEX protocol message" request { pathParameter("keystore") { @@ -161,7 +172,8 @@ fun Application.acdc() = walletRoute { val alias = call.parameters["alias"] ?: return@get call.respond(HttpStatusCode.BadRequest) val dto = call.receive() - val response = IpexService().list(keystore, + val response = IpexService().list( + keystore, alias, dto.passcode, dto.schema, From 1df967b9d2ee912a218e00edfc57b36b07b3b505 Mon Sep 17 00:00:00 2001 From: aminbenmansour Date: Wed, 1 Nov 2023 14:23:12 +0100 Subject: [PATCH 35/49] docs(admit): OpenApi request structure --- .../id/walt/web/controllers/AcdcController.kt | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/main/kotlin/id/walt/web/controllers/AcdcController.kt b/src/main/kotlin/id/walt/web/controllers/AcdcController.kt index e79bb09..5cd9673 100644 --- a/src/main/kotlin/id/walt/web/controllers/AcdcController.kt +++ b/src/main/kotlin/id/walt/web/controllers/AcdcController.kt @@ -121,6 +121,28 @@ fun Application.acdc() = walletRoute { post("ipex/admit/keystore/{keystore}/alias/{alias}", { summary = "Accept a credential being issued or presented in response to an IPEX grant" + + request { + pathParameter("keystore") { + description = "keystore name and file location of KERI keystore" + example = "waltid" + } + + pathParameter("alias") { + description = "human readable alias for the identifier to whom the credential was issued" + example = "waltid-alias" + } + + body { + description = "Required data for listing an event" + example("application/json", IpexAdmit( + passcode = "0123456789abcdefghijk", + said = "EBfdlu8R27Fbx-ehrqwImnK-8Cm79sqbAQ4MmvEAYqao", + message = "Sent to a friend" + )) + } + } + }) { val keystore = call.parameters["keystore"] ?: return@post call.respond(HttpStatusCode.BadRequest) val alias = call.parameters["alias"] ?: return@post call.respond(HttpStatusCode.BadRequest) From 37a85b553f585ad17726ab274f2ab332ab5b919c Mon Sep 17 00:00:00 2001 From: aminbenmansour Date: Wed, 1 Nov 2023 14:42:08 +0100 Subject: [PATCH 36/49] feat(spurn): reject an IPEX apply, offer, agree or grant message --- .../service/dto/AcdcManagemementObjects.kt | 7 ++++++ .../id/walt/service/keri/IpexService.kt | 24 ++++++++++++++++++- .../id/walt/web/controllers/AcdcController.kt | 16 ++++++++++++- 3 files changed, 45 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/id/walt/service/dto/AcdcManagemementObjects.kt b/src/main/kotlin/id/walt/service/dto/AcdcManagemementObjects.kt index 928de5e..86bbf65 100644 --- a/src/main/kotlin/id/walt/service/dto/AcdcManagemementObjects.kt +++ b/src/main/kotlin/id/walt/service/dto/AcdcManagemementObjects.kt @@ -33,6 +33,13 @@ data class IpexAdmit ( val message: String? = null ) +@Serializable +data class IpexSpurn ( + val passcode: String, + val said: String, + val message: String? = null +) + @Serializable data class IpexList ( val passcode: String, diff --git a/src/main/kotlin/id/walt/service/keri/IpexService.kt b/src/main/kotlin/id/walt/service/keri/IpexService.kt index 1a9832b..02bbb48 100644 --- a/src/main/kotlin/id/walt/service/keri/IpexService.kt +++ b/src/main/kotlin/id/walt/service/keri/IpexService.kt @@ -202,6 +202,28 @@ class IpexService: IpexInterface { } override fun spurn(keystore: String, alias: String, passcode: String, said: String, message: String?) { - TODO("Not yet implemented") + val command: MutableList = mutableListOf( + "kli", "ipex", + "admit", + "--name", keystore, + "--alias", alias, + "--passcode", passcode, + "--said", said + ) + + if (message != null) { + command.add("--message"); command.add(message) + } + + try { + val processBuilder = ProcessBuilder(command) + val process = processBuilder.start() + process.waitFor() + + } catch(e: IOException) { + e.printStackTrace() + } catch (e: InterruptedException) { + e.printStackTrace() + } } } \ No newline at end of file diff --git a/src/main/kotlin/id/walt/web/controllers/AcdcController.kt b/src/main/kotlin/id/walt/web/controllers/AcdcController.kt index 5cd9673..764d3ca 100644 --- a/src/main/kotlin/id/walt/web/controllers/AcdcController.kt +++ b/src/main/kotlin/id/walt/web/controllers/AcdcController.kt @@ -5,6 +5,7 @@ import id.walt.service.keri.AcdcSaidifyService import id.walt.service.keri.IpexService import io.github.smiley4.ktorswaggerui.dsl.get import io.github.smiley4.ktorswaggerui.dsl.post +import io.github.smiley4.ktorswaggerui.dsl.delete import io.github.smiley4.ktorswaggerui.dsl.route import io.ktor.http.* import io.ktor.server.application.* @@ -134,7 +135,7 @@ fun Application.acdc() = walletRoute { } body { - description = "Required data for listing an event" + description = "Required data for admitting an event" example("application/json", IpexAdmit( passcode = "0123456789abcdefghijk", said = "EBfdlu8R27Fbx-ehrqwImnK-8Cm79sqbAQ4MmvEAYqao", @@ -208,6 +209,19 @@ fun Application.acdc() = walletRoute { call.respond(HttpStatusCode.OK, response) } + delete("ipex/admit/keystore/{keystore}/alias/{alias}", { + summary = "Reject an IPEX apply, offer, agree or grant message" + + + }) { + val keystore = call.parameters["keystore"] ?: return@delete call.respond(HttpStatusCode.BadRequest) + val alias = call.parameters["alias"] ?: return@delete call.respond(HttpStatusCode.BadRequest) + + val dto = call.receive() + IpexService().spurn(keystore, alias, dto.passcode, dto.said, dto.message) + call.respond(HttpStatusCode.NoContent) + } + } } \ No newline at end of file From e2af3a61159cff829498ff85a5600488c757ba49 Mon Sep 17 00:00:00 2001 From: aminbenmansour Date: Wed, 1 Nov 2023 14:42:51 +0100 Subject: [PATCH 37/49] docs(admit): OpenApi spurn request structure --- .../id/walt/web/controllers/AcdcController.kt | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/main/kotlin/id/walt/web/controllers/AcdcController.kt b/src/main/kotlin/id/walt/web/controllers/AcdcController.kt index 764d3ca..f06f13a 100644 --- a/src/main/kotlin/id/walt/web/controllers/AcdcController.kt +++ b/src/main/kotlin/id/walt/web/controllers/AcdcController.kt @@ -212,7 +212,26 @@ fun Application.acdc() = walletRoute { delete("ipex/admit/keystore/{keystore}/alias/{alias}", { summary = "Reject an IPEX apply, offer, agree or grant message" + request { + pathParameter("keystore") { + description = "keystore name and file location of KERI keystore" + example = "waltid" + } + pathParameter("alias") { + description = "human readable alias for the identifier to whom the credential was issued" + example = "waltid-alias" + } + + body { + description = "Required data for rejecting an event" + example("application/json", IpexSpurn( + passcode = "0123456789abcdefghijk", + said = "EBfdlu8R27Fbx-ehrqwImnK-8Cm79sqbAQ4MmvEAYqao", + message = "Sent to a friend" + )) + } + } }) { val keystore = call.parameters["keystore"] ?: return@delete call.respond(HttpStatusCode.BadRequest) val alias = call.parameters["alias"] ?: return@delete call.respond(HttpStatusCode.BadRequest) From 26f5361969052162d7e840ef0ede34a915cb7749 Mon Sep 17 00:00:00 2001 From: aminbenmansour Date: Wed, 1 Nov 2023 15:22:54 +0100 Subject: [PATCH 38/49] fix(spurn): correct api endpoint --- src/main/kotlin/id/walt/web/controllers/AcdcController.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/id/walt/web/controllers/AcdcController.kt b/src/main/kotlin/id/walt/web/controllers/AcdcController.kt index f06f13a..300b5ea 100644 --- a/src/main/kotlin/id/walt/web/controllers/AcdcController.kt +++ b/src/main/kotlin/id/walt/web/controllers/AcdcController.kt @@ -100,7 +100,7 @@ fun Application.acdc() = walletRoute { } post("ipex/grant/keystore/{keystore}/alias/{alias}", { - summary = "" + summary = "Reply to IPEX agree message or initiate an IPEX exchange with a credential issuance or presentation" response { HttpStatusCode.OK to { @@ -209,7 +209,7 @@ fun Application.acdc() = walletRoute { call.respond(HttpStatusCode.OK, response) } - delete("ipex/admit/keystore/{keystore}/alias/{alias}", { + delete("ipex/spurn/keystore/{keystore}/alias/{alias}", { summary = "Reject an IPEX apply, offer, agree or grant message" request { From 3ac7479f2af32301e3151f68689364006fee5e3b Mon Sep 17 00:00:00 2001 From: aminbenmansour Date: Wed, 1 Nov 2023 15:27:11 +0100 Subject: [PATCH 39/49] chore(acdc): define acdc management interface --- .../service/keri/AcdcManagementService.kt | 51 +++++++++++++++++++ .../interfaces/AcdcManagementInterface.kt | 36 +++++++++++++ 2 files changed, 87 insertions(+) create mode 100644 src/main/kotlin/id/walt/service/keri/AcdcManagementService.kt create mode 100644 src/main/kotlin/id/walt/service/keri/interfaces/AcdcManagementInterface.kt diff --git a/src/main/kotlin/id/walt/service/keri/AcdcManagementService.kt b/src/main/kotlin/id/walt/service/keri/AcdcManagementService.kt new file mode 100644 index 0000000..e71e623 --- /dev/null +++ b/src/main/kotlin/id/walt/service/keri/AcdcManagementService.kt @@ -0,0 +1,51 @@ +package id.walt.service.keri + +import id.walt.service.keri.interfaces.AcdcManagementInterface + +class AcdcManagementService: AcdcManagementInterface { + override fun create( + keystore: String, + registry: String, + passcode: String, + schema: String, + edges: String, + rules: String, + recipient: String, + data: String, + credential: String, + alias: String, + private: Boolean, + time: String + ) { + TODO("Not yet implemented") + } + + override fun present(keystore: String, alias: String, passcode: String, said: String, recipient: String) { + TODO("Not yet implemented") + } + + override fun list( + keystore: String, + alias: String, + passcode: String, + verbose: Boolean, + poll: Boolean, + issued: Boolean, + said: Boolean, + schema: Boolean + ) { + TODO("Not yet implemented") + } + + override fun revoke( + keystore: String, + alias: String, + registry: String, + passcode: String, + said: String, + send: String, + time: String + ) { + TODO("Not yet implemented") + } +} \ No newline at end of file diff --git a/src/main/kotlin/id/walt/service/keri/interfaces/AcdcManagementInterface.kt b/src/main/kotlin/id/walt/service/keri/interfaces/AcdcManagementInterface.kt new file mode 100644 index 0000000..fad2c15 --- /dev/null +++ b/src/main/kotlin/id/walt/service/keri/interfaces/AcdcManagementInterface.kt @@ -0,0 +1,36 @@ +package id.walt.service.keri.interfaces + +interface AcdcManagementInterface { + fun create(keystore: String, + registry: String, + passcode: String, + schema: String, + edges: String, + rules: String, + recipient: String, + data: String, + credential: String, + alias: String, + private: Boolean, + time: String) + fun present(keystore: String, + alias: String, + passcode: String, + said: String, + recipient: String) + fun list(keystore: String, + alias: String, + passcode: String, + verbose: Boolean, + poll: Boolean, + issued: Boolean, + said: Boolean, + schema: Boolean) + fun revoke(keystore: String, + alias: String, + registry: String, + passcode: String, + said: String, + send: String, + time: String) +} \ No newline at end of file From 4ddeea809bf3b9b35888e3aa460c7ada4fb747e0 Mon Sep 17 00:00:00 2001 From: aminbenmansour Date: Wed, 1 Nov 2023 15:56:05 +0100 Subject: [PATCH 40/49] feat(list): implement listing credentials --- .../service/dto/AcdcManagemementObjects.kt | 10 +++++ .../service/keri/AcdcManagementService.kt | 39 ++++++++++++++++++- .../interfaces/AcdcManagementInterface.kt | 11 +++++- .../id/walt/web/controllers/AcdcController.kt | 20 ++++++++++ 4 files changed, 77 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/id/walt/service/dto/AcdcManagemementObjects.kt b/src/main/kotlin/id/walt/service/dto/AcdcManagemementObjects.kt index 86bbf65..1c6cb38 100644 --- a/src/main/kotlin/id/walt/service/dto/AcdcManagemementObjects.kt +++ b/src/main/kotlin/id/walt/service/dto/AcdcManagemementObjects.kt @@ -51,6 +51,16 @@ data class IpexList ( val verbose: Boolean = false ) +@Serializable +data class AcdcList ( + val passcode: String, + val verbose: Boolean, + val poll: Boolean = true, + val issued: Boolean = false, + val said: Boolean = true, + val schema: Boolean = false, +) + enum class IPEX_EVENT(val type: String) { APPLY("apply"), OFFER("offer"), diff --git a/src/main/kotlin/id/walt/service/keri/AcdcManagementService.kt b/src/main/kotlin/id/walt/service/keri/AcdcManagementService.kt index e71e623..354198b 100644 --- a/src/main/kotlin/id/walt/service/keri/AcdcManagementService.kt +++ b/src/main/kotlin/id/walt/service/keri/AcdcManagementService.kt @@ -1,6 +1,9 @@ package id.walt.service.keri import id.walt.service.keri.interfaces.AcdcManagementInterface +import java.io.BufferedReader +import java.io.IOException +import java.io.InputStreamReader class AcdcManagementService: AcdcManagementInterface { override fun create( @@ -33,8 +36,40 @@ class AcdcManagementService: AcdcManagementInterface { issued: Boolean, said: Boolean, schema: Boolean - ) { - TODO("Not yet implemented") + ): String { + var result = "" + val command: MutableList = mutableListOf( + "kli", "vc", + "list", + "--name", keystore, + "--alias", alias, + "--passcode", passcode + ) + + command.takeIf { verbose }?.add("--verbose") + command.takeIf { poll }?.add("--poll") + command.takeIf { issued }?.add("--issued") + command.takeIf { said }?.add("--said") + command.takeIf { schema }?.add("--schema") + + try { + val processBuilder = ProcessBuilder(command) + val process = processBuilder.start() + + val reader = BufferedReader(InputStreamReader(process.inputStream)) + var line: String? + while (reader.readLine().also { line = it } != null) { + result+=line + } + + process.waitFor() + + } catch(e: IOException) { + e.printStackTrace() + } catch (e: InterruptedException) { + e.printStackTrace() + } + return result } override fun revoke( diff --git a/src/main/kotlin/id/walt/service/keri/interfaces/AcdcManagementInterface.kt b/src/main/kotlin/id/walt/service/keri/interfaces/AcdcManagementInterface.kt index fad2c15..2c9f7c5 100644 --- a/src/main/kotlin/id/walt/service/keri/interfaces/AcdcManagementInterface.kt +++ b/src/main/kotlin/id/walt/service/keri/interfaces/AcdcManagementInterface.kt @@ -13,11 +13,19 @@ interface AcdcManagementInterface { alias: String, private: Boolean, time: String) + + /** + * Send credential presentation for specified credential to recipient + */ fun present(keystore: String, alias: String, passcode: String, said: String, recipient: String) + + /** + * List credentials and check mailboxes for any newly issued credentials + */ fun list(keystore: String, alias: String, passcode: String, @@ -25,7 +33,8 @@ interface AcdcManagementInterface { poll: Boolean, issued: Boolean, said: Boolean, - schema: Boolean) + schema: Boolean): String + fun revoke(keystore: String, alias: String, registry: String, diff --git a/src/main/kotlin/id/walt/web/controllers/AcdcController.kt b/src/main/kotlin/id/walt/web/controllers/AcdcController.kt index f06f13a..1fb4383 100644 --- a/src/main/kotlin/id/walt/web/controllers/AcdcController.kt +++ b/src/main/kotlin/id/walt/web/controllers/AcdcController.kt @@ -1,6 +1,7 @@ package id.walt.web.controllers import id.walt.service.dto.* +import id.walt.service.keri.AcdcManagementService import id.walt.service.keri.AcdcSaidifyService import id.walt.service.keri.IpexService import io.github.smiley4.ktorswaggerui.dsl.get @@ -243,4 +244,23 @@ fun Application.acdc() = walletRoute { } + get("list/keystore/{keystore}/alias/{alias}", { + summary = "List credentials and check mailboxes for any newly issued credentials" + + }) { + val keystore = call.parameters["keystore"] ?: return@get call.respond(HttpStatusCode.BadRequest) + val alias = call.parameters["alias"] ?: return@get call.respond(HttpStatusCode.BadRequest) + + val dto = call.receive() + val response = AcdcManagementService().list(keystore, + alias, + dto.passcode, + dto.verbose, + dto.poll, + dto.issued, + dto.said, + dto.schema) + call.respond(HttpStatusCode.OK, response) + } + } \ No newline at end of file From edb95c1bf8269e28175409b632258233eed5c243 Mon Sep 17 00:00:00 2001 From: aminbenmansour Date: Wed, 1 Nov 2023 15:56:50 +0100 Subject: [PATCH 41/49] docs(list): openapi acdc listing request --- .../id/walt/web/controllers/AcdcController.kt | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/main/kotlin/id/walt/web/controllers/AcdcController.kt b/src/main/kotlin/id/walt/web/controllers/AcdcController.kt index 1fb4383..ee668ca 100644 --- a/src/main/kotlin/id/walt/web/controllers/AcdcController.kt +++ b/src/main/kotlin/id/walt/web/controllers/AcdcController.kt @@ -247,6 +247,30 @@ fun Application.acdc() = walletRoute { get("list/keystore/{keystore}/alias/{alias}", { summary = "List credentials and check mailboxes for any newly issued credentials" + request { + pathParameter("keystore") { + description = "keystore name and file location of KERI keystore" + example = "waltid" + } + + pathParameter("alias") { + description = "human readable alias for the identifier to whom the credential was issued" + example = "waltid-alias" + } + + body { + description = "Required data for listing an ACDC" + example("application/json", AcdcList( + passcode = "0123456789abcdefghijk", + verbose = false, + poll = false, + issued = false, + said = false, + schema = false + )) + } + } + }) { val keystore = call.parameters["keystore"] ?: return@get call.respond(HttpStatusCode.BadRequest) val alias = call.parameters["alias"] ?: return@get call.respond(HttpStatusCode.BadRequest) From 06820adb8fa229816b87029950ef5dfe0b6b4af2 Mon Sep 17 00:00:00 2001 From: aminbenmansour Date: Wed, 1 Nov 2023 16:49:47 +0100 Subject: [PATCH 42/49] feat(revoke): implement revocation mechanism --- .../service/dto/AcdcManagemementObjects.kt | 5 +++ .../service/keri/AcdcManagementService.kt | 33 +++++++++++++++-- .../interfaces/AcdcManagementInterface.kt | 4 +- .../id/walt/web/controllers/AcdcController.kt | 37 +++++++++++++++++++ 4 files changed, 74 insertions(+), 5 deletions(-) diff --git a/src/main/kotlin/id/walt/service/dto/AcdcManagemementObjects.kt b/src/main/kotlin/id/walt/service/dto/AcdcManagemementObjects.kt index 1c6cb38..6a1501e 100644 --- a/src/main/kotlin/id/walt/service/dto/AcdcManagemementObjects.kt +++ b/src/main/kotlin/id/walt/service/dto/AcdcManagemementObjects.kt @@ -61,6 +61,11 @@ data class AcdcList ( val schema: Boolean = false, ) +@Serializable +data class AcdcRevoke ( + val passcode: String, + val said: String +) enum class IPEX_EVENT(val type: String) { APPLY("apply"), OFFER("offer"), diff --git a/src/main/kotlin/id/walt/service/keri/AcdcManagementService.kt b/src/main/kotlin/id/walt/service/keri/AcdcManagementService.kt index 354198b..9a66dd8 100644 --- a/src/main/kotlin/id/walt/service/keri/AcdcManagementService.kt +++ b/src/main/kotlin/id/walt/service/keri/AcdcManagementService.kt @@ -78,9 +78,36 @@ class AcdcManagementService: AcdcManagementInterface { registry: String, passcode: String, said: String, - send: String, - time: String + send: String?, + time: String? ) { - TODO("Not yet implemented") + + val command: MutableList = mutableListOf( + "kli", "vc", + "revoke", + "--name", keystore, + "--alias", alias, + "--registry", registry, + "--passcode", passcode, + "--said", said + ) + + try { + val processBuilder = ProcessBuilder(command) + val process = processBuilder.start() + + val errorReader = BufferedReader(InputStreamReader(process.errorStream)) + var errorLine: String? + while (errorReader.readLine().also { errorLine = it } != null) { + System.err.println(errorLine) + } + process.waitFor() + + } catch(e: IOException) { + e.printStackTrace() + } catch (e: InterruptedException) { + e.printStackTrace() + } + } } \ No newline at end of file diff --git a/src/main/kotlin/id/walt/service/keri/interfaces/AcdcManagementInterface.kt b/src/main/kotlin/id/walt/service/keri/interfaces/AcdcManagementInterface.kt index 2c9f7c5..d34d660 100644 --- a/src/main/kotlin/id/walt/service/keri/interfaces/AcdcManagementInterface.kt +++ b/src/main/kotlin/id/walt/service/keri/interfaces/AcdcManagementInterface.kt @@ -40,6 +40,6 @@ interface AcdcManagementInterface { registry: String, passcode: String, said: String, - send: String, - time: String) + send: String?, + time: String?) } \ No newline at end of file diff --git a/src/main/kotlin/id/walt/web/controllers/AcdcController.kt b/src/main/kotlin/id/walt/web/controllers/AcdcController.kt index ee668ca..56b6504 100644 --- a/src/main/kotlin/id/walt/web/controllers/AcdcController.kt +++ b/src/main/kotlin/id/walt/web/controllers/AcdcController.kt @@ -242,6 +242,43 @@ fun Application.acdc() = walletRoute { call.respond(HttpStatusCode.NoContent) } + delete("revoke/keystore/{keystore}/alias/{alias}/registry/{registry}", { + summary = "Revoke an ACDC" + + request { + pathParameter("keystore") { + description = "keystore name and file location of KERI keystore" + example = "waltid" + } + + pathParameter("alias") { + description = "human readable alias for the new identifier prefix" + example = "waltid-alias" + } + + pathParameter("registry") { + description = "human readable name for registry, defaults to name of Habitat" + example = "waltid-registry" + } + + body { + description = "Required data for rejecting an event" + example("application/json", AcdcRevoke( + passcode = "0123456789abcdefghijk", + said = "EBfdlu8R27Fbx-ehrqwImnK-8Cm79sqbAQ4MmvEAYqao", + + )) + } + } + }) { + val keystore = call.parameters["keystore"] ?: return@delete call.respond(HttpStatusCode.BadRequest) + val alias = call.parameters["alias"] ?: return@delete call.respond(HttpStatusCode.BadRequest) + val registry = call.parameters["registry"] ?: return@delete call.respond(HttpStatusCode.BadRequest) + val dto = call.receive() + AcdcManagementService().revoke(keystore, alias, registry, dto.passcode, dto.said, null, null); + call.respond(HttpStatusCode.NoContent) + } + } get("list/keystore/{keystore}/alias/{alias}", { From 43efd622765e1616b8e79aa6a3e0ae6ffe23cefd Mon Sep 17 00:00:00 2001 From: aminbenmansour Date: Wed, 1 Nov 2023 16:59:01 +0100 Subject: [PATCH 43/49] fix(ipex): correct admit event --- src/main/kotlin/id/walt/service/dto/AcdcManagemementObjects.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/id/walt/service/dto/AcdcManagemementObjects.kt b/src/main/kotlin/id/walt/service/dto/AcdcManagemementObjects.kt index 6a1501e..11bfb58 100644 --- a/src/main/kotlin/id/walt/service/dto/AcdcManagemementObjects.kt +++ b/src/main/kotlin/id/walt/service/dto/AcdcManagemementObjects.kt @@ -71,5 +71,5 @@ enum class IPEX_EVENT(val type: String) { OFFER("offer"), AGREE("agree"), GRANT("grant"), - SUBMIT("submit") + ADMIT("admit") } \ No newline at end of file From 12b116c418ca9ed233a015ca320f84529663bc10 Mon Sep 17 00:00:00 2001 From: aminbenmansour Date: Wed, 1 Nov 2023 17:04:06 +0100 Subject: [PATCH 44/49] fix(list, spurn): correct CLI cmd --- src/main/kotlin/id/walt/service/keri/IpexService.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/id/walt/service/keri/IpexService.kt b/src/main/kotlin/id/walt/service/keri/IpexService.kt index 02bbb48..8f03f31 100644 --- a/src/main/kotlin/id/walt/service/keri/IpexService.kt +++ b/src/main/kotlin/id/walt/service/keri/IpexService.kt @@ -149,7 +149,7 @@ class IpexService: IpexInterface { val command: MutableList = mutableListOf( "kli", "ipex", - "grant", + "list", "--name", keystore, "--alias", alias, "--passcode", passcode, @@ -204,7 +204,7 @@ class IpexService: IpexInterface { override fun spurn(keystore: String, alias: String, passcode: String, said: String, message: String?) { val command: MutableList = mutableListOf( "kli", "ipex", - "admit", + "spurn", "--name", keystore, "--alias", alias, "--passcode", passcode, From 3a0a9e451f6a66e614f2edd63e285469ef342594 Mon Sep 17 00:00:00 2001 From: aminbenmansour Date: Wed, 1 Nov 2023 17:15:01 +0100 Subject: [PATCH 45/49] docs(postman): KERI collection Caveat: Incomplete --- postman/KERI.postman_collection.json | 155 +++++++++++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 postman/KERI.postman_collection.json diff --git a/postman/KERI.postman_collection.json b/postman/KERI.postman_collection.json new file mode 100644 index 0000000..c6fbf9b --- /dev/null +++ b/postman/KERI.postman_collection.json @@ -0,0 +1,155 @@ +{ + "info": { + "_postman_id": "a599ecc6-a7e7-4b95-9092-47c27d80a7b1", + "name": "KERI", + "schema": "https://schema.getpostman.com/json/collection/v2.0.0/collection.json", + "_exporter_id": "27540209" + }, + "item": [ + { + "name": "Create a DB and a keystore", + "request": { + "auth": { + "type": "bearer", + "bearer": { + "token": "ThFPtjWgjkWFmuHDiDd5o3GGqFlu_jjkkXJl2dOeo6E" + } + }, + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"passcode\": \"0123456789abcdefghijk\"\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": "http://127.0.0.1:4545/r/wallet/keri/db/waltid", + "description": "Create a DB and a Keystore and designating witnesses" + }, + "response": [] + }, + { + "name": "Create inception event and create and AID and a DID for KERI", + "request": { + "auth": { + "type": "bearer", + "bearer": { + "token": "fyQUzZSzMy7ZnCebBJmIv-aHl-8wTstQUY1KRc-zgGs" + } + }, + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"passcode\": \"0123456789abcdefghijk\",\n \"alias\": \"waltid-alias\"\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": "http://127.0.0.1:4545/r/wallet/keri/incept/waltid" + }, + "response": [] + }, + { + "name": "Registry", + "request": { + "auth": { + "type": "bearer", + "bearer": { + "token": "s7B9oBn-mxdNhicJamVTaX5NsWBZQZW58bDpREQuu0Q" + } + }, + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"passcode\": \"0123456789abcdefghijk\"\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": "http://127.0.0.1:4545/r/wallet/keri/keystore/waltid/alias/waltid-alias/registry/waltid-registry" + }, + "response": [] + }, + { + "name": "Witness OOBI resolution", + "request": { + "method": "GET", + "header": [], + "url": "http://127.0.0.1:5642/oobi/BBilc4-L3tFUnfM_wJr4S4OJanAv_VmF_dJNN6vkf2Ha" + }, + "response": [] + }, + { + "name": "Saidify", + "request": { + "auth": { + "type": "bearer", + "bearer": { + "token": "EaI7hP6e1XdXDDi25i_9HLdZnynZaH_fYM3KlM2mk6c" + } + }, + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"filename\": \"config/keri/acdc/data/rules/child-rule.json\"\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": "http://127.0.0.1:4545/r/wallet/acdc/saidify" + }, + "response": [] + }, + { + "name": "IPEX Apply", + "request": { + "method": "POST", + "header": [], + "url": "http://127.0.0.1:4545/r/wallet/acdc/ipex/apply" + }, + "response": [] + }, + { + "name": "IPEX Offer", + "request": { + "auth": { + "type": "bearer", + "bearer": { + "token": "SR6AkV1Gb9-LfGva-2Nsyj-HjGUerDxTmVV7_MmFQ7s" + } + }, + "method": "POST", + "header": [], + "url": "http://127.0.0.1:4545/r/wallet/acdc/ipex/offer" + }, + "response": [] + }, + { + "name": "IPEX Agree", + "request": { + "auth": { + "type": "bearer", + "bearer": { + "token": "SR6AkV1Gb9-LfGva-2Nsyj-HjGUerDxTmVV7_MmFQ7s" + } + }, + "method": "POST", + "header": [], + "url": "http://127.0.0.1:4545/r/wallet/acdc/ipex/agree" + }, + "response": [] + } + ] +} \ No newline at end of file From 24a7861fa054f2647cb9642b9a4bb1fb4108dd75 Mon Sep 17 00:00:00 2001 From: aminbenmansour Date: Wed, 1 Nov 2023 17:42:11 +0100 Subject: [PATCH 46/49] docs(demo): single acdc issuance full workflow --- .../config/keri/cf/demo-witness-oobis.json | 8 +++++ docs/keri/demo/data/inception-config.json | 13 ++++++++ docs/keri/demo/single-issuer.sh | 33 +++++++++++++++++++ 3 files changed, 54 insertions(+) create mode 100644 docs/keri/demo/config/keri/cf/demo-witness-oobis.json create mode 100644 docs/keri/demo/data/inception-config.json create mode 100644 docs/keri/demo/single-issuer.sh diff --git a/docs/keri/demo/config/keri/cf/demo-witness-oobis.json b/docs/keri/demo/config/keri/cf/demo-witness-oobis.json new file mode 100644 index 0000000..078b312 --- /dev/null +++ b/docs/keri/demo/config/keri/cf/demo-witness-oobis.json @@ -0,0 +1,8 @@ +{ + "dt": "2022-01-20T12:57:59.823350+00:00", + "iurls": [ + "http://127.0.0.1:5642/oobi/BBilc4-L3tFUnfM_wJr4S4OJanAv_VmF_dJNN6vkf2Ha/controller", + "http://127.0.0.1:5643/oobi/BLskRTInXnMxWaGqcpSyMgo0nYbalW99cGZESrz3zapM/controller", + "http://127.0.0.1:5644/oobi/BIKKuvBwpmDVA4Ds-EpL5bt9OqPzWPja2LigFYZN2YfX/controller" + ] +} \ No newline at end of file diff --git a/docs/keri/demo/data/inception-config.json b/docs/keri/demo/data/inception-config.json new file mode 100644 index 0000000..850aca0 --- /dev/null +++ b/docs/keri/demo/data/inception-config.json @@ -0,0 +1,13 @@ +{ + "transferable": true, + "wits": [ + "BBilc4-L3tFUnfM_wJr4S4OJanAv_VmF_dJNN6vkf2Ha", + "BLskRTInXnMxWaGqcpSyMgo0nYbalW99cGZESrz3zapM", + "BIKKuvBwpmDVA4Ds-EpL5bt9OqPzWPja2LigFYZN2YfX" + ], + "toad": 3, + "icount": 1, + "ncount": 1, + "isith": "1", + "nsith": "1" +} diff --git a/docs/keri/demo/single-issuer.sh b/docs/keri/demo/single-issuer.sh new file mode 100644 index 0000000..055628d --- /dev/null +++ b/docs/keri/demo/single-issuer.sh @@ -0,0 +1,33 @@ +#!/bin/bash + +kli init --name issuer --salt 0ACDEyMzQ1Njc4OWxtbm9aBc --nopasscode --config-dir config --config-file demo-witness-oobis +kli incept --name issuer --alias issuer --file data/inception-config.json + +kli init --name holder --salt 0ACDEyMzQ1Njc4OWxtbm9qWc --nopasscode --config-dir ${KERI_SCRIPT_DIR} --config-file demo-witness-oobis +kli incept --name holder --alias holder --file data/inception-config.json + +kli oobi resolve --name issuer --oobi-alias holder --oobi http://127.0.0.1:5642/oobi/ELjSFdrTdCebJlmvbFNX9-TLhR2PO0_60al1kQp5_e6k/witness/BBilc4-L3tFUnfM_wJr4S4OJanAv_VmF_dJNN6vkf2Ha +kli oobi resolve --name holder --oobi-alias issuer --oobi http://127.0.0.1:5642/oobi/EKxICWTx5Ph4EKq5xie2znZf7amggUn4Sd-2-46MIQTg/witness/BBilc4-L3tFUnfM_wJr4S4OJanAv_VmF_dJNN6vkf2Ha +kli oobi resolve --name issuer --oobi-alias issuer --oobi http://127.0.0.1:7723/oobi/EBfdlu8R27Fbx-ehrqwImnK-8Cm79sqbAQ4MmvEAYqao +kli oobi resolve --name holder --oobi-alias holder --oobi http://127.0.0.1:7723/oobi/EBfdlu8R27Fbx-ehrqwImnK-8Cm79sqbAQ4MmvEAYqao + +kli vc registry incept --name issuer --alias issuer --registry-name vLEI + +kli vc create --name issuer --alias issuer --registry-name vLEI --schema EBfdlu8R27Fbx-ehrqwImnK-8Cm79sqbAQ4MmvEAYqao --recipient ELjSFdrTdCebJlmvbFNX9-TLhR2PO0_60al1kQp5_e6k --data @${KERI_DEMO_SCRIPT_DIR}/data/credential-data.json +SAID=$(kli vc list --name issuer --alias issuer --issued --said --schema EBfdlu8R27Fbx-ehrqwImnK-8Cm79sqbAQ4MmvEAYqao) + +kli ipex grant --name issuer --alias issuer --said "${SAID}" --recipient ELjSFdrTdCebJlmvbFNX9-TLhR2PO0_60al1kQp5_e6k + +echo "Checking holder for grant messages..." +GRANT=$(kli ipex list --name holder --alias holder --poll --said) + +echo "Admitting credential from grant ${GRANT}" +kli ipex admit --name holder --alias holder --said "${GRANT}" + +kli vc list --name holder --alias holder + +exit 0 + +kli vc revoke --name issuer --alias issuer --registry-name vLEI --said "${SAID}" +sleep 2 +kli vc list --name holder --alias holder --poll From bc43af5ebbcb9cbaa54f8aa0947483e595f30faf Mon Sep 17 00:00:00 2001 From: aminbenmansour Date: Wed, 1 Nov 2023 19:39:02 +0100 Subject: [PATCH 47/49] docs(demo): fix script and provide output --- .../config/keri/cf/demo-witness-oobis.json | 0 docs/keri/demo/output.txt | 47 +++++++++++++++++++ docs/keri/demo/single-issuer.sh | 2 +- 3 files changed, 48 insertions(+), 1 deletion(-) mode change 100644 => 100755 docs/keri/demo/config/keri/cf/demo-witness-oobis.json create mode 100644 docs/keri/demo/output.txt mode change 100644 => 100755 docs/keri/demo/single-issuer.sh diff --git a/docs/keri/demo/config/keri/cf/demo-witness-oobis.json b/docs/keri/demo/config/keri/cf/demo-witness-oobis.json old mode 100644 new mode 100755 diff --git a/docs/keri/demo/output.txt b/docs/keri/demo/output.txt new file mode 100644 index 0000000..5569d60 --- /dev/null +++ b/docs/keri/demo/output.txt @@ -0,0 +1,47 @@ +KERI Keystore created at: /home/amin/.keri/ks/issuer +KERI Database created at: /home/amin/.keri/db/issuer +KERI Credential Store created at: /home/amin/.keri/reg/issuer + +Loading 3 OOBIs... +http://127.0.0.1:5642/oobi/BBilc4-L3tFUnfM_wJr4S4OJanAv_VmF_dJNN6vkf2Ha/controller succeeded +http://127.0.0.1:5643/oobi/BLskRTInXnMxWaGqcpSyMgo0nYbalW99cGZESrz3zapM/controller succeeded +http://127.0.0.1:5644/oobi/BIKKuvBwpmDVA4Ds-EpL5bt9OqPzWPja2LigFYZN2YfX/controller succeeded +Waiting for witness receipts... +Prefix EKxICWTx5Ph4EKq5xie2znZf7amggUn4Sd-2-46MIQTg + Public key 1: DLlce_MSqQukQgluGlcDjKzGKwrnYVHpaCXAo7y23SUD + +KERI Keystore created at: /home/amin/.keri/ks/holder +KERI Database created at: /home/amin/.keri/db/holder +KERI Credential Store created at: /home/amin/.keri/reg/holder + +Loading 3 OOBIs... +http://127.0.0.1:5642/oobi/BBilc4-L3tFUnfM_wJr4S4OJanAv_VmF_dJNN6vkf2Ha/controller succeeded +http://127.0.0.1:5643/oobi/BLskRTInXnMxWaGqcpSyMgo0nYbalW99cGZESrz3zapM/controller succeeded +http://127.0.0.1:5644/oobi/BIKKuvBwpmDVA4Ds-EpL5bt9OqPzWPja2LigFYZN2YfX/controller succeeded +Waiting for witness receipts... +Prefix ELjSFdrTdCebJlmvbFNX9-TLhR2PO0_60al1kQp5_e6k + Public key 1: DDj8Si7vYnYxXWsGP4Pr-BT2jbncKzsIALuiwmN6lPNr + +http://127.0.0.1:5642/oobi/ELjSFdrTdCebJlmvbFNX9-TLhR2PO0_60al1kQp5_e6k/witness/BBilc4-L3tFUnfM_wJr4S4OJanAv_VmF_dJNN6vkf2Ha resolved +http://127.0.0.1:5642/oobi/EKxICWTx5Ph4EKq5xie2znZf7amggUn4Sd-2-46MIQTg/witness/BBilc4-L3tFUnfM_wJr4S4OJanAv_VmF_dJNN6vkf2Ha resolved +http://127.0.0.1:7723/oobi/EBfdlu8R27Fbx-ehrqwImnK-8Cm79sqbAQ4MmvEAYqao resolved +http://127.0.0.1:7723/oobi/EBfdlu8R27Fbx-ehrqwImnK-8Cm79sqbAQ4MmvEAYqao resolved +Waiting for TEL event witness receipts +Sending TEL events to witnesses +Registry: vLEI(EBSf3xSpLop9Q3_ctgJ_X_VMrlyb3QTxrnt1MxjMSA_1) + created for Identifier Prefix: EKxICWTx5Ph4EKq5xie2znZf7amggUn4Sd-2-46MIQTg +Waiting for TEL event witness receipts +Sending TEL events to witnesses +EOk2C8RoI_gOt17Cee8PDZuMxtrpyOfCEl5n9sczXVzo has been created. +Sending message EPUi2CwJjcvkyqUkuPwziV4QETXHFAxkxQpiC6XJBywM to ELjSFdrTdCebJlmvbFNX9-TLhR2PO0_60al1kQp5_e6k +... grant message sent +Checking holder for grant messages... +Admitting credential from grant EPUi2CwJjcvkyqUkuPwziV4QETXHFAxkxQpiC6XJBywM +Sending admit message to EKxICWTx5Ph4EKq5xie2znZf7amggUn4Sd-2-46MIQTg +Current received credentials for holder (ELjSFdrTdCebJlmvbFNX9-TLhR2PO0_60al1kQp5_e6k): + +Credential #1: EOk2C8RoI_gOt17Cee8PDZuMxtrpyOfCEl5n9sczXVzo + Type: Qualified vLEI Issuer Credential + Status: Issued ✔ + Issued by EKxICWTx5Ph4EKq5xie2znZf7amggUn4Sd-2-46MIQTg + Issued on 2023-10-31T16:37:54.848251+00:00 diff --git a/docs/keri/demo/single-issuer.sh b/docs/keri/demo/single-issuer.sh old mode 100644 new mode 100755 index 055628d..dad2622 --- a/docs/keri/demo/single-issuer.sh +++ b/docs/keri/demo/single-issuer.sh @@ -3,7 +3,7 @@ kli init --name issuer --salt 0ACDEyMzQ1Njc4OWxtbm9aBc --nopasscode --config-dir config --config-file demo-witness-oobis kli incept --name issuer --alias issuer --file data/inception-config.json -kli init --name holder --salt 0ACDEyMzQ1Njc4OWxtbm9qWc --nopasscode --config-dir ${KERI_SCRIPT_DIR} --config-file demo-witness-oobis +kli init --name holder --salt 0ACDEyMzQ1Njc4OWxtbm9qWc --nopasscode --config-dir config --config-file demo-witness-oobis kli incept --name holder --alias holder --file data/inception-config.json kli oobi resolve --name issuer --oobi-alias holder --oobi http://127.0.0.1:5642/oobi/ELjSFdrTdCebJlmvbFNX9-TLhR2PO0_60al1kQp5_e6k/witness/BBilc4-L3tFUnfM_wJr4S4OJanAv_VmF_dJNN6vkf2Ha From 1fdea1b6df5bff2b9f1481fa82907a50a9bc6117 Mon Sep 17 00:00:00 2001 From: aminbenmansour Date: Wed, 1 Nov 2023 19:40:06 +0100 Subject: [PATCH 48/49] docs(keri): instructions on setup, running script and web wallet --- docs/keri/KERI.md | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 docs/keri/KERI.md diff --git a/docs/keri/KERI.md b/docs/keri/KERI.md new file mode 100644 index 0000000..98e84e6 --- /dev/null +++ b/docs/keri/KERI.md @@ -0,0 +1,37 @@ +# Key Event Receipt Infrastructure (KERI) and Authentic Chain Data Container (ACDC) +Installation and demo workflow +## Installation +Follow installations instructors in these repositories +1. Install python KERI implementation from WebOfTrust [keripy](https://github.com/WebOfTrust/keripy). +2. Install [vLEI server](https://github.com/WebOfTrust/vLEI) from WebOfTrust (To promulgate ACDC OOBIs). + +## Pre-requisites +In order to run the project you must +1. Run demo witnesses provided by KERI in a separate terminal +```bash +kli witness demo +``` +2. Run vLEI server. vLEI server repository provides sample schemas, credentials and OOBIs, we can use them or provide our own data. In the root directory of vLEI server run: + +```bash +vLEI-server -s ./schema/acdc -c ./samples/acdc/ -o ./samples/oobis/ +``` +## Launch demo script +1. Demo script provides a full workflow that + 1. Incept controllers + 2. Resolve OOBIs + 3. Create a credential + 4. Issue and list ACDC credential + 5. Revocation script +2. Run command: +```bash +cd docs/keri/demo/;./single-issuer.sh +``` + + +## Launch waltid-web-wallet + +3. In the root directory of waltid-web-wallet +```bash + ./gradlew build && ./gradlew run +``` \ No newline at end of file From 01c1dc24eb1cc85d2bd80ea07e4b6dd1590f796b Mon Sep 17 00:00:00 2001 From: aminbenmansour Date: Wed, 1 Nov 2023 19:48:13 +0100 Subject: [PATCH 49/49] docs(keri): add caveat: clean file system --- docs/keri/KERI.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/keri/KERI.md b/docs/keri/KERI.md index 98e84e6..ca88696 100644 --- a/docs/keri/KERI.md +++ b/docs/keri/KERI.md @@ -16,6 +16,15 @@ kli witness demo ```bash vLEI-server -s ./schema/acdc -c ./samples/acdc/ -o ./samples/oobis/ ``` +### Caveat: Deleting Database Directories +KERIpy core library manages database directories for key event log, transaction event log, credential and private key storage. +The library will create the directories in local file system. + +Demo script was written expecting a clean database. Relaunch witnesses before running scripts through the following command +```bash +rm -rf $HOME/.keri/*;kli witness demo +``` + ## Launch demo script 1. Demo script provides a full workflow that 1. Incept controllers