gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[libeufin] branch master updated: Taler URI generator.


From: gnunet
Subject: [libeufin] branch master updated: Taler URI generator.
Date: Tue, 19 Sep 2023 14:55:45 +0200

This is an automated email from the git hooks/post-receive script.

ms pushed a commit to branch master
in repository libeufin.

The following commit(s) were added to refs/heads/master by this push:
     new b0e1a2b3 Taler URI generator.
b0e1a2b3 is described below

commit b0e1a2b3cd3eb0ce3c6f6567570f019fe9a36900
Author: MS <ms@taler.net>
AuthorDate: Tue Sep 19 14:55:30 2023 +0200

    Taler URI generator.
---
 .../src/main/kotlin/tech/libeufin/bank/Database.kt |  1 +
 bank/src/main/kotlin/tech/libeufin/bank/helpers.kt | 36 +++++++++++++++++++++-
 .../kotlin/tech/libeufin/bank/talerWebHandlers.kt  | 31 ++++++++++++++++++-
 bank/src/main/kotlin/tech/libeufin/bank/types.kt   |  7 +++++
 bank/src/test/kotlin/TalerTest.kt                  | 34 ++++++++++++++++++++
 5 files changed, 107 insertions(+), 2 deletions(-)

diff --git a/bank/src/main/kotlin/tech/libeufin/bank/Database.kt 
b/bank/src/main/kotlin/tech/libeufin/bank/Database.kt
index 8b45e146..64fe9afa 100644
--- a/bank/src/main/kotlin/tech/libeufin/bank/Database.kt
+++ b/bank/src/main/kotlin/tech/libeufin/bank/Database.kt
@@ -32,6 +32,7 @@ private const val DB_CTR_LIMIT = 1000000
 
 fun Customer.expectRowId(): Long = this.dbRowId ?: throw 
internalServerError("Cutsomer '$login' had no DB row ID.")
 fun BankAccount.expectBalance(): TalerAmount = this.balance ?: throw 
internalServerError("Bank account '${this.internalPaytoUri}' lacks balance.")
+fun BankAccount.expectRowId(): Long = this.bankAccountId ?: throw 
internalServerError("Bank account '${this.internalPaytoUri}' lacks database row 
ID.")
 
 
 class Database(private val dbConfig: String) {
diff --git a/bank/src/main/kotlin/tech/libeufin/bank/helpers.kt 
b/bank/src/main/kotlin/tech/libeufin/bank/helpers.kt
index 1431ff4f..59ddb318 100644
--- a/bank/src/main/kotlin/tech/libeufin/bank/helpers.kt
+++ b/bank/src/main/kotlin/tech/libeufin/bank/helpers.kt
@@ -21,10 +21,12 @@ package tech.libeufin.bank
 
 import io.ktor.http.*
 import io.ktor.server.application.*
+import io.ktor.server.util.*
 import net.taler.common.errorcodes.TalerErrorCode
 import net.taler.wallet.crypto.Base32Crockford
 import tech.libeufin.util.*
 import java.lang.NumberFormatException
+import java.net.URL
 
 fun ApplicationCall.expectUriComponent(componentName: String) =
     this.maybeUriComponent(componentName) ?: throw badRequest(
@@ -335,4 +337,36 @@ fun isBalanceEnough(
         (normalDiff.frac > normalMaxDebt.frac)) return false
     return true
 }
-fun getBankCurrency(): String = db.configGet("internal_currency") ?: throw 
internalServerError("Bank lacks currency")
\ No newline at end of file
+fun getBankCurrency(): String = db.configGet("internal_currency") ?: throw 
internalServerError("Bank lacks currency")
+
+/**
+ *  Builds the taler://withdraw-URI.  Such URI will serve the requests
+ *  from wallets, when they need to manage the operation.  For example,
+ *  a URI like taler://withdraw/$BANK_URL/taler-integration/$WO_ID needs
+ *  the bank to implement the Taler integratino API at the following base URL:
+ *
+ *      https://$BANK_URL/taler-integration
+ */
+fun getTalerWithdrawUri(baseUrl: String, woId: String) =
+    url {
+        val baseUrlObj = URL(baseUrl)
+        protocol = URLProtocol(
+            name = "taler".plus(if (baseUrlObj.protocol.lowercase() == "http") 
"+http" else ""),
+            defaultPort = -1
+        )
+        host = "withdraw"
+        val pathSegments = mutableListOf(
+            // adds the hostname(+port) of the actual bank that will serve the 
withdrawal request.
+            baseUrlObj.host.plus(
+                if (baseUrlObj.port != -1)
+                    ":${baseUrlObj.port}"
+                else ""
+            )
+        )
+        // Removing potential double slashes.
+        baseUrlObj.path.split("/").forEach {
+            if (it.isNotEmpty()) pathSegments.add(it)
+        }
+        pathSegments.add("taler-integration/${woId}")
+        this.appendPathSegments(pathSegments)
+    }
\ No newline at end of file
diff --git a/bank/src/main/kotlin/tech/libeufin/bank/talerWebHandlers.kt 
b/bank/src/main/kotlin/tech/libeufin/bank/talerWebHandlers.kt
index 6bb27374..8d6fd3d6 100644
--- a/bank/src/main/kotlin/tech/libeufin/bank/talerWebHandlers.kt
+++ b/bank/src/main/kotlin/tech/libeufin/bank/talerWebHandlers.kt
@@ -26,7 +26,10 @@ package tech.libeufin.bank
 
 import io.ktor.server.application.*
 import io.ktor.server.request.*
+import io.ktor.server.response.*
 import io.ktor.server.routing.*
+import net.taler.common.errorcodes.TalerErrorCode
+import java.util.*
 
 fun Routing.talerWebHandlers() {
     post("/accounts/{USERNAME}/withdrawals") {
@@ -39,8 +42,34 @@ fun Routing.talerWebHandlers() {
         // Checking that the user has enough funds.
         val b = db.bankAccountGetFromOwnerId(c.expectRowId())
             ?: throw internalServerError("Customer '${c.login}' lacks bank 
account.")
+        val withdrawalAmount = parseTalerAmount(req.amount)
+        if (
+            !isBalanceEnough(
+                balance = b.expectBalance(),
+                due = withdrawalAmount,
+                maxDebt = b.maxDebt,
+                hasBalanceDebt = b.hasDebt
+            ))
+            throw forbidden(
+                hint = "Insufficient funds to withdraw with Taler",
+                talerErrorCode = TalerErrorCode.TALER_EC_NONE // FIXME: need 
EC.
+            )
+        // Auth and funds passed, create the operation now!
+        val opId = UUID.randomUUID()
+        if(
+            !db.talerWithdrawalCreate(
+                opId,
+                b.expectRowId(),
+                withdrawalAmount
+            )
+        )
+            throw internalServerError("Bank failed at creating the withdraw 
operation.")
 
-        throw NotImplementedError()
+        call.respond(BankAccountCreateWithdrawalResponse(
+            withdrawal_id = opId.toString(),
+            taler_withdraw_uri = "FIXME"
+        ))
+        return@post
     }
     get("/accounts/{USERNAME}/withdrawals/{W_ID}") {
         throw NotImplementedError()
diff --git a/bank/src/main/kotlin/tech/libeufin/bank/types.kt 
b/bank/src/main/kotlin/tech/libeufin/bank/types.kt
index 92567634..ebbb0f1e 100644
--- a/bank/src/main/kotlin/tech/libeufin/bank/types.kt
+++ b/bank/src/main/kotlin/tech/libeufin/bank/types.kt
@@ -388,3 +388,10 @@ data class BankAccountTransactionsResponse(
 data class BankAccountCreateWithdrawalRequest(
     val amount: String
 )
+
+// Taler withdrawal response.
+@Serializable
+data class BankAccountCreateWithdrawalResponse(
+    val withdrawal_id: String,
+    val taler_withdraw_uri: String
+)
diff --git a/bank/src/test/kotlin/TalerTest.kt 
b/bank/src/test/kotlin/TalerTest.kt
new file mode 100644
index 00000000..2aa90e2d
--- /dev/null
+++ b/bank/src/test/kotlin/TalerTest.kt
@@ -0,0 +1,34 @@
+import org.junit.Test
+import tech.libeufin.bank.getTalerWithdrawUri
+
+class TalerTest {
+    // Testing the generation of taler://withdraw-URIs.
+    @Test
+    fun testWithdrawUri() {
+        // Checking the taler+http://-style.
+        val withHttp = getTalerWithdrawUri(
+            "http://example.com";,
+            "my-id"
+        )
+        assert(withHttp == 
"taler+http://withdraw/example.com/taler-integration/my-id";)
+        // Checking the taler://-style
+        val onlyTaler = getTalerWithdrawUri(
+            "https://example.com/";,
+            "my-id"
+        )
+        // Note: this tests as well that no double slashes belong to the result
+        assert(onlyTaler == 
"taler://withdraw/example.com/taler-integration/my-id")
+        // Checking the removal of subsequent slashes
+        val manySlashes = getTalerWithdrawUri(
+            "https://www.example.com//////";,
+            "my-id"
+        )
+        assert(manySlashes == 
"taler://withdraw/www.example.com/taler-integration/my-id")
+        // Checking with specified port number
+        val withPort = getTalerWithdrawUri(
+            "https://www.example.com:9876";,
+            "my-id"
+        )
+        assert(withPort == 
"taler://withdraw/www.example.com:9876/taler-integration/my-id")
+    }
+}
\ No newline at end of file

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]