gnunet-svn
[Top][All Lists]
Advanced

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

[libeufin] branch master updated (7e4b86e6 -> 6de75405)


From: gnunet
Subject: [libeufin] branch master updated (7e4b86e6 -> 6de75405)
Date: Fri, 08 Jul 2022 16:48:01 +0200

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

ms pushed a change to branch master
in repository libeufin.

    from 7e4b86e6 decrease log verbosity
     new 24838e2d (re)implement /admin/add-incoming
     new 6de75405 more on /admin/add-incoming

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 cli/bin/libeufin-cli                               |   8 +-
 nexus/src/main/kotlin/tech/libeufin/nexus/Taler.kt | 106 ++++++++++++++++++++-
 .../tech/libeufin/nexus/bankaccount/BankAccount.kt |   2 +-
 .../kotlin/tech/libeufin/nexus/ebics/EbicsNexus.kt |   2 +-
 .../src/main/kotlin/tech/libeufin/sandbox/Main.kt  |  12 ++-
 util/src/main/kotlin/HTTP.kt                       |   7 ++
 6 files changed, 128 insertions(+), 9 deletions(-)

diff --git a/cli/bin/libeufin-cli b/cli/bin/libeufin-cli
index 5ccb0663..c6310788 100755
--- a/cli/bin/libeufin-cli
+++ b/cli/bin/libeufin-cli
@@ -1333,12 +1333,18 @@ def sandbox_demobank_delete(obj, bank_account):
     default="",
     help="Person name",
 )
+@click.option(
+    "--iban",
+    help="Uses this IBAN, instead of a random one.",
+)
 @click.pass_obj
-def sandbox_demobank_register(obj, public, name):
+def sandbox_demobank_register(obj, public, name, iban):
     url = obj.access_api_url ("/testing/register")
     req = dict(username=obj.username, password=obj.password, isPublic=public)
     if name != "":
         req.update(name=name)
+    if iban:
+        req.update(iban=iban)
     try:
         resp = post(
             url,
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/Taler.kt 
b/nexus/src/main/kotlin/tech/libeufin/nexus/Taler.kt
index bdb0969e..202453ed 100644
--- a/nexus/src/main/kotlin/tech/libeufin/nexus/Taler.kt
+++ b/nexus/src/main/kotlin/tech/libeufin/nexus/Taler.kt
@@ -22,24 +22,28 @@ package tech.libeufin.nexus
 import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
 import io.ktor.application.ApplicationCall
 import io.ktor.application.call
+import io.ktor.client.*
+import io.ktor.client.features.*
+import io.ktor.client.request.*
 import io.ktor.content.TextContent
-import io.ktor.http.ContentType
-import io.ktor.http.HttpStatusCode
+import io.ktor.http.*
 import io.ktor.request.receive
 import io.ktor.response.respond
 import io.ktor.response.respondText
 import io.ktor.routing.Route
 import io.ktor.routing.get
 import io.ktor.routing.post
+import io.ktor.util.*
 import org.jetbrains.exposed.dao.Entity
 import org.jetbrains.exposed.dao.id.IdTable
 import org.jetbrains.exposed.sql.*
 import org.jetbrains.exposed.sql.transactions.transaction
 import tech.libeufin.nexus.bankaccount.addPaymentInitiation
+import tech.libeufin.nexus.bankaccount.fetchBankAccountTransactions
 import tech.libeufin.nexus.iso20022.*
 import tech.libeufin.nexus.server.*
 import tech.libeufin.util.*
-import java.net.URLEncoder
+import java.net.URL
 import kotlin.math.abs
 import kotlin.math.min
 
@@ -56,7 +60,7 @@ data class TalerTransferRequest(
 
 data class TalerTransferResponse(
     /**
-     * Point in time when the nexus put the payment instruction into the 
database.
+     * Point in time when Nexus put the payment instruction into the database.
      */
     val timestamp: GnunetTimestamp,
     val row_id: Long
@@ -455,6 +459,96 @@ private suspend fun historyIncoming(call: ApplicationCall) 
{
     return call.respond(TextContent(customConverter(history), 
ContentType.Application.Json))
 }
 
+/**
+ * This call proxies /admin/add/incoming to the Sandbox,
+ * which is the service keeping the transactions ledger.
+ * The credentials are ASSUMED to be exchange/x (user/pass).
+ *
+ * In the future, a dedicate "add-incoming" facade should
+ * be provided, offering the mean to store the credentials
+ * at configuration time.
+ *
+ */
+private suspend fun addIncoming(call: ApplicationCall) {
+    val facadeId = ensureNonNull(call.parameters["fcid"])
+    val currentBody = call.receive<String>()
+    val fromDb = transaction {
+        val f = FacadeEntity.findByName(facadeId) ?: throw notFound("facade 
$facadeId not found")
+        val state = FacadeStateEntity.find {
+            FacadeStateTable.facade eq f.id
+        }.firstOrNull() ?: throw internalServerError("facade $facadeId has no 
state!")
+        val conn = NexusBankConnectionEntity.findByName(state.bankConnection) 
?: throw internalServerError(
+            "state of facade $facadeId has no bank connection!"
+        )
+        val ebicsData = NexusEbicsSubscribersTable.select {
+            NexusEbicsSubscribersTable.nexusBankConnection eq conn.id
+        }.firstOrNull() ?: throw internalServerError(
+            "Connection '${conn.connectionId}' doesn't have EBICS"
+        )
+        // Resort Sandbox URL from EBICS endpoint.
+        val sandboxUrl = URL(ebicsData[NexusEbicsSubscribersTable.ebicsURL])
+        // NOTE: the exchange username must be 'exchange', at the Sandbox.
+        return@transaction Pair(url {
+            protocol = URLProtocol(sandboxUrl.protocol, 80)
+            host = sandboxUrl.host
+            if (sandboxUrl.port != 80) port = sandboxUrl.port
+            path(
+                "demobanks",
+                "default",
+                "taler-wire-gateway",
+                "exchange",
+                "admin",
+                "add-incoming"
+            )
+        }, state.bankAccount
+        )
+    }
+    val client = HttpClient { followRedirects = true }
+    try {
+        client.post<String>(
+            urlString = fromDb.first,
+            block = {
+                this.body = currentBody
+                this.header(
+                    "Authorization",
+                    buildBasicAuthLine("exchange", "x")
+                )
+                this.header("Content-Type", "application/json")
+            }
+        )
+    } catch (e: ClientRequestException) {
+        logger.error("Proxying /admin/add/incoming to the Sandbox failed: $e")
+    } catch (e: Exception) {
+        logger.error("Could not proxy /admin/add/incoming to the Sandbox: $e")
+    }
+    /**
+     * At this point, Sandbox booked the payment.  Now the "row_id"
+     * value to put in the response needs to be resorted; that may
+     * be known by fetching a fresh C52 report, then let Nexus ingest
+     * the result, and finally _optimistically_ pick the latest entry
+     * in the received payments.  */
+    fetchBankAccountTransactions(
+        client,
+        FetchSpecLatestJson(
+            FetchLevel.REPORT,
+            null
+        ),
+        fromDb.second
+    )
+    /**
+     * The latest incoming payment should now be found among
+     * the ingested ones.
+     */
+    val lastIncomingPayment = transaction {
+        val lastRecord = TalerIncomingPaymentEntity.all().last()
+        return@transaction Pair(lastRecord.id.value, lastRecord.timestampMs)
+    }
+    call.respond(object {
+        val row_id = lastIncomingPayment.first
+        val timestamp = GnunetTimestamp(lastIncomingPayment.second / 1000L)
+    })
+}
+
 private fun getCurrency(facadeName: String): String {
     return transaction {
         getFacadeState(facadeName).currency
@@ -487,6 +581,10 @@ fun talerFacadeRoutes(route: Route) {
         historyIncoming(call)
         return@get
     }
+    route.post("/admin/add-incoming") {
+        addIncoming(call)
+        return@post
+    }
     route.get("") {
         call.respondText("Hello, this is a Taler Facade")
         return@get
diff --git 
a/nexus/src/main/kotlin/tech/libeufin/nexus/bankaccount/BankAccount.kt 
b/nexus/src/main/kotlin/tech/libeufin/nexus/bankaccount/BankAccount.kt
index 7bd0a035..c0e20dc3 100644
--- a/nexus/src/main/kotlin/tech/libeufin/nexus/bankaccount/BankAccount.kt
+++ b/nexus/src/main/kotlin/tech/libeufin/nexus/bankaccount/BankAccount.kt
@@ -352,7 +352,7 @@ suspend fun fetchBankAccountTransactions(
         if (acct == null) {
             throw NexusError(
                 HttpStatusCode.NotFound,
-                "Account not found"
+                "Account '$accountId' not found"
             )
         }
         val conn = acct.defaultBankConnection
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/EbicsNexus.kt 
b/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/EbicsNexus.kt
index a3f70793..2e22a68f 100644
--- a/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/EbicsNexus.kt
+++ b/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/EbicsNexus.kt
@@ -415,7 +415,7 @@ class EbicsBankConnectionProtocol: BankConnectionProtocol {
             if (acct == null) {
                 throw NexusError(
                     HttpStatusCode.NotFound,
-                    "Account not found"
+                    "Account '$accountId' not found"
                 )
             }
             object {
diff --git a/sandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt 
b/sandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt
index 67c8b371..ef97b4df 100644
--- a/sandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt
+++ b/sandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt
@@ -1069,8 +1069,8 @@ val sandboxApp: Application.() -> Unit = {
             call.respond(getJsonFromDemobankConfig(demobank))
             return@get
         }
-        route("/demobanks/{demobankid}") {
 
+        route("/demobanks/{demobankid}") {
             // NOTE: TWG assumes that username == bank account label.
             route("/taler-wire-gateway") {
                 post("/{exchangeUsername}/admin/add-incoming") {
@@ -1082,7 +1082,15 @@ val sandboxApp: Application.() -> Unit = {
                         )
                     }
                     logger.debug("TWG add-incoming passed authentication")
-                    val body = call.receiveJson<TWGAdminAddIncoming>()
+                    val body = try {
+                        call.receiveJson<TWGAdminAddIncoming>()
+                    } catch (e: Exception) {
+                        logger.error("/admin/add-incoming failed at parsing 
the request body")
+                        throw SandboxError(
+                            HttpStatusCode.BadRequest,
+                            "Invalid request"
+                        )
+                    }
                     transaction {
                         val demobank = ensureDemobank(call)
                         val bankAccountCredit = 
getBankAccountFromLabel(username, demobank)
diff --git a/util/src/main/kotlin/HTTP.kt b/util/src/main/kotlin/HTTP.kt
index 368c2c87..387a7b05 100644
--- a/util/src/main/kotlin/HTTP.kt
+++ b/util/src/main/kotlin/HTTP.kt
@@ -153,6 +153,13 @@ fun getAuthorizationHeader(request: ApplicationRequest): 
String {
     )
 }
 
+// Builds the Authorization:-header value, given the credentials.
+fun buildBasicAuthLine(username: String, password: String): String {
+    val ret = "Basic "
+    val cred = "$username:$password"
+    val enc = bytesToBase64(cred.toByteArray(Charsets.UTF_8))
+    return ret+enc
+}
 /**
  * This helper function parses a Authorization:-header line, decode the 
credentials
  * and returns a pair made of username and hashed (sha256) password.  The 
hashed value

-- 
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]