[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.