diff options
author | Torsten Grote <t@grobox.de> | 2020-07-29 17:24:27 -0300 |
---|---|---|
committer | Torsten Grote <t@grobox.de> | 2020-07-29 17:25:41 -0300 |
commit | 479f8015f8663507fd318aa29e863dac35683c64 (patch) | |
tree | 3d65de0c8af74cf4f2ba37e65624d01a8eb8af60 /src | |
parent | 9befa8db8317758ad9e5dad5e7698efff76f1a71 (diff) | |
download | wallet-kotlin-479f8015f8663507fd318aa29e863dac35683c64.tar.gz wallet-kotlin-479f8015f8663507fd318aa29e863dac35683c64.tar.bz2 wallet-kotlin-479f8015f8663507fd318aa29e863dac35683c64.zip |
Upgrade Taler URI to new format
Diffstat (limited to 'src')
5 files changed, 58 insertions, 32 deletions
diff --git a/src/commonMain/kotlin/net/taler/wallet/kotlin/TalerUri.kt b/src/commonMain/kotlin/net/taler/wallet/kotlin/TalerUri.kt index f64f738..c489d71 100644 --- a/src/commonMain/kotlin/net/taler/wallet/kotlin/TalerUri.kt +++ b/src/commonMain/kotlin/net/taler/wallet/kotlin/TalerUri.kt @@ -19,23 +19,42 @@ package net.taler.wallet.kotlin internal object TalerUri { private const val SCHEME = "taler://" + private const val SCHEME_INSECURE = "taler+http://" private const val AUTHORITY_PAY = "pay" private const val AUTHORITY_WITHDRAW = "withdraw" private const val AUTHORITY_REFUND = "refund" private const val AUTHORITY_TIP = "tip" + data class WithdrawUriResult( + val bankIntegrationApiBaseUrl: String, + val withdrawalOperationId: String + ) + /** * Parses a withdraw URI and returns a bank status URL or null if the URI was invalid. */ - fun parseWithdrawUri(uri: String): String? { - val prefix = "${SCHEME}${AUTHORITY_WITHDRAW}" - if (!uri.startsWith(prefix, ignoreCase = true)) return null - val parts = uri.substring(prefix.length + 1).split('/') - if (parts.size != 3) return null - val (host, query, withdrawId) = parts - // TODO clarify what query is and if it can include '/' (docs seem out of date) - val urlQuery = if (query == "-") "api/withdraw-operation" else query - return "https://${host.toLowerCase()}/$urlQuery/$withdrawId" + fun parseWithdrawUri(uri: String): WithdrawUriResult? { + val (resultScheme, prefix) = when { + uri.startsWith(SCHEME, ignoreCase = true) -> { + Pair("https://", "${SCHEME}${AUTHORITY_WITHDRAW}/") + } + uri.startsWith(SCHEME_INSECURE, ignoreCase = true) -> { + Pair("http://", "${SCHEME_INSECURE}${AUTHORITY_WITHDRAW}/") + } + else -> return null + } + if (!uri.startsWith(prefix)) return null + val parts = uri.let { + (if (it.endsWith("/")) it.dropLast(1) else it).substring(prefix.length).split('/') + } + if (parts.size < 2) return null + val host = parts[0].toLowerCase() + val pathSegments = parts.slice(1 until parts.size - 1).joinToString("/") + val withdrawId = parts.last() + if (withdrawId.isBlank()) return null + val url = "${resultScheme}${host}/${pathSegments}" + + return WithdrawUriResult(url, withdrawId) } } diff --git a/src/commonMain/kotlin/net/taler/wallet/kotlin/operations/Withdraw.kt b/src/commonMain/kotlin/net/taler/wallet/kotlin/operations/Withdraw.kt index 1fa2822..1173140 100644 --- a/src/commonMain/kotlin/net/taler/wallet/kotlin/operations/Withdraw.kt +++ b/src/commonMain/kotlin/net/taler/wallet/kotlin/operations/Withdraw.kt @@ -52,7 +52,7 @@ internal class Withdraw( val amount: Amount, val selectionDone: Boolean, val transferDone: Boolean, - val senderWire: String?, + val senderPaytoUri: String?, val suggestedExchange: String?, val confirmTransferUrl: String?, val wireTypes: List<String>, @@ -69,7 +69,7 @@ internal class Withdraw( @SerialName("wire_types") val wireTypes: List<String>, @SerialName("sender_wire") - val senderWire: String?, + val senderPaytoUri: String?, @SerialName("suggested_exchange") val suggestedExchange: String?, @SerialName("confirm_transfer_url") @@ -80,7 +80,7 @@ internal class Withdraw( confirmTransferUrl = confirmTransferUrl, extractedStatusUrl = extractedStatusUrl, selectionDone = selectionDone, - senderWire = senderWire, + senderPaytoUri = senderPaytoUri, suggestedExchange = suggestedExchange, transferDone = transferDone, wireTypes = wireTypes @@ -88,7 +88,8 @@ internal class Withdraw( } suspend fun getBankInfo(talerWithdrawUri: String): BankDetails { - val url = parseWithdrawUri(talerWithdrawUri) ?: throw Error("Can't parse URI $talerWithdrawUri") + val uriResult = parseWithdrawUri(talerWithdrawUri) ?: throw Error("Can't parse URI $talerWithdrawUri") + val url = "${uriResult.bankIntegrationApiBaseUrl}api/withdraw-operation/${uriResult.withdrawalOperationId}" val response: Response = httpClient.get(url) return response.toBankDetails(url) } diff --git a/src/commonTest/kotlin/net/taler/wallet/kotlin/TalerUriTest.kt b/src/commonTest/kotlin/net/taler/wallet/kotlin/TalerUriTest.kt index c35d155..cfcc8bd 100644 --- a/src/commonTest/kotlin/net/taler/wallet/kotlin/TalerUriTest.kt +++ b/src/commonTest/kotlin/net/taler/wallet/kotlin/TalerUriTest.kt @@ -16,6 +16,7 @@ package net.taler.wallet.kotlin +import net.taler.wallet.kotlin.TalerUri.WithdrawUriResult import net.taler.wallet.kotlin.TalerUri.parseWithdrawUri import kotlin.test.Test import kotlin.test.assertEquals @@ -26,31 +27,38 @@ class TalerUriTest { @Test fun testParseWithdrawUri() { // correct parsing - var uri = "taler://withdraw/bank.example.com/-/12345" - assertEquals("https://bank.example.com/api/withdraw-operation/12345", parseWithdrawUri(uri)) + var uri = "taler://withdraw/bank.example.com/12345" + var expected = WithdrawUriResult("https://bank.example.com/", "12345") + assertEquals(expected, parseWithdrawUri(uri)) - // correct parsing with custom query - uri = "taler://withdraw/bank.example.com/foo/12345" - assertEquals("https://bank.example.com/foo/12345", parseWithdrawUri(uri)) + // correct parsing with insecure http + uri = "taler+http://withdraw/bank.example.org/foo" + expected = WithdrawUriResult("http://bank.example.org/", "foo") + assertEquals(expected, parseWithdrawUri(uri)) + + // correct parsing with long path + uri = "taler://withdraw/bank.example.com/foo/bar/23/42/1337/1234567890" + expected = WithdrawUriResult("https://bank.example.com/foo/bar/23/42/1337", "1234567890") + assertEquals(expected, parseWithdrawUri(uri)) // rejects incorrect scheme - uri = "talerx://withdraw/bank.example.com/-/12345" + uri = "talerx://withdraw/bank.example.com/12345" assertNull(parseWithdrawUri(uri)) // rejects incorrect authority - uri = "taler://withdrawx/bank.example.com/-/12345" + uri = "taler://withdrawx/bank.example.com/12345" assertNull(parseWithdrawUri(uri)) - // rejects incorrect authority - uri = "taler://withdrawx/bank.example.com/-/12345" + // rejects incorrect authority with insecure http + uri = "taler+http://withdrawx/bank.example.com/12345" assertNull(parseWithdrawUri(uri)) - // rejects too few parts - uri = "taler://withdraw/bank.example.com/foo" + // rejects empty withdrawalId + uri = "taler://withdraw/bank.example.com//" assertNull(parseWithdrawUri(uri)) - // rejects too many parts - uri = "taler://withdraw/bank.example.com/-/12345/foo" + // rejects empty path and withdrawalId + uri = "taler://withdraw/bank.example.com////" assertNull(parseWithdrawUri(uri)) } diff --git a/src/commonTest/kotlin/net/taler/wallet/kotlin/TestUtils.kt b/src/commonTest/kotlin/net/taler/wallet/kotlin/TestUtils.kt index 4b04ebf..42f297a 100644 --- a/src/commonTest/kotlin/net/taler/wallet/kotlin/TestUtils.kt +++ b/src/commonTest/kotlin/net/taler/wallet/kotlin/TestUtils.kt @@ -20,11 +20,9 @@ import io.ktor.client.HttpClient import io.ktor.client.engine.mock.MockEngine import io.ktor.client.engine.mock.MockEngineConfig import io.ktor.client.engine.mock.respond -import io.ktor.client.engine.mock.respondError import io.ktor.client.features.json.JsonFeature import io.ktor.client.features.json.serializer.KotlinxSerializer import io.ktor.http.ContentType.Application -import io.ktor.http.HttpStatusCode.Companion.InternalServerError import io.ktor.http.Url import io.ktor.http.fullPath import io.ktor.http.headersOf @@ -63,7 +61,7 @@ fun HttpClient.giveJsonResponse(url: String, jsonProducer: () -> String) { val headers = headersOf("Content-Type" to listOf(Application.Json.toString())) respond(jsonProducer(), headers = headers) } else { - respondError(InternalServerError, "Unexpected URL: ${request.url.fullUrl}") + error("Unexpected URL: ${request.url.fullUrl}") } } } diff --git a/src/commonTest/kotlin/net/taler/wallet/kotlin/operations/WithdrawTest.kt b/src/commonTest/kotlin/net/taler/wallet/kotlin/operations/WithdrawTest.kt index 413deef..541f24f 100644 --- a/src/commonTest/kotlin/net/taler/wallet/kotlin/operations/WithdrawTest.kt +++ b/src/commonTest/kotlin/net/taler/wallet/kotlin/operations/WithdrawTest.kt @@ -59,7 +59,7 @@ internal class WithdrawTest { confirmTransferUrl = "https://bank.test.taler.net/confirm-withdrawal/9b51c1dd-db41-4b5f-97d9-1071d5dd8091", extractedStatusUrl = "https://bank.test.taler.net/api/withdraw-operation/9b51c1dd-db41-4b5f-97d9-1071d5dd8091", selectionDone = false, - senderWire = "payto://x-taler-bank/bank.test.taler.net/test", + senderPaytoUri = "payto://x-taler-bank/bank.test.taler.net/test", suggestedExchange = "https://exchange.test.taler.net/", transferDone = false, wireTypes = listOf("x-taler-bank") @@ -70,14 +70,14 @@ internal class WithdrawTest { "transfer_done": ${bankDetails.transferDone}, "amount": "${bankDetails.amount.toJSONString()}", "wire_types": ["${bankDetails.wireTypes[0]}"], - "sender_wire": "${bankDetails.senderWire}", + "sender_wire": "${bankDetails.senderPaytoUri}", "suggested_exchange": "${bankDetails.suggestedExchange}", "confirm_transfer_url": "${bankDetails.confirmTransferUrl}" }""".trimIndent() } runCoroutine { val details = - withdraw.getBankInfo("taler://withdraw/bank.test.taler.net/-/9b51c1dd-db41-4b5f-97d9-1071d5dd8091") + withdraw.getBankInfo("taler://withdraw/bank.test.taler.net/9b51c1dd-db41-4b5f-97d9-1071d5dd8091") assertEquals(bankDetails, details) } } |