gnunet-svn
[Top][All Lists]
Advanced

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

[libeufin] 01/02: (re)implement /admin/add-incoming


From: gnunet
Subject: [libeufin] 01/02: (re)implement /admin/add-incoming
Date: Fri, 08 Jul 2022 16:48:02 +0200

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

ms pushed a commit to branch master
in repository libeufin.

commit 24838e2d9451d90e59d211cb9cd13baadb278742
Author: MS <ms@taler.net>
AuthorDate: Fri Jul 8 13:10:58 2022 +0200

    (re)implement /admin/add-incoming
---
 cli/bin/libeufin-cli                               |  8 ++-
 nexus/src/main/kotlin/tech/libeufin/nexus/Taler.kt | 78 +++++++++++++++++++++-
 .../src/main/kotlin/tech/libeufin/sandbox/Main.kt  | 12 +++-
 util/src/main/kotlin/HTTP.kt                       |  7 ++
 4 files changed, 99 insertions(+), 6 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..43d9ae45 100644
--- a/nexus/src/main/kotlin/tech/libeufin/nexus/Taler.kt
+++ b/nexus/src/main/kotlin/tech/libeufin/nexus/Taler.kt
@@ -22,15 +22,18 @@ 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.*
@@ -39,7 +42,7 @@ import tech.libeufin.nexus.bankaccount.addPaymentInitiation
 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
 
@@ -455,6 +458,71 @@ 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 sandboxUrl = 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 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"
+            )
+
+        }
+    }
+    val client = HttpClient { followRedirects = true }
+    val resp = try {
+        client.post<String>(
+            urlString = sandboxUrl,
+            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")
+    }
+    call.respond(resp)
+}
+
 private fun getCurrency(facadeName: String): String {
     return transaction {
         getFacadeState(facadeName).currency
@@ -487,6 +555,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/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]