gnunet-svn
[Top][All Lists]
Advanced

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

[libeufin] branch master updated: Avoid asking base URL in the env.


From: gnunet
Subject: [libeufin] branch master updated: Avoid asking base URL in the env.
Date: Wed, 13 Oct 2021 10:44:19 +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 856605c  Avoid asking base URL in the env.
856605c is described below

commit 856605c4048e47d05d4bcb583ed06c5f8cc36d28
Author: ms <ms@taler.net>
AuthorDate: Wed Oct 13 10:43:47 2021 +0200

    Avoid asking base URL in the env.
    
    Take it from X-Forwarded-* headers.
---
 .../tech/libeufin/nexus/server/NexusServer.kt      |   9 +-
 .../src/main/kotlin/tech/libeufin/sandbox/Main.kt  | 147 ++++++++++-----------
 util/src/main/kotlin/HTTP.kt                       |  39 ++++++
 3 files changed, 112 insertions(+), 83 deletions(-)

diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/server/NexusServer.kt 
b/nexus/src/main/kotlin/tech/libeufin/nexus/server/NexusServer.kt
index a9a2e64..cfa42f6 100644
--- a/nexus/src/main/kotlin/tech/libeufin/nexus/server/NexusServer.kt
+++ b/nexus/src/main/kotlin/tech/libeufin/nexus/server/NexusServer.kt
@@ -56,11 +56,6 @@ import java.net.URLEncoder
 import kotlin.system.exitProcess
 import java.net.URL
 
-private val baseUrl = URL(
-    getValueFromEnv("LIBEUFIN_NEXUS_BASE_URL") ?: throw Exception(
-        "env LIBEUFIN_NEXUS_BASE_URL is not defined")
-)
-
 /**
  * Return facade state depending on the type.
  */
@@ -901,7 +896,7 @@ val nexusApp: Application.() -> Unit = {
                     type = f.type,
                     baseUrl = call.url {
                         parameters.clear()
-                        encodedPath = baseUrl.path
+                        encodedPath = call.request.getBaseUrl()
                         pathComponents("facades", f.facadeName, f.type)
                         encodedPath += "/"
                     },
@@ -928,7 +923,7 @@ val nexusApp: Application.() -> Unit = {
                             type = it.type,
                             baseUrl = call.url {
                                 parameters.clear()
-                                encodedPath = baseUrl.path
+                                encodedPath = call.request.getBaseUrl()
                                 pathComponents("facades", it.facadeName, 
it.type)
                                 encodedPath += "/"
                             },
diff --git a/sandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt 
b/sandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt
index 1fe92c6..559e7eb 100644
--- a/sandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt
+++ b/sandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt
@@ -38,65 +38,53 @@ package tech.libeufin.sandbox
 
 import UtilError
 import com.fasterxml.jackson.core.JsonParseException
-import io.ktor.server.engine.embeddedServer
-import org.jetbrains.exposed.sql.*
-import org.jetbrains.exposed.sql.transactions.transaction
-import org.slf4j.Logger
-import org.slf4j.LoggerFactory
-import org.w3c.dom.Document
-import io.ktor.jackson.*
-import tech.libeufin.util.CryptoUtil
-import tech.libeufin.util.RawPayment
-import java.lang.ArithmeticException
-import java.math.BigDecimal
-import java.security.interfaces.RSAPublicKey
-import javax.xml.bind.JAXBContext
+import com.fasterxml.jackson.core.util.DefaultIndenter
+import com.fasterxml.jackson.core.util.DefaultPrettyPrinter
 import com.fasterxml.jackson.databind.exc.MismatchedInputException
+import com.fasterxml.jackson.module.kotlin.KotlinModule
 import com.fasterxml.jackson.module.kotlin.MissingKotlinParameterException
 import com.github.ajalt.clikt.core.CliktCommand
-import com.github.ajalt.clikt.core.ProgramResult
 import com.github.ajalt.clikt.core.context
-import com.github.ajalt.clikt.parameters.arguments.argument
 import com.github.ajalt.clikt.core.subcommands
 import com.github.ajalt.clikt.output.CliktHelpFormatter
+import com.github.ajalt.clikt.parameters.arguments.argument
 import com.github.ajalt.clikt.parameters.options.*
 import com.github.ajalt.clikt.parameters.types.int
 import execThrowableOrTerminate
-import io.ktor.application.ApplicationCall
-import io.ktor.application.call
-import io.ktor.application.install
-import org.jetbrains.exposed.sql.statements.api.ExposedBlob
-import com.fasterxml.jackson.core.util.DefaultIndenter
-import com.fasterxml.jackson.core.util.DefaultPrettyPrinter
-import com.fasterxml.jackson.module.kotlin.KotlinModule
-import 
org.jetbrains.exposed.sql.transactions.experimental.newSuspendedTransaction
-import io.ktor.features.StatusPages
-import io.ktor.response.respond
-import io.ktor.response.respondText
+import io.ktor.application.*
 import io.ktor.auth.*
+import io.ktor.features.*
 import io.ktor.http.*
+import io.ktor.jackson.*
 import io.ktor.request.*
+import io.ktor.response.*
 import io.ktor.routing.*
+import io.ktor.server.engine.*
 import io.ktor.server.netty.*
-import io.ktor.util.date.*
-import io.ktor.application.*
 import io.ktor.util.*
+import io.ktor.util.date.*
 import kotlinx.coroutines.newSingleThreadContext
+import org.jetbrains.exposed.sql.*
+import org.jetbrains.exposed.sql.statements.api.ExposedBlob
+import 
org.jetbrains.exposed.sql.transactions.experimental.newSuspendedTransaction
+import org.jetbrains.exposed.sql.transactions.transaction
+import org.slf4j.Logger
+import org.slf4j.LoggerFactory
+import org.w3c.dom.Document
 import startServer
 import tech.libeufin.util.*
 import validatePlainAmount
+import java.math.BigDecimal
 import java.net.BindException
 import java.net.URL
+import java.security.interfaces.RSAPublicKey
+import javax.xml.bind.JAXBContext
 import kotlin.system.exitProcess
 
 private val logger: Logger = LoggerFactory.getLogger("tech.libeufin.sandbox")
 private val currencyEnv: String? = getValueFromEnv("LIBEUFIN_SANDBOX_CURRENCY")
 private val envName: String? = getValueFromEnv("TALER_ENV_NAME")
 const val SANDBOX_DB_ENV_VAR_NAME = "LIBEUFIN_SANDBOX_DB_CONNECTION"
-private val baseUrl = URL(
-    getValueFromEnv("LIBEUFIN_SANDBOX_BASE_URL") ?: throw Exception(
-        "env LIBEUFIN_SANDBOX_BASE_URL is not defined")
-)
 // when null, privileged operations turn impossible
 private val sandboxToken: String? = getValueFromEnv("LIBEUFIN_SANDBOX_TOKEN")
 
@@ -258,6 +246,7 @@ class Serve : CliktCommand("Run sandbox HTTP server") {
         help = "Bind the Sandbox to the Unix domain socket at PATH.  
Overrides" +
                 "--port, when both are given", metavar = "PATH"
     )
+
     override fun run() {
         setLogLevel(logLevel)
         execThrowableOrTerminate { 
dbCreateTables(getDbConnFromEnv(SANDBOX_DB_ENV_VAR_NAME)) }
@@ -412,7 +401,8 @@ val sandboxApp: Application.() -> Unit = {
 
             val hostAuthPriv = transaction {
                 val host = tech.libeufin.sandbox.EbicsHostEntity.find {
-                    tech.libeufin.sandbox.EbicsHostsTable.hostID.upperCase() 
eq call.attributes.get(tech.libeufin.sandbox.EbicsHostIdAttribute).uppercase()
+                    tech.libeufin.sandbox.EbicsHostsTable.hostID.upperCase() 
eq call.attributes.get(tech.libeufin.sandbox.EbicsHostIdAttribute)
+                        .uppercase()
                 }.firstOrNull() ?: throw SandboxError(
                     io.ktor.http.HttpStatusCode.InternalServerError,
                     "Requested Ebics host ID not found."
@@ -451,59 +441,59 @@ val sandboxApp: Application.() -> Unit = {
         }
         exception<Throwable> { cause ->
             logger.error("Exception while handling '${call.request.uri}'", 
cause)
-            call.respondText("Internal server error.", 
io.ktor.http.ContentType.Text.Plain, 
io.ktor.http.HttpStatusCode.InternalServerError)
+            call.respondText(
+                "Internal server error.",
+                io.ktor.http.ContentType.Text.Plain,
+                io.ktor.http.HttpStatusCode.InternalServerError
+            )
         }
     }
-    intercept(io.ktor.application.ApplicationCallPipeline.Fallback) {
+    intercept(ApplicationCallPipeline.Fallback) {
         if (this.call.response.status() == null) {
-            call.respondText("Not found (no route matched).\n", 
io.ktor.http.ContentType.Text.Plain, io.ktor.http.HttpStatusCode.NotFound)
+            call.respondText(
+                "Not found (no route matched).\n",
+                io.ktor.http.ContentType.Text.Plain,
+                io.ktor.http.HttpStatusCode.NotFound
+            )
             return@intercept finish()
         }
     }
     routing {
 
         get("/") {
-            call.respondText("Hello, this is Sandbox\n", 
io.ktor.http.ContentType.Text.Plain)
+            call.respondText("Hello, this is Sandbox\n", 
ContentType.Text.Plain)
         }
-        get("/config") {
-            call.respond(object {
-                val name = "libeufin-sandbox"
 
-                // FIXME: use actual version here!
-                val version = "0.0.0-dev.0"
-            })
-        }
-        /**
-         * For now, only returns the last statement of the
-         * requesting account.
-         */
+        // Respond with the last statement of the requesting account.
+        // Query details in the body.
         post("/admin/payments/camt") {
             call.request.authWithToken(sandboxToken)
             val body = call.receiveJson<CamtParams>()
             val bankaccount = getAccountFromLabel(body.bankaccount)
             if (body.type != 53) throw SandboxError(
-                io.ktor.http.HttpStatusCode.NotFound,
+                HttpStatusCode.NotFound,
                 "Only Camt.053 documents can be generated."
             )
             val camtMessage = transaction {
-                tech.libeufin.sandbox.BankAccountStatementEntity.find {
-                    
tech.libeufin.sandbox.BankAccountStatementsTable.bankAccount eq bankaccount.id
+                BankAccountStatementEntity.find {
+                    BankAccountStatementsTable.bankAccount eq bankaccount.id
                 }.lastOrNull()?.xmlMessage ?: throw SandboxError(
-                    io.ktor.http.HttpStatusCode.NotFound,
+                    HttpStatusCode.NotFound,
                     "Could not find any statements; please wait next tick"
                 )
             }
             call.respondText(
-                camtMessage, io.ktor.http.ContentType.Text.Xml, 
io.ktor.http.HttpStatusCode.OK
+                camtMessage, ContentType.Text.Xml, HttpStatusCode.OK
             )
             return@post
         }
 
+        // create a new bank account, no EBICS relation.
         post("/admin/bank-accounts/{label}") {
             call.request.authWithToken(sandboxToken)
             val body = call.receiveJson<BankAccountInfo>()
             transaction {
-                tech.libeufin.sandbox.BankAccountEntity.new {
+                BankAccountEntity.new {
                     iban = body.iban
                     bic = body.bic
                     name = body.name
@@ -515,6 +505,7 @@ val sandboxApp: Application.() -> Unit = {
             return@post
         }
 
+        // Information about one bank account.
         get("/admin/bank-accounts/{label}") {
             call.request.authWithToken(sandboxToken)
             val label = ensureNonNull(call.parameters["label"])
@@ -538,6 +529,8 @@ val sandboxApp: Application.() -> Unit = {
             return@get
         }
 
+        // Book one incoming payment for the requesting account.
+        // The debtor is not required to have an account at this Sandbox.
         post("/admin/bank-accounts/{label}/simulate-incoming-transaction") {
             call.request.authWithToken(sandboxToken)
             val body = call.receiveJson<IncomingPaymentInfo>()
@@ -578,9 +571,8 @@ val sandboxApp: Application.() -> Unit = {
             call.respond(object {})
         }
 
-        /**
-         * Associates a new bank account with an existing Ebics subscriber.
-         */
+
+        // Associates a new bank account with an existing Ebics subscriber.
         post("/admin/ebics/bank-accounts") {
             call.request.authWithToken(sandboxToken)
             val body = call.receiveJson<BankAccountRequest>()
@@ -611,6 +603,8 @@ val sandboxApp: Application.() -> Unit = {
             call.respondText("Bank account created")
             return@post
         }
+
+        // Information about all the bank accounts.
         get("/admin/bank-accounts") {
             call.request.authWithToken(sandboxToken)
             val accounts = mutableListOf<BankAccountInfo>()
@@ -629,6 +623,8 @@ val sandboxApp: Application.() -> Unit = {
             }
             call.respond(accounts)
         }
+
+        // Details of all the transactions of one bank account.
         get("/admin/bank-accounts/{label}/transactions") {
             call.request.authWithToken(sandboxToken)
             val ret = AccountTransactions()
@@ -668,6 +664,10 @@ val sandboxApp: Application.() -> Unit = {
             }
             call.respond(ret)
         }
+
+        // Generate one incoming and one outgoing transactions for
+        // one bank account.  Counterparts do not need to have an account
+        // at this Sandbox.
         post("/admin/bank-accounts/{label}/generate-transactions") {
             call.request.authWithToken(sandboxToken)
             transaction {
@@ -698,7 +698,7 @@ val sandboxApp: Application.() -> Unit = {
                 run {
                     val amount = kotlin.random.Random.nextLong(5, 25)
 
-                    tech.libeufin.sandbox.BankAccountTransactionEntity.new {
+                    BankAccountTransactionEntity.new {
                         debtorIban = account.iban
                         debtorBic = account.bic
                         debtorName = account.name
@@ -717,9 +717,8 @@ val sandboxApp: Application.() -> Unit = {
             }
             call.respond(object {})
         }
-        /**
-         * Creates a new Ebics subscriber.
-         */
+
+        // Creates a new Ebics subscriber.
         post("/admin/ebics/subscribers") {
             call.request.authWithToken(sandboxToken)
             val body = call.receiveJson<EbicsSubscriberElement>()
@@ -739,9 +738,8 @@ val sandboxApp: Application.() -> Unit = {
             )
             return@post
         }
-        /**
-         * Shows all the Ebics subscribers' details.
-         */
+
+        // Shows details of all the EBICS subscribers of this Sandbox.
         get("/admin/ebics/subscribers") {
             call.request.authWithToken(sandboxToken)
             val ret = AdminGetSubscribers()
@@ -759,6 +757,8 @@ val sandboxApp: Application.() -> Unit = {
             call.respond(ret)
             return@get
         }
+
+        // Change keys used in the EBICS communications.
         post("/admin/ebics/hosts/{hostID}/rotate-keys") {
             call.request.authWithToken(sandboxToken)
             val hostID: String = call.parameters["hostID"] ?: throw 
SandboxError(
@@ -785,9 +785,7 @@ val sandboxApp: Application.() -> Unit = {
             return@post
         }
 
-        /**
-         * Creates a new EBICS host.
-         */
+        // Create a new EBICS host
         post("/admin/ebics/hosts") {
             call.request.authWithToken(sandboxToken)
             val req = call.receiveJson<EbicsHostCreateRequest>()
@@ -811,9 +809,7 @@ val sandboxApp: Application.() -> Unit = {
             return@post
         }
 
-        /**
-         * Show the names of all the Ebics hosts
-         */
+        // Show the names of all the Ebics hosts
         get("/admin/ebics/hosts") {
             call.request.authWithToken(sandboxToken)
             val ebicsHosts = transaction {
@@ -821,9 +817,8 @@ val sandboxApp: Application.() -> Unit = {
             }
             call.respond(EbicsHostsResponse(ebicsHosts))
         }
-        /**
-         * Serves all the Ebics requests.
-         */
+
+        // Process one EBICS request
         post("/ebicsweb") {
             try {
                 call.ebicsweb()
@@ -848,6 +843,7 @@ val sandboxApp: Application.() -> Unit = {
             }
 
         }
+
         /**
          * Activates a withdraw operation of 1 currency unit with
          * the default exchange, from a designated/constant customer.
@@ -879,9 +875,7 @@ val sandboxApp: Application.() -> Unit = {
                     // wopid is autogenerated, and momentarily the only column
                 }
             }
-            /**
-             * Future versions will include the QR code in this response.
-             */
+            val baseUrl = URL(call.request.getBaseUrl())
             val ret = call.url {
                 protocol = URLProtocol(
                     "taler".plus(if (baseUrl.protocol.lowercase() == "http") 
"+http" else ""),
@@ -1055,6 +1049,7 @@ val sandboxApp: Application.() -> Unit = {
         }
     }
 }
+
 fun serverMain(port: Int) {
     val server = embeddedServer(Netty, port = port, module = sandboxApp)
     logger.info("LibEuFin Sandbox running on port $port")
diff --git a/util/src/main/kotlin/HTTP.kt b/util/src/main/kotlin/HTTP.kt
index d74d7b2..7c3528f 100644
--- a/util/src/main/kotlin/HTTP.kt
+++ b/util/src/main/kotlin/HTTP.kt
@@ -1,8 +1,10 @@
 package tech.libeufin.util
 
 import UtilError
+import io.ktor.application.*
 import io.ktor.http.*
 import io.ktor.request.*
+import io.ktor.util.*
 import logger
 import java.net.URLDecoder
 
@@ -33,6 +35,43 @@ fun extractToken(authHeader: String): String {
     return "${tokenSplit[0]}:${URLDecoder.decode(tokenSplit[1], 
Charsets.UTF_8)}"
 }
 
+private fun internalServerError(
+    reason: String,
+    libeufinErrorCode: LibeufinErrorCode? = LibeufinErrorCode.LIBEUFIN_EC_NONE
+): UtilError {
+    return UtilError(
+        HttpStatusCode.InternalServerError,
+        reason,
+        ec = libeufinErrorCode
+    )
+}
+/**
+ * Get the base URL of a request; handles proxied case.
+ */
+fun ApplicationRequest.getBaseUrl(): String {
+
+    val isProxied = this.headers.contains("X-Forwarded-Host")
+    return if (isProxied) {
+        URLBuilder(
+            protocol = URLProtocol(
+                name = this.headers.get("X-Forwarded-Proto") ?: throw 
internalServerError("Reverse proxy did not define X-Forwarded-Proto"),
+                defaultPort = -1 // Port must be specified with 
X-Forwarded-Host.
+            ),
+            host = this.headers.get("X-Forwarded-Host") ?: throw 
internalServerError(
+                "Reverse proxy did not define X-Forwarded-Host"
+            ),
+            encodedPath = this.headers.get("X-Forwarded-Prefix") ?: throw 
internalServerError(
+                "Reverse proxy did not define X-Forwarded-Prefix"
+            )
+        ).toString()
+    } else {
+        this.call.url {
+            parameters.clear()
+            encodedPath = "/"
+        }
+    }
+}
+
 /**
  * Authenticate the HTTP request with a given token.  This one
  * is expected to comply with the RFC 8959 format; the function

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