From b81f786f14aff2d20fbeadd9e229fa2724c72e2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ribo=CC=81?= Date: Fri, 27 Jan 2023 10:29:37 +0100 Subject: [PATCH 01/10] Adding Agent errors to Domain. --- .../models/Errors.kt | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/domain/src/commonMain/kotlin/io.iohk.atala.prism.domain/models/Errors.kt b/domain/src/commonMain/kotlin/io.iohk.atala.prism.domain/models/Errors.kt index 3cce7c460..161ad3ebb 100644 --- a/domain/src/commonMain/kotlin/io.iohk.atala.prism.domain/models/Errors.kt +++ b/domain/src/commonMain/kotlin/io.iohk.atala.prism.domain/models/Errors.kt @@ -47,3 +47,28 @@ sealed class PlutoError(message: String? = null) : Throwable(message) { sealed class PolluxError(message: String? = null) : Throwable(message) { class InvalidCredentialError(message: String? = null) : PolluxError(message) } + +sealed class PrismAgentError(message: String? = null) : Throwable(message) { + class invalidURLError(message: String? = null) : PrismAgentError(message) + class cannotFindDIDKeyPairIndex(message: String? = null) : PrismAgentError(message) + class invitationHasNoFromDIDError(message: String? = null) : PrismAgentError(message) + class noValidServiceEndpointError(message: String? = null) : PrismAgentError(message) + class invitationIsInvalidError(message: String? = null) : PrismAgentError(message) + class noConnectionOpenError(message: String? = null) : PrismAgentError(message) + class noHandshakeResponseError(message: String? = null) : PrismAgentError(message) + class unknownInvitationTypeError(message: String? = null) : PrismAgentError(message) + class unknownPrismOnboardingTypeError(message: String? = null) : PrismAgentError(message) + class failedToOnboardError(message: String? = null) : PrismAgentError(message) + class invalidPickupDeliveryMessageError(message: String? = null) : PrismAgentError(message) + class invalidOfferCredentialMessageError(message: String? = null) : PrismAgentError(message) + class invalidProposedCredentialMessageError(message: String? = null) : PrismAgentError(message) + class invalidIssueCredentialMessageError(message: String? = null) : PrismAgentError(message) + class invalidRequestCredentialMessageError(message: String? = null) : PrismAgentError(message) + class invalidPresentationMessageError(message: String? = null) : PrismAgentError(message) + class invalidRequestPresentationMessageError(message: String? = null) : PrismAgentError(message) + class invalidProposePresentationMessageError(message: String? = null) : PrismAgentError(message) + class invalidMediationGrantMessageError(message: String? = null) : PrismAgentError(message) + class noMediatorAvailableError(message: String? = null) : PrismAgentError(message) + class mediationRequestFailedError(message: String? = null) : PrismAgentError(message) + +} \ No newline at end of file From cfe1a424d1203df939d594bdf4a319523bacc25c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ribo=CC=81?= Date: Fri, 27 Jan 2023 11:37:46 +0100 Subject: [PATCH 02/10] PrismEnterprise onboarding invitation parsing implementation. --- .../models/Errors.kt | 3 +- .../prism/walletsdk/prismagent/PrismAgent.kt | 42 +++++++++++++++++++ .../PrismOnboardingInvitation.kt | 24 +++++++++++ 3 files changed, 67 insertions(+), 2 deletions(-) create mode 100644 prism-agent/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/PrismOnboarding/PrismOnboardingInvitation.kt diff --git a/domain/src/commonMain/kotlin/io.iohk.atala.prism.domain/models/Errors.kt b/domain/src/commonMain/kotlin/io.iohk.atala.prism.domain/models/Errors.kt index 161ad3ebb..8378a3e6f 100644 --- a/domain/src/commonMain/kotlin/io.iohk.atala.prism.domain/models/Errors.kt +++ b/domain/src/commonMain/kotlin/io.iohk.atala.prism.domain/models/Errors.kt @@ -70,5 +70,4 @@ sealed class PrismAgentError(message: String? = null) : Throwable(message) { class invalidMediationGrantMessageError(message: String? = null) : PrismAgentError(message) class noMediatorAvailableError(message: String? = null) : PrismAgentError(message) class mediationRequestFailedError(message: String? = null) : PrismAgentError(message) - -} \ No newline at end of file +} diff --git a/prism-agent/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/PrismAgent.kt b/prism-agent/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/PrismAgent.kt index 317499159..7a4a88ce5 100644 --- a/prism-agent/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/PrismAgent.kt +++ b/prism-agent/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/PrismAgent.kt @@ -6,7 +6,9 @@ import io.iohk.atala.prism.domain.buildingBlocks.Pluto import io.iohk.atala.prism.domain.models.DID import io.iohk.atala.prism.domain.models.DIDDocument import io.iohk.atala.prism.domain.models.KeyCurve +import io.iohk.atala.prism.domain.models.PrismAgentError import io.iohk.atala.prism.domain.models.Seed +import io.iohk.atala.prism.walletsdk.prismagent.protocols.PrismOnboarding.PrismOnboardingInvitation import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.map @@ -15,6 +17,12 @@ final class PrismAgent { STOPED, STARTING, RUNNING, STOPING } + sealed class InvitationType { + class PrismOnboarding(val from: String, val endpoint: String, val ownDID: DID) + + data class OnboardingPrism(val prismOnboarding: PrismOnboarding) : InvitationType() + } + val seed: Seed var state = State.STOPED @@ -72,4 +80,38 @@ final class PrismAgent { return did } + + @Throws(PrismAgentError.unknownInvitationTypeError::class) + suspend fun parseInvitation(str: String): InvitationType { + return try { + InvitationType.OnboardingPrism(parsePrismInvitation(str)) + } catch (e: Throwable) { + throw PrismAgentError.unknownInvitationTypeError() + } + } + + private suspend fun parsePrismInvitation(str: String): InvitationType.PrismOnboarding { + val prismOnboarding = PrismOnboardingInvitation(str) + val url = prismOnboarding.body.onboardEndpoint + val did = createNewPeerDID( + arrayOf( + DIDDocument.Service( + id = "#didcomm-1", + type = arrayOf("DIDCommMessaging"), + serviceEndpoint = DIDDocument.ServiceEndpoint( + uri = url, + accept = arrayOf("DIDCommMessaging"), + routingKeys = arrayOf() + ) + ) + ), + true + ) + + return InvitationType.PrismOnboarding( + from = prismOnboarding.body.from, + endpoint = url, + ownDID = did + ) + } } diff --git a/prism-agent/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/PrismOnboarding/PrismOnboardingInvitation.kt b/prism-agent/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/PrismOnboarding/PrismOnboardingInvitation.kt new file mode 100644 index 000000000..df9363bd2 --- /dev/null +++ b/prism-agent/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/PrismOnboarding/PrismOnboardingInvitation.kt @@ -0,0 +1,24 @@ +package io.iohk.atala.prism.walletsdk.prismagent.protocols.PrismOnboarding + +import io.iohk.atala.prism.domain.models.PrismAgentError +import kotlinx.serialization.decodeFromString +import kotlinx.serialization.json.Json + +class PrismOnboardingInvitation(jsonString: String) { + + data class Body( + val type: String, + val onboardEndpoint: String, + val from: String + ) + + var body: Body + + init { + body = try { + Json.decodeFromString(jsonString) + } catch (e: Throwable) { + throw PrismAgentError.invitationIsInvalidError() + } + } +} From e576df83ed202c02c5077669d1f26ebcec4939f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ribo=CC=81?= Date: Fri, 27 Jan 2023 12:08:14 +0100 Subject: [PATCH 03/10] add ktor 2.1.3 dependency --- prism-agent/build.gradle.kts | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/prism-agent/build.gradle.kts b/prism-agent/build.gradle.kts index 33a8f428c..68bbc783b 100644 --- a/prism-agent/build.gradle.kts +++ b/prism-agent/build.gradle.kts @@ -71,6 +71,11 @@ kotlin { implementation(project(":domain")) implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4") implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.4.1") + + implementation("io.ktor:ktor-client-core:2.1.3") + implementation("io.ktor:ktor-client-content-negotiation:2.1.3") + implementation("io.ktor:ktor-serialization-kotlinx-json:2.1.3") + implementation("io.ktor:ktor-client-logging:2.1.3") } } val commonTest by getting { @@ -80,10 +85,15 @@ kotlin { implementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.6.4") } } - val jvmMain by getting + val jvmMain by getting { + dependencies { + implementation("io.ktor:ktor-client-okhttp:2.1.3") + } + } val jvmTest by getting { dependencies { implementation("junit:junit:4.13.2") + implementation("io.ktor:ktor-client-mock:2.1.3") } } val androidMain by getting { @@ -96,10 +106,19 @@ kotlin { implementation("junit:junit:4.13.2") } } - val jsMain by getting + val jsMain by getting { + dependencies { + implementation("io.ktor:ktor-client-js:2.1.3") + implementation("io.ktor:ktor-client-content-negotiation:2.1.3") + implementation("io.ktor:ktor-serialization-kotlinx-json:2.1.3") + implementation(npm("abort-controller", "3.0.0")) + implementation(npm("node-fetch", "2.6.7")) + } + } val jsTest by getting all { + languageSettings.optIn("kotlin.js.ExperimentalJsExport") languageSettings.optIn("kotlin.RequiresOptIn") } } From 99b03506e82d35bbe0dc1aacf4bc3ba67138f7db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ribo=CC=81?= Date: Fri, 27 Jan 2023 13:21:59 +0100 Subject: [PATCH 04/10] Add commonMain expected httpClient and crease actuals in jvmMain, androidMain and jsMain --- prism-agent/build.gradle.kts | 2 ++ .../prism/walletsdk/prismagent/helpers/httpClient.kt | 9 +++++++++ .../prism/walletsdk/prismagent/helpers/httpClient.kt | 6 ++++++ .../prism/walletsdk/prismagent/helpers/httpClient.kt | 9 +++++++++ .../prism/walletsdk/prismagent/helpers/httpClient.kt | 9 +++++++++ 5 files changed, 35 insertions(+) create mode 100644 prism-agent/src/androidMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/helpers/httpClient.kt create mode 100644 prism-agent/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/helpers/httpClient.kt create mode 100644 prism-agent/src/jsMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/helpers/httpClient.kt create mode 100644 prism-agent/src/jvmMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/helpers/httpClient.kt diff --git a/prism-agent/build.gradle.kts b/prism-agent/build.gradle.kts index 68bbc783b..124d1bc01 100644 --- a/prism-agent/build.gradle.kts +++ b/prism-agent/build.gradle.kts @@ -94,11 +94,13 @@ kotlin { dependencies { implementation("junit:junit:4.13.2") implementation("io.ktor:ktor-client-mock:2.1.3") + implementation(kotlin("test")) } } val androidMain by getting { dependencies { implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4") + implementation("io.ktor:ktor-client-okhttp:2.1.3") } } val androidTest by getting { diff --git a/prism-agent/src/androidMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/helpers/httpClient.kt b/prism-agent/src/androidMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/helpers/httpClient.kt new file mode 100644 index 000000000..c8ead80d0 --- /dev/null +++ b/prism-agent/src/androidMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/helpers/httpClient.kt @@ -0,0 +1,9 @@ +package io.iohk.atala.prism.walletsdk.prismagent.helpers + +import io.ktor.client.HttpClient +import io.ktor.client.HttpClientConfig +import io.ktor.client.engine.okhttp.OkHttp + +internal actual fun httpClient(config: HttpClientConfig<*>.() -> Unit) = HttpClient(OkHttp) { + config(this) +} diff --git a/prism-agent/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/helpers/httpClient.kt b/prism-agent/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/helpers/httpClient.kt new file mode 100644 index 000000000..775ebc46e --- /dev/null +++ b/prism-agent/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/helpers/httpClient.kt @@ -0,0 +1,6 @@ +package io.iohk.atala.prism.walletsdk.prismagent.helpers + +import io.ktor.client.HttpClient +import io.ktor.client.HttpClientConfig + +internal expect fun httpClient(config: HttpClientConfig<*>.() -> Unit = {}): HttpClient diff --git a/prism-agent/src/jsMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/helpers/httpClient.kt b/prism-agent/src/jsMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/helpers/httpClient.kt new file mode 100644 index 000000000..ec66adf1d --- /dev/null +++ b/prism-agent/src/jsMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/helpers/httpClient.kt @@ -0,0 +1,9 @@ +package io.iohk.atala.prism.walletsdk.prismagent.helpers + +import io.ktor.client.HttpClient +import io.ktor.client.HttpClientConfig +import io.ktor.client.engine.js.Js + +internal actual fun httpClient(config: HttpClientConfig<*>.() -> Unit) = HttpClient(Js) { + config(this) +} diff --git a/prism-agent/src/jvmMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/helpers/httpClient.kt b/prism-agent/src/jvmMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/helpers/httpClient.kt new file mode 100644 index 000000000..c8ead80d0 --- /dev/null +++ b/prism-agent/src/jvmMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/helpers/httpClient.kt @@ -0,0 +1,9 @@ +package io.iohk.atala.prism.walletsdk.prismagent.helpers + +import io.ktor.client.HttpClient +import io.ktor.client.HttpClientConfig +import io.ktor.client.engine.okhttp.OkHttp + +internal actual fun httpClient(config: HttpClientConfig<*>.() -> Unit) = HttpClient(OkHttp) { + config(this) +} From 7792f137682a834a6c5e799f11fb1acad57fd84b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ribo=CC=81?= Date: Fri, 27 Jan 2023 13:22:38 +0100 Subject: [PATCH 05/10] Implement basic re-usable httpClient for onboarding and authenticate + integrate it in acceptPrismInvitation. --- .../prism/walletsdk/prismagent/PrismAgent.kt | 21 +++++ .../prism/walletsdk/prismagent/helpers/Api.kt | 83 +++++++++++++++++++ 2 files changed, 104 insertions(+) create mode 100644 prism-agent/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/helpers/Api.kt diff --git a/prism-agent/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/PrismAgent.kt b/prism-agent/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/PrismAgent.kt index 7a4a88ce5..4db7ff96b 100644 --- a/prism-agent/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/PrismAgent.kt +++ b/prism-agent/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/PrismAgent.kt @@ -8,9 +8,13 @@ import io.iohk.atala.prism.domain.models.DIDDocument import io.iohk.atala.prism.domain.models.KeyCurve import io.iohk.atala.prism.domain.models.PrismAgentError import io.iohk.atala.prism.domain.models.Seed +import io.iohk.atala.prism.walletsdk.prismagent.helpers.Api import io.iohk.atala.prism.walletsdk.prismagent.protocols.PrismOnboarding.PrismOnboardingInvitation +import io.ktor.http.HttpMethod +import io.ktor.http.Url import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.map +import kotlinx.serialization.Serializable final class PrismAgent { enum class State { @@ -90,6 +94,23 @@ final class PrismAgent { } } + suspend fun acceptInvitation(invitation: InvitationType.PrismOnboarding) { + @Serializable + data class SendDID(val did: String) + + var response = Api().request( + HttpMethod.Post, + Url(invitation.endpoint), + mapOf(), + mapOf(), + SendDID(invitation.ownDID.toString()) + ) + + if (response.status.value != 200) { + throw PrismAgentError.failedToOnboardError() + } + } + private suspend fun parsePrismInvitation(str: String): InvitationType.PrismOnboarding { val prismOnboarding = PrismOnboardingInvitation(str) val url = prismOnboarding.body.onboardEndpoint diff --git a/prism-agent/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/helpers/Api.kt b/prism-agent/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/helpers/Api.kt new file mode 100644 index 000000000..2d383fdbe --- /dev/null +++ b/prism-agent/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/helpers/Api.kt @@ -0,0 +1,83 @@ +package io.iohk.atala.prism.walletsdk.prismagent.helpers + +import io.ktor.client.HttpClient +import io.ktor.client.plugins.contentnegotiation.ContentNegotiation +import io.ktor.client.request.prepareRequest +import io.ktor.client.request.setBody +import io.ktor.client.statement.HttpResponse +import io.ktor.client.statement.HttpStatement +import io.ktor.http.ContentType +import io.ktor.http.HttpHeaders +import io.ktor.http.HttpMethod +import io.ktor.http.Url +import io.ktor.http.contentType +import io.ktor.http.path +import io.ktor.serialization.kotlinx.json.json +import kotlinx.coroutines.DelicateCoroutinesApi +import kotlinx.serialization.json.Json + +@DelicateCoroutinesApi +class Api { + private val client: HttpClient = httpClient { + install(ContentNegotiation) { + json( + Json { + ignoreUnknownKeys = true + prettyPrint = true + isLenient = true + } + ) + } + expectSuccess = true + } + private suspend fun prepareRequest( + httpMethod: HttpMethod, + url: Url, + urlParameters: Map = mapOf(), + httpHeaders: Map = mapOf(), + body: Any? = null + ): HttpStatement { + + return client.prepareRequest { + for (header in httpHeaders) { + if ( + httpMethod == HttpMethod.Get && + header.key == HttpHeaders.ContentType && + header.value.contains(ContentType.Application.Json.contentSubtype) + ) { + continue + } + headers.append(header.key, header.value) + } + + contentType(ContentType.Application.Json) + + body?.let { + setBody(body) + } + + url { + method = httpMethod + protocol = url.protocol + host = url.host + port = url.specifiedPort + + path(url.encodedPath) + + for (parameter in urlParameters) { + parameters.append(parameter.key, parameter.value) + } + } + } + } + + suspend fun request( + httpMethod: HttpMethod, + url: Url, + urlParameters: Map = mapOf(), + httpHeaders: Map = mapOf(), + body: Any? = null + ): HttpResponse { + return prepareRequest(httpMethod, url, urlParameters, httpHeaders, body).execute() + } +} From bf2c4210aac96cce09ae032126ce656a6dc61e6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ribo=CC=81?= Date: Fri, 27 Jan 2023 14:45:46 +0100 Subject: [PATCH 06/10] Add Http mock for Agent and implement basic unit testing. --- prism-agent/build.gradle.kts | 1 + .../prism/walletsdk/prismagent/PrismAgent.kt | 23 ++++----- .../prism/walletsdk/prismagent/helpers/Api.kt | 5 +- .../PrismOnboardingInvitation.kt | 9 +++- .../walletsdk/prismagent/AgentApiMock.kt | 11 +++++ .../prism/walletsdk/prismagent/ApiMock.kt | 39 +++++++++++++++ .../prism/walletsdk/prismagent/CastorMock.kt | 2 +- .../walletsdk/prismagent/PrismAgentTests.kt | 48 +++++++++++++++++++ 8 files changed, 123 insertions(+), 15 deletions(-) create mode 100644 prism-agent/src/commonTest/kotlin/io/iohk/atala/prism/walletsdk/prismagent/AgentApiMock.kt create mode 100644 prism-agent/src/commonTest/kotlin/io/iohk/atala/prism/walletsdk/prismagent/ApiMock.kt diff --git a/prism-agent/build.gradle.kts b/prism-agent/build.gradle.kts index 124d1bc01..edf550788 100644 --- a/prism-agent/build.gradle.kts +++ b/prism-agent/build.gradle.kts @@ -83,6 +83,7 @@ kotlin { implementation(project(":domain")) implementation(kotlin("test")) implementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.6.4") + implementation("io.ktor:ktor-client-mock:2.1.3") } } val jvmMain by getting { diff --git a/prism-agent/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/PrismAgent.kt b/prism-agent/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/PrismAgent.kt index 4db7ff96b..84738f84d 100644 --- a/prism-agent/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/PrismAgent.kt +++ b/prism-agent/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/PrismAgent.kt @@ -16,16 +16,14 @@ import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.map import kotlinx.serialization.Serializable -final class PrismAgent { +open class PrismAgent { enum class State { STOPED, STARTING, RUNNING, STOPING } - sealed class InvitationType { - class PrismOnboarding(val from: String, val endpoint: String, val ownDID: DID) + sealed class InvitationType - data class OnboardingPrism(val prismOnboarding: PrismOnboarding) : InvitationType() - } + data class PrismOnboardingInvitation(val from: String, val endpoint: String, val ownDID: DID) : InvitationType() val seed: Seed var state = State.STOPED @@ -33,6 +31,7 @@ final class PrismAgent { private val apollo: Apollo private val castor: Castor private val pluto: Pluto + open val api: Api = Api() constructor( apollo: Apollo, @@ -87,18 +86,20 @@ final class PrismAgent { @Throws(PrismAgentError.unknownInvitationTypeError::class) suspend fun parseInvitation(str: String): InvitationType { - return try { - InvitationType.OnboardingPrism(parsePrismInvitation(str)) + val invite = try { + parsePrismInvitation(str) } catch (e: Throwable) { + println(e) throw PrismAgentError.unknownInvitationTypeError() } + return invite } - suspend fun acceptInvitation(invitation: InvitationType.PrismOnboarding) { + suspend fun acceptInvitation(invitation: PrismOnboardingInvitation) { @Serializable data class SendDID(val did: String) - var response = Api().request( + var response = api.request( HttpMethod.Post, Url(invitation.endpoint), mapOf(), @@ -111,7 +112,7 @@ final class PrismAgent { } } - private suspend fun parsePrismInvitation(str: String): InvitationType.PrismOnboarding { + private suspend fun parsePrismInvitation(str: String): PrismOnboardingInvitation { val prismOnboarding = PrismOnboardingInvitation(str) val url = prismOnboarding.body.onboardEndpoint val did = createNewPeerDID( @@ -129,7 +130,7 @@ final class PrismAgent { true ) - return InvitationType.PrismOnboarding( + return PrismOnboardingInvitation( from = prismOnboarding.body.from, endpoint = url, ownDID = did diff --git a/prism-agent/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/helpers/Api.kt b/prism-agent/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/helpers/Api.kt index 2d383fdbe..5e9d15d3b 100644 --- a/prism-agent/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/helpers/Api.kt +++ b/prism-agent/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/helpers/Api.kt @@ -17,7 +17,7 @@ import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.serialization.json.Json @DelicateCoroutinesApi -class Api { +open class Api( private val client: HttpClient = httpClient { install(ContentNegotiation) { json( @@ -28,8 +28,9 @@ class Api { } ) } - expectSuccess = true } +) { + private suspend fun prepareRequest( httpMethod: HttpMethod, url: Url, diff --git a/prism-agent/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/PrismOnboarding/PrismOnboardingInvitation.kt b/prism-agent/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/PrismOnboarding/PrismOnboardingInvitation.kt index df9363bd2..b181fc1be 100644 --- a/prism-agent/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/PrismOnboarding/PrismOnboardingInvitation.kt +++ b/prism-agent/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/PrismOnboarding/PrismOnboardingInvitation.kt @@ -1,11 +1,13 @@ package io.iohk.atala.prism.walletsdk.prismagent.protocols.PrismOnboarding import io.iohk.atala.prism.domain.models.PrismAgentError +import kotlinx.serialization.Serializable import kotlinx.serialization.decodeFromString import kotlinx.serialization.json.Json class PrismOnboardingInvitation(jsonString: String) { + @Serializable data class Body( val type: String, val onboardEndpoint: String, @@ -15,8 +17,13 @@ class PrismOnboardingInvitation(jsonString: String) { var body: Body init { + val json = Json { + ignoreUnknownKeys = true + prettyPrint = true + isLenient = true + } body = try { - Json.decodeFromString(jsonString) + json.decodeFromString(jsonString) } catch (e: Throwable) { throw PrismAgentError.invitationIsInvalidError() } diff --git a/prism-agent/src/commonTest/kotlin/io/iohk/atala/prism/walletsdk/prismagent/AgentApiMock.kt b/prism-agent/src/commonTest/kotlin/io/iohk/atala/prism/walletsdk/prismagent/AgentApiMock.kt new file mode 100644 index 000000000..543ec810f --- /dev/null +++ b/prism-agent/src/commonTest/kotlin/io/iohk/atala/prism/walletsdk/prismagent/AgentApiMock.kt @@ -0,0 +1,11 @@ +package io.iohk.atala.prism.walletsdk.prismagent + +import io.iohk.atala.prism.walletsdk.prismagent.helpers.Api +import io.ktor.http.HttpStatusCode + +class AgentApiMock( + statusCode: HttpStatusCode, + response: String +) : PrismAgent(ApolloMock(), CastorMock(), PlutoMock()) { + override val api: Api = ApiMock(statusCode, response) +} diff --git a/prism-agent/src/commonTest/kotlin/io/iohk/atala/prism/walletsdk/prismagent/ApiMock.kt b/prism-agent/src/commonTest/kotlin/io/iohk/atala/prism/walletsdk/prismagent/ApiMock.kt new file mode 100644 index 000000000..75dc113cb --- /dev/null +++ b/prism-agent/src/commonTest/kotlin/io/iohk/atala/prism/walletsdk/prismagent/ApiMock.kt @@ -0,0 +1,39 @@ +package io.iohk.atala.prism.walletsdk.prismagent + +import io.iohk.atala.prism.walletsdk.prismagent.helpers.Api +import io.ktor.client.HttpClient +import io.ktor.client.engine.mock.MockEngine +import io.ktor.client.engine.mock.respond +import io.ktor.client.plugins.contentnegotiation.ContentNegotiation +import io.ktor.http.HttpHeaders +import io.ktor.http.HttpStatusCode +import io.ktor.http.headersOf +import io.ktor.serialization.kotlinx.json.json +import kotlinx.coroutines.DelicateCoroutinesApi +import kotlinx.serialization.json.Json + +@OptIn(DelicateCoroutinesApi::class) +class ApiMock : Api { + + constructor(statusCode: HttpStatusCode, response: String) : super( + HttpClient( + engine = MockEngine { _ -> + respond( + content = response, + status = statusCode, + headers = headersOf(HttpHeaders.ContentType, "application/json") + ) + } + ) { + install(ContentNegotiation) { + json( + Json { + ignoreUnknownKeys = true + prettyPrint = true + isLenient = true + } + ) + } + } + ) +} diff --git a/prism-agent/src/commonTest/kotlin/io/iohk/atala/prism/walletsdk/prismagent/CastorMock.kt b/prism-agent/src/commonTest/kotlin/io/iohk/atala/prism/walletsdk/prismagent/CastorMock.kt index 140cde168..c4fb92740 100644 --- a/prism-agent/src/commonTest/kotlin/io/iohk/atala/prism/walletsdk/prismagent/CastorMock.kt +++ b/prism-agent/src/commonTest/kotlin/io/iohk/atala/prism/walletsdk/prismagent/CastorMock.kt @@ -9,7 +9,7 @@ import io.iohk.atala.prism.domain.models.PublicKey class CastorMock : Castor { var parseDIDReturn: DID? = null var createPrismDIDReturn: DID? = null - var createPeerDIDReturn: DID? = null + var createPeerDIDReturn: DID? = DID("did", "prism", "b6c0c33d701ac1b9a262a14454d1bbde3d127d697a76950963c5fd930605:Cj8KPRI7CgdtYXN0ZXIwEAFKLgoJc2VmsxEiECSTjyV7sUfCr_ArpN9rvCwR9fRMAhcsr_S7ZRiJk4p5k") var resolveDIDReturn: DIDDocument? = null var verifySignatureReturn: Boolean = false diff --git a/prism-agent/src/commonTest/kotlin/io/iohk/atala/prism/walletsdk/prismagent/PrismAgentTests.kt b/prism-agent/src/commonTest/kotlin/io/iohk/atala/prism/walletsdk/prismagent/PrismAgentTests.kt index 65237440b..dc64d6e86 100644 --- a/prism-agent/src/commonTest/kotlin/io/iohk/atala/prism/walletsdk/prismagent/PrismAgentTests.kt +++ b/prism-agent/src/commonTest/kotlin/io/iohk/atala/prism/walletsdk/prismagent/PrismAgentTests.kt @@ -1,10 +1,13 @@ package io.iohk.atala.prism.walletsdk.prismagent import io.iohk.atala.prism.domain.models.DID +import io.iohk.atala.prism.domain.models.PrismAgentError import io.iohk.atala.prism.domain.models.Seed +import io.ktor.http.HttpStatusCode import kotlinx.coroutines.test.runTest import kotlin.test.Test import kotlin.test.assertEquals +import kotlin.test.assertFailsWith @OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class) class PrismAgentTests { @@ -41,4 +44,49 @@ class PrismAgentTests { assertEquals(newDID, validDID) assertEquals(newDID, plutoMock.storedPeerDID.first()) } + + @Test + fun testPrismAgentOnboardingInvitation_shouldAcceptOnboardingInvitation_whenStatusIs200() = runTest { + var agent = AgentApiMock(HttpStatusCode.OK, "{\"success\":\"true\"}") + var invitationString = """ + { + "type":"Onboarding", + "onboardEndpoint":"http://localhost/onboarding", + "from":"did:prism:b6c0c33d701ac1b9a262a14454d1bbde3d127d697a76950963c5fd930605:Cj8KPRI7CgdtYXN0ZXIwEAFKLgoJc2VmsxEiECSTjyV7sUfCr_ArpN9rvCwR9fRMAhcsr_S7ZRiJk4p5k" + } + """ + val invitation = agent.parseInvitation(invitationString) + agent.acceptInvitation(invitation as PrismAgent.PrismOnboardingInvitation) + } + + @Test + fun testPrismAgentOnboardingInvitation_shouldRejectOnboardingInvitation_whenStatusIsNot200() = runTest { + var agent = AgentApiMock(HttpStatusCode.BadRequest, "{\"success\":\"true\"}") + var invitationString = """ + { + "type":"Onboarding", + "onboardEndpoint":"http://localhost/onboarding", + "from":"did:prism:b6c0c33d701ac1b9a262a14454d1bbde3d127d697a76950963c5fd930605:Cj8KPRI7CgdtYXN0ZXIwEAFKLgoJc2VmsxEiECSTjyV7sUfCr_ArpN9rvCwR9fRMAhcsr_S7ZRiJk4p5k" + } + """ + val invitation = agent.parseInvitation(invitationString) + assertFailsWith { + agent.acceptInvitation(invitation as PrismAgent.PrismOnboardingInvitation) + } + } + + @Test + fun testPrismAgentOnboardingInvitation_shouldRejectOnboardingInvitation_whenBodyIsWrong() = runTest { + var agent = AgentApiMock(HttpStatusCode.BadRequest, "{\"success\":\"true\"}") + var invitationString = """ + { + "type":"Onboarding", + "errorField":"http://localhost/onboarding", + "from":"did:prism:b6c0c33d701ac1b9a262a14454d1bbde3d127d697a76950963c5fd930605:Cj8KPRI7CgdtYXN0ZXIwEAFKLgoJc2VmsxEiECSTjyV7sUfCr_ArpN9rvCwR9fRMAhcsr_S7ZRiJk4p5k" + } + """ + assertFailsWith { + agent.parseInvitation(invitationString) + } + } } From 5e62e750194ea033f893040382a464108098f36f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ribo=CC=81?= Date: Fri, 27 Jan 2023 15:29:49 +0100 Subject: [PATCH 07/10] Linter. --- castor/src/commonMain/kotlin/CastorImpl.kt | 1 + .../iohk/atala/prism/castor}/Resolvers/PeerDIDResolver.kt | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) rename castor/src/commonMain/kotlin/{ => io/iohk/atala/prism/castor}/Resolvers/PeerDIDResolver.kt (96%) diff --git a/castor/src/commonMain/kotlin/CastorImpl.kt b/castor/src/commonMain/kotlin/CastorImpl.kt index f0943f840..9406d468b 100644 --- a/castor/src/commonMain/kotlin/CastorImpl.kt +++ b/castor/src/commonMain/kotlin/CastorImpl.kt @@ -1,5 +1,6 @@ package io.iohk.atala.prism.castor +import io.iohk.atala.prism.castor.io.iohk.atala.prism.castor.Resolvers.PeerDIDResolver import io.iohk.atala.prism.domain.buildingBlocks.Castor import io.iohk.atala.prism.domain.models.CastorError import io.iohk.atala.prism.domain.models.DID diff --git a/castor/src/commonMain/kotlin/Resolvers/PeerDIDResolver.kt b/castor/src/commonMain/kotlin/io/iohk/atala/prism/castor/Resolvers/PeerDIDResolver.kt similarity index 96% rename from castor/src/commonMain/kotlin/Resolvers/PeerDIDResolver.kt rename to castor/src/commonMain/kotlin/io/iohk/atala/prism/castor/Resolvers/PeerDIDResolver.kt index 052dc78c3..2a52edcc0 100644 --- a/castor/src/commonMain/kotlin/Resolvers/PeerDIDResolver.kt +++ b/castor/src/commonMain/kotlin/io/iohk/atala/prism/castor/Resolvers/PeerDIDResolver.kt @@ -1,5 +1,7 @@ -package io.iohk.atala.prism.castor +package io.iohk.atala.prism.castor.io.iohk.atala.prism.castor.Resolvers +import io.iohk.atala.prism.castor.DIDParser +import io.iohk.atala.prism.castor.DIDUrlParser import io.iohk.atala.prism.domain.models.DIDDocument import io.iohk.atala.prism.domain.models.DIDDocumentCoreProperty import io.iohk.atala.prism.domain.models.DIDResolver From ee716b06dfc7d8e6772af395c3f521a491ba69b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ribo=CC=81?= Date: Fri, 27 Jan 2023 16:29:48 +0100 Subject: [PATCH 08/10] Linting issues. --- castor/src/commonMain/kotlin/CastorImpl.kt | 2 +- .../castor/{Resolvers => resolvers}/PeerDIDResolver.kt | 2 +- .../prismagent/helpers/{httpClient.kt => HttpClient.kt} | 4 ++-- .../io/iohk/atala/prism/walletsdk/prismagent/PrismAgent.kt | 2 +- .../io/iohk/atala/prism/walletsdk/prismagent/helpers/Api.kt | 4 ++-- .../atala/prism/walletsdk/prismagent/helpers/HttpClient.kt | 6 ++++++ .../atala/prism/walletsdk/prismagent/helpers/httpClient.kt | 6 ------ .../PrismOnboardingInvitation.kt | 2 +- .../io/iohk/atala/prism/walletsdk/prismagent/ApiMock.kt | 4 ++-- .../prismagent/helpers/{httpClient.kt => HttpClient.kt} | 4 ++-- .../prismagent/helpers/{httpClient.kt => HttpClient.kt} | 4 ++-- 11 files changed, 20 insertions(+), 20 deletions(-) rename castor/src/commonMain/kotlin/io/iohk/atala/prism/castor/{Resolvers => resolvers}/PeerDIDResolver.kt (98%) rename prism-agent/src/androidMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/helpers/{httpClient.kt => HttpClient.kt} (53%) create mode 100644 prism-agent/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/helpers/HttpClient.kt delete mode 100644 prism-agent/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/helpers/httpClient.kt rename prism-agent/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/{PrismOnboarding => prismOnboarding}/PrismOnboardingInvitation.kt (91%) rename prism-agent/src/jsMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/helpers/{httpClient.kt => HttpClient.kt} (52%) rename prism-agent/src/jvmMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/helpers/{httpClient.kt => HttpClient.kt} (53%) diff --git a/castor/src/commonMain/kotlin/CastorImpl.kt b/castor/src/commonMain/kotlin/CastorImpl.kt index 9406d468b..7e9e34106 100644 --- a/castor/src/commonMain/kotlin/CastorImpl.kt +++ b/castor/src/commonMain/kotlin/CastorImpl.kt @@ -1,6 +1,6 @@ package io.iohk.atala.prism.castor -import io.iohk.atala.prism.castor.io.iohk.atala.prism.castor.Resolvers.PeerDIDResolver +import io.iohk.atala.prism.castor.io.iohk.atala.prism.castor.resolvers.PeerDIDResolver import io.iohk.atala.prism.domain.buildingBlocks.Castor import io.iohk.atala.prism.domain.models.CastorError import io.iohk.atala.prism.domain.models.DID diff --git a/castor/src/commonMain/kotlin/io/iohk/atala/prism/castor/Resolvers/PeerDIDResolver.kt b/castor/src/commonMain/kotlin/io/iohk/atala/prism/castor/resolvers/PeerDIDResolver.kt similarity index 98% rename from castor/src/commonMain/kotlin/io/iohk/atala/prism/castor/Resolvers/PeerDIDResolver.kt rename to castor/src/commonMain/kotlin/io/iohk/atala/prism/castor/resolvers/PeerDIDResolver.kt index 2a52edcc0..809d49c00 100644 --- a/castor/src/commonMain/kotlin/io/iohk/atala/prism/castor/Resolvers/PeerDIDResolver.kt +++ b/castor/src/commonMain/kotlin/io/iohk/atala/prism/castor/resolvers/PeerDIDResolver.kt @@ -1,4 +1,4 @@ -package io.iohk.atala.prism.castor.io.iohk.atala.prism.castor.Resolvers +package io.iohk.atala.prism.castor.io.iohk.atala.prism.castor.resolvers import io.iohk.atala.prism.castor.DIDParser import io.iohk.atala.prism.castor.DIDUrlParser diff --git a/prism-agent/src/androidMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/helpers/httpClient.kt b/prism-agent/src/androidMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/helpers/HttpClient.kt similarity index 53% rename from prism-agent/src/androidMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/helpers/httpClient.kt rename to prism-agent/src/androidMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/helpers/HttpClient.kt index c8ead80d0..3611174b2 100644 --- a/prism-agent/src/androidMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/helpers/httpClient.kt +++ b/prism-agent/src/androidMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/helpers/HttpClient.kt @@ -1,9 +1,9 @@ package io.iohk.atala.prism.walletsdk.prismagent.helpers -import io.ktor.client.HttpClient import io.ktor.client.HttpClientConfig import io.ktor.client.engine.okhttp.OkHttp +import io.ktor.client.HttpClient as KtorClient -internal actual fun httpClient(config: HttpClientConfig<*>.() -> Unit) = HttpClient(OkHttp) { +internal actual fun HttpClient(config: HttpClientConfig<*>.() -> Unit) = KtorClient(OkHttp) { config(this) } diff --git a/prism-agent/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/PrismAgent.kt b/prism-agent/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/PrismAgent.kt index 84738f84d..0a610174c 100644 --- a/prism-agent/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/PrismAgent.kt +++ b/prism-agent/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/PrismAgent.kt @@ -9,7 +9,7 @@ import io.iohk.atala.prism.domain.models.KeyCurve import io.iohk.atala.prism.domain.models.PrismAgentError import io.iohk.atala.prism.domain.models.Seed import io.iohk.atala.prism.walletsdk.prismagent.helpers.Api -import io.iohk.atala.prism.walletsdk.prismagent.protocols.PrismOnboarding.PrismOnboardingInvitation +import io.iohk.atala.prism.walletsdk.prismagent.protocols.prismOnboarding.PrismOnboardingInvitation import io.ktor.http.HttpMethod import io.ktor.http.Url import kotlinx.coroutines.flow.first diff --git a/prism-agent/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/helpers/Api.kt b/prism-agent/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/helpers/Api.kt index 5e9d15d3b..c4ddd2962 100644 --- a/prism-agent/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/helpers/Api.kt +++ b/prism-agent/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/helpers/Api.kt @@ -1,6 +1,5 @@ package io.iohk.atala.prism.walletsdk.prismagent.helpers -import io.ktor.client.HttpClient import io.ktor.client.plugins.contentnegotiation.ContentNegotiation import io.ktor.client.request.prepareRequest import io.ktor.client.request.setBody @@ -15,10 +14,11 @@ import io.ktor.http.path import io.ktor.serialization.kotlinx.json.json import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.serialization.json.Json +import io.ktor.client.HttpClient as KtorClient @DelicateCoroutinesApi open class Api( - private val client: HttpClient = httpClient { + private val client: KtorClient = HttpClient { install(ContentNegotiation) { json( Json { diff --git a/prism-agent/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/helpers/HttpClient.kt b/prism-agent/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/helpers/HttpClient.kt new file mode 100644 index 000000000..e4d4a6d5b --- /dev/null +++ b/prism-agent/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/helpers/HttpClient.kt @@ -0,0 +1,6 @@ +package io.iohk.atala.prism.walletsdk.prismagent.helpers + +import io.ktor.client.HttpClientConfig +import io.ktor.client.HttpClient as KtorClient + +internal expect fun HttpClient(config: HttpClientConfig<*>.() -> Unit = {}): KtorClient diff --git a/prism-agent/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/helpers/httpClient.kt b/prism-agent/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/helpers/httpClient.kt deleted file mode 100644 index 775ebc46e..000000000 --- a/prism-agent/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/helpers/httpClient.kt +++ /dev/null @@ -1,6 +0,0 @@ -package io.iohk.atala.prism.walletsdk.prismagent.helpers - -import io.ktor.client.HttpClient -import io.ktor.client.HttpClientConfig - -internal expect fun httpClient(config: HttpClientConfig<*>.() -> Unit = {}): HttpClient diff --git a/prism-agent/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/PrismOnboarding/PrismOnboardingInvitation.kt b/prism-agent/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/prismOnboarding/PrismOnboardingInvitation.kt similarity index 91% rename from prism-agent/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/PrismOnboarding/PrismOnboardingInvitation.kt rename to prism-agent/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/prismOnboarding/PrismOnboardingInvitation.kt index b181fc1be..04161b083 100644 --- a/prism-agent/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/PrismOnboarding/PrismOnboardingInvitation.kt +++ b/prism-agent/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/protocols/prismOnboarding/PrismOnboardingInvitation.kt @@ -1,4 +1,4 @@ -package io.iohk.atala.prism.walletsdk.prismagent.protocols.PrismOnboarding +package io.iohk.atala.prism.walletsdk.prismagent.protocols.prismOnboarding import io.iohk.atala.prism.domain.models.PrismAgentError import kotlinx.serialization.Serializable diff --git a/prism-agent/src/commonTest/kotlin/io/iohk/atala/prism/walletsdk/prismagent/ApiMock.kt b/prism-agent/src/commonTest/kotlin/io/iohk/atala/prism/walletsdk/prismagent/ApiMock.kt index 75dc113cb..4e47e5c47 100644 --- a/prism-agent/src/commonTest/kotlin/io/iohk/atala/prism/walletsdk/prismagent/ApiMock.kt +++ b/prism-agent/src/commonTest/kotlin/io/iohk/atala/prism/walletsdk/prismagent/ApiMock.kt @@ -1,7 +1,6 @@ package io.iohk.atala.prism.walletsdk.prismagent import io.iohk.atala.prism.walletsdk.prismagent.helpers.Api -import io.ktor.client.HttpClient import io.ktor.client.engine.mock.MockEngine import io.ktor.client.engine.mock.respond import io.ktor.client.plugins.contentnegotiation.ContentNegotiation @@ -11,12 +10,13 @@ import io.ktor.http.headersOf import io.ktor.serialization.kotlinx.json.json import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.serialization.json.Json +import io.ktor.client.HttpClient as KtorClient @OptIn(DelicateCoroutinesApi::class) class ApiMock : Api { constructor(statusCode: HttpStatusCode, response: String) : super( - HttpClient( + KtorClient( engine = MockEngine { _ -> respond( content = response, diff --git a/prism-agent/src/jsMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/helpers/httpClient.kt b/prism-agent/src/jsMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/helpers/HttpClient.kt similarity index 52% rename from prism-agent/src/jsMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/helpers/httpClient.kt rename to prism-agent/src/jsMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/helpers/HttpClient.kt index ec66adf1d..6b0dd0439 100644 --- a/prism-agent/src/jsMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/helpers/httpClient.kt +++ b/prism-agent/src/jsMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/helpers/HttpClient.kt @@ -1,9 +1,9 @@ package io.iohk.atala.prism.walletsdk.prismagent.helpers -import io.ktor.client.HttpClient import io.ktor.client.HttpClientConfig import io.ktor.client.engine.js.Js +import io.ktor.client.HttpClient as KtorClient -internal actual fun httpClient(config: HttpClientConfig<*>.() -> Unit) = HttpClient(Js) { +internal actual fun HttpClient(config: HttpClientConfig<*>.() -> Unit) = KtorClient(Js) { config(this) } diff --git a/prism-agent/src/jvmMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/helpers/httpClient.kt b/prism-agent/src/jvmMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/helpers/HttpClient.kt similarity index 53% rename from prism-agent/src/jvmMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/helpers/httpClient.kt rename to prism-agent/src/jvmMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/helpers/HttpClient.kt index c8ead80d0..3611174b2 100644 --- a/prism-agent/src/jvmMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/helpers/httpClient.kt +++ b/prism-agent/src/jvmMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/helpers/HttpClient.kt @@ -1,9 +1,9 @@ package io.iohk.atala.prism.walletsdk.prismagent.helpers -import io.ktor.client.HttpClient import io.ktor.client.HttpClientConfig import io.ktor.client.engine.okhttp.OkHttp +import io.ktor.client.HttpClient as KtorClient -internal actual fun httpClient(config: HttpClientConfig<*>.() -> Unit) = HttpClient(OkHttp) { +internal actual fun HttpClient(config: HttpClientConfig<*>.() -> Unit) = KtorClient(OkHttp) { config(this) } From 450e03dba94e6a94cceda71a79c5908afef76be3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ribo=CC=81?= Date: Fri, 27 Jan 2023 17:19:18 +0100 Subject: [PATCH 09/10] Improve removing android kotlin httpClient and including jvmMain source in androidMain --- prism-agent/build.gradle.kts | 3 +++ .../prism/walletsdk/prismagent/helpers/HttpClient.kt | 9 --------- .../prism/walletsdk/prismagent/helpers/HttpClient.kt | 1 + 3 files changed, 4 insertions(+), 9 deletions(-) delete mode 100644 prism-agent/src/androidMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/helpers/HttpClient.kt diff --git a/prism-agent/build.gradle.kts b/prism-agent/build.gradle.kts index edf550788..2955c7ba8 100644 --- a/prism-agent/build.gradle.kts +++ b/prism-agent/build.gradle.kts @@ -99,6 +99,9 @@ kotlin { } } val androidMain by getting { + kotlin { + srcDir("src/jvmMain/kotlin") + } dependencies { implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4") implementation("io.ktor:ktor-client-okhttp:2.1.3") diff --git a/prism-agent/src/androidMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/helpers/HttpClient.kt b/prism-agent/src/androidMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/helpers/HttpClient.kt deleted file mode 100644 index 3611174b2..000000000 --- a/prism-agent/src/androidMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/helpers/HttpClient.kt +++ /dev/null @@ -1,9 +0,0 @@ -package io.iohk.atala.prism.walletsdk.prismagent.helpers - -import io.ktor.client.HttpClientConfig -import io.ktor.client.engine.okhttp.OkHttp -import io.ktor.client.HttpClient as KtorClient - -internal actual fun HttpClient(config: HttpClientConfig<*>.() -> Unit) = KtorClient(OkHttp) { - config(this) -} diff --git a/prism-agent/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/helpers/HttpClient.kt b/prism-agent/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/helpers/HttpClient.kt index e4d4a6d5b..5625a0cc2 100644 --- a/prism-agent/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/helpers/HttpClient.kt +++ b/prism-agent/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/helpers/HttpClient.kt @@ -3,4 +3,5 @@ package io.iohk.atala.prism.walletsdk.prismagent.helpers import io.ktor.client.HttpClientConfig import io.ktor.client.HttpClient as KtorClient +@Suppress("NO_ACTUAL_FOR_EXPECT") internal expect fun HttpClient(config: HttpClientConfig<*>.() -> Unit = {}): KtorClient From f2d251322a7e9c45111d3fec1270958416e73e62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ribo=CC=81?= Date: Fri, 27 Jan 2023 18:07:28 +0100 Subject: [PATCH 10/10] Code improvements --- domain/build.gradle.kts | 2 ++ .../io.iohk.atala.prism.domain/models/Api.kt | 26 ++++++++++++++ .../prism/walletsdk/prismagent/PrismAgent.kt | 24 +++++++++++-- .../prismagent/helpers/{Api.kt => ApiImpl.kt} | 34 ++++++------------- .../walletsdk/prismagent/AgentApiMock.kt | 11 ------ .../prism/walletsdk/prismagent/ApiMock.kt | 4 +-- .../walletsdk/prismagent/PrismAgentTests.kt | 30 ++++++++++++++-- 7 files changed, 88 insertions(+), 43 deletions(-) create mode 100644 domain/src/commonMain/kotlin/io.iohk.atala.prism.domain/models/Api.kt rename prism-agent/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/helpers/{Api.kt => ApiImpl.kt} (68%) delete mode 100644 prism-agent/src/commonTest/kotlin/io/iohk/atala/prism/walletsdk/prismagent/AgentApiMock.kt diff --git a/domain/build.gradle.kts b/domain/build.gradle.kts index ddd007289..3f964eb6f 100644 --- a/domain/build.gradle.kts +++ b/domain/build.gradle.kts @@ -69,6 +69,7 @@ kotlin { implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.4.1") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4") implementation("io.iohk.atala.prism:uuid:1.0.0-alpha") + implementation("io.ktor:ktor-client-core:2.1.3") } } val commonTest by getting { @@ -77,6 +78,7 @@ kotlin { } } val jvmMain by getting + val jvmTest by getting { dependencies { implementation("junit:junit:4.13.2") diff --git a/domain/src/commonMain/kotlin/io.iohk.atala.prism.domain/models/Api.kt b/domain/src/commonMain/kotlin/io.iohk.atala.prism.domain/models/Api.kt new file mode 100644 index 000000000..122e846e5 --- /dev/null +++ b/domain/src/commonMain/kotlin/io.iohk.atala.prism.domain/models/Api.kt @@ -0,0 +1,26 @@ +package io.iohk.atala.prism.domain.models + +import io.ktor.client.statement.HttpResponse +import io.ktor.client.statement.HttpStatement +import io.ktor.http.HttpMethod +import io.ktor.http.Url +import io.ktor.client.HttpClient as KtorClient + +interface Api { + val client: KtorClient + suspend fun prepareRequest( + httpMethod: HttpMethod, + url: Url, + urlParameters: Map = mapOf(), + httpHeaders: Map = mapOf(), + body: Any? = null + ): HttpStatement + + suspend fun request( + httpMethod: HttpMethod, + url: Url, + urlParameters: Map = mapOf(), + httpHeaders: Map = mapOf(), + body: Any? = null + ): HttpResponse +} diff --git a/prism-agent/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/PrismAgent.kt b/prism-agent/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/PrismAgent.kt index 0a610174c..8cd987843 100644 --- a/prism-agent/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/PrismAgent.kt +++ b/prism-agent/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/PrismAgent.kt @@ -8,15 +8,19 @@ import io.iohk.atala.prism.domain.models.DIDDocument import io.iohk.atala.prism.domain.models.KeyCurve import io.iohk.atala.prism.domain.models.PrismAgentError import io.iohk.atala.prism.domain.models.Seed -import io.iohk.atala.prism.walletsdk.prismagent.helpers.Api +import io.iohk.atala.prism.walletsdk.prismagent.helpers.ApiImpl +import io.iohk.atala.prism.walletsdk.prismagent.helpers.HttpClient import io.iohk.atala.prism.walletsdk.prismagent.protocols.prismOnboarding.PrismOnboardingInvitation +import io.ktor.client.plugins.contentnegotiation.ContentNegotiation import io.ktor.http.HttpMethod import io.ktor.http.Url +import io.ktor.serialization.kotlinx.json.json import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.map import kotlinx.serialization.Serializable +import kotlinx.serialization.json.Json -open class PrismAgent { +final class PrismAgent { enum class State { STOPED, STARTING, RUNNING, STOPING } @@ -31,18 +35,32 @@ open class PrismAgent { private val apollo: Apollo private val castor: Castor private val pluto: Pluto - open val api: Api = Api() + private val api: ApiImpl constructor( apollo: Apollo, castor: Castor, pluto: Pluto, seed: Seed? = null, + api: ApiImpl? = null ) { this.apollo = apollo this.castor = castor this.pluto = pluto this.seed = seed ?: apollo.createRandomSeed().second + this.api = api ?: ApiImpl( + HttpClient { + install(ContentNegotiation) { + json( + Json { + ignoreUnknownKeys = true + prettyPrint = true + isLenient = true + } + ) + } + } + ) } suspend fun createNewPrismDID( diff --git a/prism-agent/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/helpers/Api.kt b/prism-agent/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/helpers/ApiImpl.kt similarity index 68% rename from prism-agent/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/helpers/Api.kt rename to prism-agent/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/helpers/ApiImpl.kt index c4ddd2962..6a1700a88 100644 --- a/prism-agent/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/helpers/Api.kt +++ b/prism-agent/src/commonMain/kotlin/io/iohk/atala/prism/walletsdk/prismagent/helpers/ApiImpl.kt @@ -1,6 +1,6 @@ package io.iohk.atala.prism.walletsdk.prismagent.helpers -import io.ktor.client.plugins.contentnegotiation.ContentNegotiation +import io.iohk.atala.prism.domain.models.Api import io.ktor.client.request.prepareRequest import io.ktor.client.request.setBody import io.ktor.client.statement.HttpResponse @@ -11,32 +11,18 @@ import io.ktor.http.HttpMethod import io.ktor.http.Url import io.ktor.http.contentType import io.ktor.http.path -import io.ktor.serialization.kotlinx.json.json import kotlinx.coroutines.DelicateCoroutinesApi -import kotlinx.serialization.json.Json import io.ktor.client.HttpClient as KtorClient @DelicateCoroutinesApi -open class Api( - private val client: KtorClient = HttpClient { - install(ContentNegotiation) { - json( - Json { - ignoreUnknownKeys = true - prettyPrint = true - isLenient = true - } - ) - } - } -) { +open class ApiImpl(override val client: KtorClient) : Api { - private suspend fun prepareRequest( + override suspend fun prepareRequest( httpMethod: HttpMethod, url: Url, - urlParameters: Map = mapOf(), - httpHeaders: Map = mapOf(), - body: Any? = null + urlParameters: Map, + httpHeaders: Map, + body: Any? ): HttpStatement { return client.prepareRequest { @@ -72,12 +58,12 @@ open class Api( } } - suspend fun request( + override suspend fun request( httpMethod: HttpMethod, url: Url, - urlParameters: Map = mapOf(), - httpHeaders: Map = mapOf(), - body: Any? = null + urlParameters: Map, + httpHeaders: Map, + body: Any? ): HttpResponse { return prepareRequest(httpMethod, url, urlParameters, httpHeaders, body).execute() } diff --git a/prism-agent/src/commonTest/kotlin/io/iohk/atala/prism/walletsdk/prismagent/AgentApiMock.kt b/prism-agent/src/commonTest/kotlin/io/iohk/atala/prism/walletsdk/prismagent/AgentApiMock.kt deleted file mode 100644 index 543ec810f..000000000 --- a/prism-agent/src/commonTest/kotlin/io/iohk/atala/prism/walletsdk/prismagent/AgentApiMock.kt +++ /dev/null @@ -1,11 +0,0 @@ -package io.iohk.atala.prism.walletsdk.prismagent - -import io.iohk.atala.prism.walletsdk.prismagent.helpers.Api -import io.ktor.http.HttpStatusCode - -class AgentApiMock( - statusCode: HttpStatusCode, - response: String -) : PrismAgent(ApolloMock(), CastorMock(), PlutoMock()) { - override val api: Api = ApiMock(statusCode, response) -} diff --git a/prism-agent/src/commonTest/kotlin/io/iohk/atala/prism/walletsdk/prismagent/ApiMock.kt b/prism-agent/src/commonTest/kotlin/io/iohk/atala/prism/walletsdk/prismagent/ApiMock.kt index 4e47e5c47..a42d91696 100644 --- a/prism-agent/src/commonTest/kotlin/io/iohk/atala/prism/walletsdk/prismagent/ApiMock.kt +++ b/prism-agent/src/commonTest/kotlin/io/iohk/atala/prism/walletsdk/prismagent/ApiMock.kt @@ -1,6 +1,6 @@ package io.iohk.atala.prism.walletsdk.prismagent -import io.iohk.atala.prism.walletsdk.prismagent.helpers.Api +import io.iohk.atala.prism.walletsdk.prismagent.helpers.ApiImpl import io.ktor.client.engine.mock.MockEngine import io.ktor.client.engine.mock.respond import io.ktor.client.plugins.contentnegotiation.ContentNegotiation @@ -13,7 +13,7 @@ import kotlinx.serialization.json.Json import io.ktor.client.HttpClient as KtorClient @OptIn(DelicateCoroutinesApi::class) -class ApiMock : Api { +class ApiMock : ApiImpl { constructor(statusCode: HttpStatusCode, response: String) : super( KtorClient( diff --git a/prism-agent/src/commonTest/kotlin/io/iohk/atala/prism/walletsdk/prismagent/PrismAgentTests.kt b/prism-agent/src/commonTest/kotlin/io/iohk/atala/prism/walletsdk/prismagent/PrismAgentTests.kt index dc64d6e86..52c196767 100644 --- a/prism-agent/src/commonTest/kotlin/io/iohk/atala/prism/walletsdk/prismagent/PrismAgentTests.kt +++ b/prism-agent/src/commonTest/kotlin/io/iohk/atala/prism/walletsdk/prismagent/PrismAgentTests.kt @@ -47,7 +47,15 @@ class PrismAgentTests { @Test fun testPrismAgentOnboardingInvitation_shouldAcceptOnboardingInvitation_whenStatusIs200() = runTest { - var agent = AgentApiMock(HttpStatusCode.OK, "{\"success\":\"true\"}") + val apolloMock = ApolloMock() + val castorMock = CastorMock() + val plutoMock = PlutoMock() + val agent = PrismAgent( + apollo = apolloMock, + castor = castorMock, + pluto = plutoMock, + api = ApiMock(HttpStatusCode.OK, "{\"success\":\"true\"}") + ) var invitationString = """ { "type":"Onboarding", @@ -61,7 +69,15 @@ class PrismAgentTests { @Test fun testPrismAgentOnboardingInvitation_shouldRejectOnboardingInvitation_whenStatusIsNot200() = runTest { - var agent = AgentApiMock(HttpStatusCode.BadRequest, "{\"success\":\"true\"}") + val apolloMock = ApolloMock() + val castorMock = CastorMock() + val plutoMock = PlutoMock() + val agent = PrismAgent( + apollo = apolloMock, + castor = castorMock, + pluto = plutoMock, + api = ApiMock(HttpStatusCode.BadRequest, "{\"success\":\"true\"}") + ) var invitationString = """ { "type":"Onboarding", @@ -77,7 +93,15 @@ class PrismAgentTests { @Test fun testPrismAgentOnboardingInvitation_shouldRejectOnboardingInvitation_whenBodyIsWrong() = runTest { - var agent = AgentApiMock(HttpStatusCode.BadRequest, "{\"success\":\"true\"}") + val apolloMock = ApolloMock() + val castorMock = CastorMock() + val plutoMock = PlutoMock() + val agent = PrismAgent( + apollo = apolloMock, + castor = castorMock, + pluto = plutoMock, + api = ApiMock(HttpStatusCode.OK, "{\"success\":\"true\"}") + ) var invitationString = """ { "type":"Onboarding",