gnunet-svn
[Top][All Lists]
Advanced

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

[libeufin] branch master updated (7677c4f1 -> 5d537b70)


From: gnunet
Subject: [libeufin] branch master updated (7677c4f1 -> 5d537b70)
Date: Mon, 14 Feb 2022 10:16:06 +0100

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

ms pushed a change to branch master
in repository libeufin.

    from 7677c4f1 optionally collecting IBAN along registration
     new 3e204b0b Setting JSON request parser as the default.
     new 5d537b70 Setting JSON request parser as the default.

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:
 .../tech/libeufin/nexus/ebics/EbicsClient.kt       |  5 ++-
 .../tech/libeufin/sandbox/EbicsProtocolBackend.kt  | 48 +++++++++++++--------
 .../src/main/kotlin/tech/libeufin/sandbox/Main.kt  | 48 +++++++++------------
 .../tech/libeufin/sandbox/XMLEbicsConverter.kt     | 49 ++++++++++++++++++++++
 4 files changed, 103 insertions(+), 47 deletions(-)
 create mode 100644 
sandbox/src/main/kotlin/tech/libeufin/sandbox/XMLEbicsConverter.kt

diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/EbicsClient.kt 
b/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/EbicsClient.kt
index f0242ceb..fdacdeb7 100644
--- a/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/EbicsClient.kt
+++ b/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/EbicsClient.kt
@@ -24,8 +24,9 @@ package tech.libeufin.nexus.ebics
 
 import io.ktor.client.HttpClient
 import io.ktor.client.features.*
-import io.ktor.client.request.post
-import io.ktor.http.HttpStatusCode
+import io.ktor.client.request.*
+import io.ktor.http.*
+import io.ktor.util.*
 import org.slf4j.Logger
 import org.slf4j.LoggerFactory
 import tech.libeufin.nexus.NexusError
diff --git 
a/sandbox/src/main/kotlin/tech/libeufin/sandbox/EbicsProtocolBackend.kt 
b/sandbox/src/main/kotlin/tech/libeufin/sandbox/EbicsProtocolBackend.kt
index 0594e934..cda505ab 100644
--- a/sandbox/src/main/kotlin/tech/libeufin/sandbox/EbicsProtocolBackend.kt
+++ b/sandbox/src/main/kotlin/tech/libeufin/sandbox/EbicsProtocolBackend.kt
@@ -23,7 +23,7 @@ package tech.libeufin.sandbox
 import io.ktor.application.*
 import io.ktor.http.ContentType
 import io.ktor.http.HttpStatusCode
-import io.ktor.request.receiveText
+import io.ktor.request.*
 import io.ktor.response.respond
 import io.ktor.response.respondText
 import io.ktor.util.AttributeKey
@@ -33,8 +33,6 @@ import org.jetbrains.exposed.sql.*
 import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
 import org.jetbrains.exposed.sql.statements.api.ExposedBlob
 import org.jetbrains.exposed.sql.transactions.transaction
-import org.slf4j.Logger
-import org.slf4j.LoggerFactory
 import org.w3c.dom.Document
 import tech.libeufin.util.*
 import tech.libeufin.util.XMLUtil.Companion.signEbicsResponse
@@ -46,8 +44,6 @@ import tech.libeufin.util.ebics_s001.UserSignatureData
 import java.math.BigDecimal
 import java.security.interfaces.RSAPrivateCrtKey
 import java.security.interfaces.RSAPublicKey
-import java.time.Instant
-import java.time.LocalDateTime
 import java.util.*
 import java.util.zip.DeflaterInputStream
 import java.util.zip.InflaterInputStream
@@ -124,6 +120,21 @@ suspend fun respondEbicsTransfer(
     errorText: String,
     errorCode: String
 ) {
+    /**
+     * Because this handler runs for any error, it could
+     * handle the case where the Ebics host ID is unknown due
+     * to an invalid request.  Recall: Sandbox is multi-host, and
+     * which Ebics host was requested belongs to the request document.
+     *
+     * Therefore, because any (? Please verify!) Ebics response
+     * should speak for one Ebics host, we won't respond any Ebics
+     * type when the Ebics host ID remains unknown due to invalid
+     * request.  Instead, we'll respond plain text:
+     */
+    if (!call.attributes.contains(EbicsHostIdAttribute)) {
+        call.respondText("Invalid document.", status = 
HttpStatusCode.BadRequest)
+        return
+    }
     val resp = EbicsResponse.createForUploadWithError(
         errorText,
         errorCode,
@@ -935,7 +946,7 @@ private suspend fun ApplicationCall.handleEbicsHpb(
 /**
  * Find the ebics host corresponding to the one specified in the header.
  */
-private fun ApplicationCall.ensureEbicsHost(requestHostID: String): 
EbicsHostPublicInfo {
+private fun ensureEbicsHost(requestHostID: String): EbicsHostPublicInfo {
     return transaction {
         val ebicsHost =
             EbicsHostEntity.find { EbicsHostsTable.hostID.upperCase() eq 
requestHostID.uppercase(Locale.getDefault()) }.firstOrNull()
@@ -952,22 +963,19 @@ private fun 
ApplicationCall.ensureEbicsHost(requestHostID: String): EbicsHostPub
         )
     }
 }
-
-private suspend fun ApplicationCall.receiveEbicsXml(): Document {
-    val body: String = receiveText()
-    logger.debug("Data received: $body")
-    val requestDocument: Document? = XMLUtil.parseStringIntoDom(body)
+fun receiveEbicsXmlInternal(xmlData: String): Document {
+    logger.debug("Data received: $xmlData")
+    val requestDocument: Document? = XMLUtil.parseStringIntoDom(xmlData)
     if (requestDocument == null || 
(!XMLUtil.validateFromDom(requestDocument))) {
         println("Problematic document was: $requestDocument")
         throw EbicsInvalidXmlError()
     }
-    val requestedHostID = requestDocument.getElementsByTagName("HostID")
-    this.attributes.put(
-        EbicsHostIdAttribute,
-        requestedHostID.item(0).textContent
-    )
     return requestDocument
 }
+suspend fun ApplicationCall.receiveEbicsXml(): Document {
+    val body: String = receiveText()
+    return receiveEbicsXmlInternal(body)
+}
 
 private fun makePartnerInfo(subscriber: EbicsSubscriberEntity): 
EbicsTypes.PartnerInfo {
     val bankAccount = getBankAccountFromSubscriber(subscriber)
@@ -1324,7 +1332,13 @@ private fun makeRequestContext(requestObject: 
EbicsRequest): RequestContext {
 }
 
 suspend fun ApplicationCall.ebicsweb() {
-    val requestDocument = receiveEbicsXml()
+    val requestDocument = this.request.call.receive<Document>()
+    val requestedHostID = requestDocument.getElementsByTagName("HostID")
+    this.attributes.put(
+        EbicsHostIdAttribute,
+        requestedHostID.item(0).textContent
+    )
+    // val requestDocument = receiveEbicsXml()
     logger.info("Processing ${requestDocument.documentElement.localName}")
     when (requestDocument.documentElement.localName) {
         "ebicsUnsecuredRequest" -> {
diff --git a/sandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt 
b/sandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt
index ca4a0db3..caf8167a 100644
--- a/sandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt
+++ b/sandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt
@@ -370,11 +370,6 @@ inline fun <reified T> Document.toObject(): T {
     return m.unmarshal(this, T::class.java).value
 }
 
-fun BigDecimal.signToString(): String {
-    return if (this.signum() > 0) "+" else ""
-    // minus sign is added by default already.
-}
-
 fun ensureNonNull(param: String?): String {
     return param ?: throw SandboxError(
         HttpStatusCode.BadRequest, "Bad ID given: $param"
@@ -426,25 +421,22 @@ val sandboxApp: Application.() -> Unit = {
         logger.info("Enabling CORS (assuming no endpoint uses cookies).")
         allowCredentials = true
     }
-    install(Authentication) {
-        // Web-based authentication for Bank customers.
-        form("auth-form") {
-            userParamName = "username"
-            passwordParamName = "password"
-            validate { credentials ->
-                if (credentials.name == "test") {
-                    UserIdPrincipal(credentials.name)
-                } else {
-                    null
-                }
-            }
-        }
-    }
     install(ContentNegotiation) {
-        jackson {
+        register(ContentType.Text.Xml, XMLEbicsConverter())
+        /**
+         * Content type "text" must go to the XML parser
+         * because Nexus can't set explicitly the Content-Type
+         * (see https://github.com/ktorio/ktor/issues/1127) to
+         * "xml" and the request made gets somehow assigned the
+         * "text/plain" type:  */
+        register(ContentType.Text.Plain, XMLEbicsConverter())
+        /**
+         * Make jackson the default parser.  It runs also when
+         * the Content-Type request header is missing. */
+        jackson(contentType = ContentType.Any) {
             
enable(com.fasterxml.jackson.databind.SerializationFeature.INDENT_OUTPUT)
             setDefaultPrettyPrinter(DefaultPrettyPrinter().apply {
-                
indentArraysWith(com.fasterxml.jackson.core.util.DefaultPrettyPrinter.FixedSpaceIndenter.instance)
+                
indentArraysWith(DefaultPrettyPrinter.FixedSpaceIndenter.instance)
                 indentObjectsWith(DefaultIndenter("  ", "\n"))
             })
             registerModule(KotlinModule(nullisSameAsDefault = true))
@@ -493,8 +485,8 @@ val sandboxApp: Application.() -> Unit = {
             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
+                ContentType.Text.Plain,
+                HttpStatusCode.InternalServerError
             )
         }
     }
@@ -530,7 +522,10 @@ val sandboxApp: Application.() -> Unit = {
     routing {
 
         get("/") {
-            call.respondText("Hello, this is the Sandbox\n", 
ContentType.Text.Plain)
+            call.respondText(
+                "Hello, this is the Sandbox\n",
+                ContentType.Text.Plain
+            )
         }
 
         // Respond with the last statement of the requesting account.
@@ -937,9 +932,7 @@ val sandboxApp: Application.() -> Unit = {
             }
             catch (e: Exception) {
                 logger.error(e)
-                if (e !is EbicsRequestError) {
-                    throw EbicsProcessingError("Unmanaged error: $e")
-                }
+                throw EbicsProcessingError("Unmanaged error: $e")
             }
             return@post
         }
@@ -990,7 +983,6 @@ val sandboxApp: Application.() -> Unit = {
             call.respond(getJsonFromDemobankConfig(demobank))
             return@get
         }
-
         route("/demobanks/{demobankid}") {
 
             // NOTE: TWG assumes that username == bank account label.
diff --git a/sandbox/src/main/kotlin/tech/libeufin/sandbox/XMLEbicsConverter.kt 
b/sandbox/src/main/kotlin/tech/libeufin/sandbox/XMLEbicsConverter.kt
new file mode 100644
index 00000000..64166daa
--- /dev/null
+++ b/sandbox/src/main/kotlin/tech/libeufin/sandbox/XMLEbicsConverter.kt
@@ -0,0 +1,49 @@
+package tech.libeufin.sandbox
+
+import io.ktor.application.*
+import io.ktor.features.*
+import io.ktor.http.*
+import io.ktor.http.content.*
+import io.ktor.request.*
+import io.ktor.response.*
+import io.ktor.util.pipeline.*
+import io.ktor.utils.io.*
+import io.ktor.utils.io.jvm.javaio.*
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.withContext
+import tech.libeufin.util.XMLUtil
+import java.io.OutputStream
+import java.nio.channels.ByteChannel
+
+class XMLEbicsConverter : ContentConverter {
+    override suspend fun convertForReceive(
+        context: PipelineContext<ApplicationReceiveRequest, ApplicationCall>): 
Any? {
+        val value = context.subject.value as? ByteReadChannel ?: return null
+        return withContext(Dispatchers.IO) {
+            receiveEbicsXmlInternal(value.toInputStream().reader().readText())
+        }
+    }
+    override suspend fun convertForSend(
+        context: PipelineContext<Any, ApplicationCall>,
+        contentType: ContentType,
+        value: Any
+    ): Any? {
+        val conv = try {
+            XMLUtil.convertJaxbToString(value)
+        } catch (e: Exception) {
+            /**
+             * Not always a error: the content negotiation might have
+             * only checked if this handler could convert the response.
+             */
+            logger.debug("Could not convert XML to string with custom 
converter.")
+            return null
+        }
+        return OutputStreamContent({
+            val out = this;
+            withContext(Dispatchers.IO) {
+                out.write(conv.toByteArray())
+            }},
+            contentType.withCharset(context.call.suitableCharset())
+        )
+    }
+}
\ 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]