gnunet-svn
[Top][All Lists]
Advanced

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

[libeufin] branch master updated: Sending C52 to the bank.


From: gnunet
Subject: [libeufin] branch master updated: Sending C52 to the bank.
Date: Thu, 28 Nov 2019 18:35:57 +0100

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

marcello pushed a commit to branch master
in repository libeufin.

The following commit(s) were added to refs/heads/master by this push:
     new 0a5fec8  Sending C52 to the bank.
0a5fec8 is described below

commit 0a5fec853dac05f66dce1ea857ff1579fe0a935e
Author: Marcello Stanisci <address@hidden>
AuthorDate: Thu Nov 28 18:35:34 2019 +0100

    Sending C52 to the bank.
---
 nexus/src/main/kotlin/Helpers.kt                   | 300 +++++++++++++++++++++
 nexus/src/main/kotlin/JSON.kt                      |   6 +
 nexus/src/main/kotlin/Main.kt                      | 267 +++---------------
 .../libeufin/schema/ebics_h004/EbicsRequest.kt     |  35 +++
 4 files changed, 380 insertions(+), 228 deletions(-)

diff --git a/nexus/src/main/kotlin/Helpers.kt b/nexus/src/main/kotlin/Helpers.kt
new file mode 100644
index 0000000..e46d144
--- /dev/null
+++ b/nexus/src/main/kotlin/Helpers.kt
@@ -0,0 +1,300 @@
+package tech.libeufin.nexus
+
+import io.ktor.client.HttpClient
+import io.ktor.client.request.post
+import io.ktor.http.HttpStatusCode
+import tech.libeufin.sandbox.CryptoUtil
+import tech.libeufin.sandbox.XMLUtil
+import tech.libeufin.sandbox.logger
+import tech.libeufin.sandbox.toByteArray
+import tech.libeufin.schema.ebics_h004.EbicsRequest
+import tech.libeufin.schema.ebics_s001.UserSignatureData
+import java.math.BigInteger
+import java.security.PrivateKey
+import java.security.SecureRandom
+import java.security.interfaces.RSAPrivateCrtKey
+import java.security.interfaces.RSAPublicKey
+import java.util.*
+import javax.xml.bind.JAXBElement
+import javax.xml.datatype.DatatypeFactory
+import javax.xml.datatype.XMLGregorianCalendar
+
+fun createDownloadInitializationPhase(
+    subscriberData: EbicsContainer,
+    orderType: String,
+    nonce: ByteArray,
+    date: XMLGregorianCalendar
+): EbicsRequest {
+
+    return EbicsRequest.createForDownloadInitializationPhase(
+        subscriberData.userId,
+        subscriberData.partnerId,
+        subscriberData.hostId,
+        nonce,
+        date,
+        subscriberData.bankEncPub ?: throw 
BankKeyMissing(HttpStatusCode.PreconditionFailed),
+        subscriberData.bankAuthPub ?: throw 
BankKeyMissing(HttpStatusCode.PreconditionFailed),
+        orderType
+    )
+}
+
+
+fun createDownloadInitializationPhase(
+    subscriberData: EbicsContainer,
+    orderType: String,
+    nonce: ByteArray,
+    date: XMLGregorianCalendar,
+    dateStart: XMLGregorianCalendar,
+    dateEnd: XMLGregorianCalendar
+): EbicsRequest {
+
+    return EbicsRequest.createForDownloadInitializationPhase(
+        subscriberData.userId,
+        subscriberData.partnerId,
+        subscriberData.hostId,
+        nonce,
+        date,
+        subscriberData.bankEncPub ?: throw 
BankKeyMissing(HttpStatusCode.PreconditionFailed),
+        subscriberData.bankAuthPub ?: throw 
BankKeyMissing(HttpStatusCode.PreconditionFailed),
+        orderType,
+        dateStart,
+        dateEnd
+    )
+}
+
+
+fun createUploadInitializationPhase(
+    subscriberData: EbicsContainer,
+    orderType: String,
+    cryptoBundle: CryptoUtil.EncryptionResult,
+    nonce: ByteArray,
+    date: XMLGregorianCalendar
+): EbicsRequest {
+
+    return EbicsRequest.createForUploadInitializationPhase(
+        cryptoBundle,
+        subscriberData.hostId,
+        getNonce(128),
+        subscriberData.partnerId,
+        subscriberData.userId,
+        getGregorianDate(),
+        subscriberData.bankAuthPub!!,
+        subscriberData.bankEncPub!!,
+        BigInteger.ONE,
+        orderType
+    )
+}
+
+fun containerInit(subscriber: EbicsSubscriberEntity): EbicsContainer {
+
+    var bankAuthPubValue: RSAPublicKey? = null
+    if (subscriber.bankAuthenticationPublicKey != null) {
+        bankAuthPubValue = CryptoUtil.loadRsaPublicKey(
+            subscriber.bankAuthenticationPublicKey?.toByteArray()!!
+        )
+    }
+    var bankEncPubValue: RSAPublicKey? = null
+    if (subscriber.bankEncryptionPublicKey != null) {
+        bankEncPubValue = CryptoUtil.loadRsaPublicKey(
+            subscriber.bankEncryptionPublicKey?.toByteArray()!!
+        )
+    }
+
+    return EbicsContainer(
+        bankAuthPub = bankAuthPubValue,
+        bankEncPub = bankEncPubValue,
+
+        ebicsUrl = subscriber.ebicsURL,
+        hostId = subscriber.hostID,
+        userId = subscriber.userID,
+        partnerId = subscriber.partnerID,
+
+        customerSignPriv = 
CryptoUtil.loadRsaPrivateKey(subscriber.signaturePrivateKey.toByteArray()),
+        customerAuthPriv = 
CryptoUtil.loadRsaPrivateKey(subscriber.authenticationPrivateKey.toByteArray()),
+        customerEncPriv = 
CryptoUtil.loadRsaPrivateKey(subscriber.authenticationPrivateKey.toByteArray())
+    )
+
+}
+
+/**
+ * Inserts spaces every 2 characters, and a newline after 8 pairs.
+ */
+fun chunkString(input: String): String {
+
+    val ret = StringBuilder()
+    var columns = 0
+
+    for (i in input.indices) {
+
+        if ((i + 1).rem(2) == 0) {
+
+            if (columns == 7) {
+                ret.append(input[i] + "\n")
+                columns = 0
+                continue
+            }
+
+            ret.append(input[i] + " ")
+            columns++
+            continue
+        }
+        ret.append(input[i])
+    }
+
+    return ret.toString()
+
+}
+
+fun expectId(param: String?): Int {
+
+    try {
+        return param!!.toInt()
+    } catch (e: Exception) {
+        throw NotAnIdError(HttpStatusCode.BadRequest)
+    }
+}
+
+fun signOrder(
+    orderBlob: ByteArray,
+    signKey: RSAPrivateCrtKey,
+    partnerId: String,
+    userId: String
+): UserSignatureData {
+
+    val ES_signature = CryptoUtil.signEbicsA006(
+        CryptoUtil.digestEbicsOrderA006(orderBlob),
+        signKey
+    )
+    val userSignatureData = UserSignatureData().apply {
+        orderSignatureList = listOf(
+            UserSignatureData.OrderSignatureData().apply {
+                signatureVersion = "A006"
+                signatureValue = ES_signature
+                partnerID = partnerId
+                userID = userId
+            }
+        )
+    }
+
+    return userSignatureData
+}
+
+
+/**
+ * @return null when the bank could not be reached, otherwise returns the
+ * response already converted in JAXB.
+ */
+suspend inline fun HttpClient.postToBank(url: String, body: String): String {
+
+    val response = try {
+        this.post<String>(
+            urlString = url,
+            block = {
+                this.body = body
+            }
+        )
+    } catch (e: Exception) {
+        throw UnreachableBankError(HttpStatusCode.InternalServerError)
+    }
+
+    return response
+}
+
+/**
+ * DO verify the bank's signature
+ */
+suspend inline fun <reified T, reified S> HttpClient.postToBankSignedAndVerify(
+    url: String,
+    body: T,
+    pub: RSAPublicKey,
+    priv: RSAPrivateCrtKey
+): JAXBElement<S> {
+
+    val doc = XMLUtil.convertJaxbToDocument(body)
+    XMLUtil.signEbicsDocument(doc, priv)
+
+    val response: String = this.postToBank(url, 
XMLUtil.convertDomToString(doc))
+    logger.debug("About to verify: ${response}")
+
+    val responseString = try {
+
+        XMLUtil.parseStringIntoDom(response)
+    } catch (e: Exception) {
+
+        throw UnparsableResponse(HttpStatusCode.BadRequest, response)
+    }
+
+    if (!XMLUtil.verifyEbicsDocument(responseString, pub)) {
+
+        throw BadSignature(HttpStatusCode.NotAcceptable)
+    }
+
+    try {
+
+        return XMLUtil.convertStringToJaxb(response)
+    } catch (e: Exception) {
+
+        throw UnparsableResponse(HttpStatusCode.BadRequest, response)
+    }
+}
+
+suspend inline fun <reified T, reified S> HttpClient.postToBankSigned(
+    url: String,
+    body: T,
+    priv: PrivateKey
+): JAXBElement<S> {
+
+    val doc = XMLUtil.convertJaxbToDocument(body)
+    XMLUtil.signEbicsDocument(doc, priv)
+
+    val response: String = this.postToBank(url, 
XMLUtil.convertDomToString(doc))
+
+    try {
+        return XMLUtil.convertStringToJaxb(response)
+    } catch (e: Exception) {
+        throw UnparsableResponse(HttpStatusCode.BadRequest, response)
+    }
+}
+
+
+
+/**
+ * do NOT verify the bank's signature
+ */
+suspend inline fun <reified T, reified S> HttpClient.postToBankUnsigned(
+    url: String,
+    body: T
+): JAXBElement<S> {
+
+    val response: String = this.postToBank(url, 
XMLUtil.convertJaxbToString(body))
+
+    try {
+        return XMLUtil.convertStringToJaxb(response)
+    } catch (e: Exception) {
+        throw UnparsableResponse(HttpStatusCode.BadRequest, response)
+    }
+}
+
+/**
+ * @param size in bits
+ */
+fun getNonce(size: Int): ByteArray {
+    val sr = SecureRandom()
+    val ret = ByteArray(size / 8)
+    sr.nextBytes(ret)
+    return ret
+}
+
+/* explicit point in time */
+fun getGregorianDate(year: Int, month: Int, day: Int): XMLGregorianCalendar {
+    val gregorianCalendar = GregorianCalendar(year, month, day)
+    val datatypeFactory = DatatypeFactory.newInstance()
+    return datatypeFactory.newXMLGregorianCalendar(gregorianCalendar)
+}
+
+/* now */
+fun getGregorianDate(): XMLGregorianCalendar {
+    val gregorianCalendar = GregorianCalendar()
+    val datatypeFactory = DatatypeFactory.newInstance()
+    return datatypeFactory.newXMLGregorianCalendar(gregorianCalendar)
+}
diff --git a/nexus/src/main/kotlin/JSON.kt b/nexus/src/main/kotlin/JSON.kt
index 42aa7ee..605bade 100644
--- a/nexus/src/main/kotlin/JSON.kt
+++ b/nexus/src/main/kotlin/JSON.kt
@@ -9,6 +9,12 @@ data class EbicsBackupRequest(
     val passphrase: String
 )
 
+
+data class EbicsDateRange(
+    val start: String, // ISO 8601 calendar date
+    val end: String // ISO 8601 calendar date
+)
+
 /**
  * This object is used twice: as a response to the backup request,
  * and as a request to the backup restore.  Note: in the second case
diff --git a/nexus/src/main/kotlin/Main.kt b/nexus/src/main/kotlin/Main.kt
index d240e21..21c3b6f 100644
--- a/nexus/src/main/kotlin/Main.kt
+++ b/nexus/src/main/kotlin/Main.kt
@@ -60,6 +60,7 @@ import javax.crypto.EncryptedPrivateKeyInfo
 import javax.xml.datatype.DatatypeFactory
 import javax.xml.datatype.XMLGregorianCalendar
 import java.security.interfaces.RSAPublicKey
+import java.time.LocalDate
 
 
 fun testData() {
@@ -82,212 +83,6 @@ fun testData() {
     }
 }
 
-fun containerInit(subscriber: EbicsSubscriberEntity): EbicsContainer {
-
-    var bankAuthPubValue: RSAPublicKey? = null
-    if (subscriber.bankAuthenticationPublicKey != null) {
-        bankAuthPubValue = CryptoUtil.loadRsaPublicKey(
-            subscriber.bankAuthenticationPublicKey?.toByteArray()!!
-        )
-    }
-    var bankEncPubValue: RSAPublicKey? = null
-    if (subscriber.bankEncryptionPublicKey != null) {
-        bankEncPubValue = CryptoUtil.loadRsaPublicKey(
-            subscriber.bankEncryptionPublicKey?.toByteArray()!!
-        )
-    }
-
-    return EbicsContainer(
-
-
-        bankAuthPub = bankAuthPubValue,
-        bankEncPub = bankEncPubValue,
-
-        ebicsUrl = subscriber.ebicsURL,
-        hostId = subscriber.hostID,
-        userId = subscriber.userID,
-        partnerId = subscriber.partnerID,
-
-        customerSignPriv = 
CryptoUtil.loadRsaPrivateKey(subscriber.signaturePrivateKey.toByteArray()),
-        customerAuthPriv = 
CryptoUtil.loadRsaPrivateKey(subscriber.authenticationPrivateKey.toByteArray()),
-        customerEncPriv = 
CryptoUtil.loadRsaPrivateKey(subscriber.authenticationPrivateKey.toByteArray())
-    )
-
-}
-
-/**
- * Inserts spaces every 2 characters, and a newline after 8 pairs.
- */
-fun chunkString(input: String): String {
-
-    val ret = StringBuilder()
-    var columns = 0
-
-    for (i in input.indices) {
-
-        if ((i + 1).rem(2) == 0) {
-
-            if (columns == 7) {
-                ret.append(input[i] + "\n")
-                columns = 0
-                continue
-            }
-
-            ret.append(input[i] + " ")
-            columns++
-            continue
-        }
-        ret.append(input[i])
-    }
-
-    return ret.toString()
-
-}
-
-fun expectId(param: String?): Int {
-
-    try {
-        return param!!.toInt()
-    } catch (e: Exception) {
-        throw NotAnIdError(HttpStatusCode.BadRequest)
-    }
-}
-
-fun signOrder(
-    orderBlob: ByteArray,
-    signKey: RSAPrivateCrtKey,
-    partnerId: String,
-    userId: String
-): UserSignatureData {
-
-    val ES_signature = CryptoUtil.signEbicsA006(
-        CryptoUtil.digestEbicsOrderA006(orderBlob),
-        signKey
-    )
-    val userSignatureData = UserSignatureData().apply {
-        orderSignatureList = listOf(
-            UserSignatureData.OrderSignatureData().apply {
-                signatureVersion = "A006"
-                signatureValue = ES_signature
-                partnerID = partnerId
-                userID = userId
-            }
-        )
-    }
-
-    return userSignatureData
-}
-
-
-/**
- * @return null when the bank could not be reached, otherwise returns the
- * response already converted in JAXB.
- */
-suspend inline fun HttpClient.postToBank(url: String, body: String): String {
-
-    val response = try {
-        this.post<String>(
-            urlString = url,
-            block = {
-                this.body = body
-            }
-        )
-    } catch (e: Exception) {
-        throw UnreachableBankError(HttpStatusCode.InternalServerError)
-    }
-
-    return response
-}
-
-/**
- * DO verify the bank's signature
- */
-suspend inline fun <reified T, reified S>HttpClient.postToBankSignedAndVerify(
-    url: String,
-    body: T,
-    pub: RSAPublicKey,
-    priv: RSAPrivateCrtKey): JAXBElement<S> {
-
-    val doc = XMLUtil.convertJaxbToDocument(body)
-    XMLUtil.signEbicsDocument(doc, priv)
-
-    val response: String = this.postToBank(url, 
XMLUtil.convertDomToString(doc))
-    logger.debug("About to verify: ${response}")
-
-    val responseString = try {
-
-        XMLUtil.parseStringIntoDom(response)
-    } catch (e: Exception) {
-
-        throw UnparsableResponse(HttpStatusCode.BadRequest, response)
-    }
-
-    if (!XMLUtil.verifyEbicsDocument(responseString, pub)) {
-
-        throw BadSignature(HttpStatusCode.NotAcceptable)
-    }
-
-    try {
-
-        return XMLUtil.convertStringToJaxb(response)
-    } catch (e: Exception) {
-
-        throw UnparsableResponse(HttpStatusCode.BadRequest, response)
-    }
-}
-
-suspend inline fun <reified T, reified S>HttpClient.postToBankSigned(
-    url: String,
-    body: T,
-    priv: PrivateKey): JAXBElement<S> {
-
-    val doc = XMLUtil.convertJaxbToDocument(body)
-    XMLUtil.signEbicsDocument(doc, priv)
-
-    val response: String = this.postToBank(url, 
XMLUtil.convertDomToString(doc))
-
-    try {
-        return XMLUtil.convertStringToJaxb(response)
-    } catch (e: Exception) {
-        throw UnparsableResponse(HttpStatusCode.BadRequest, response)
-    }
-}
-
-
-
-/**
- * do NOT verify the bank's signature
- */
-suspend inline fun <reified T, reified S>HttpClient.postToBankUnsigned(
-    url: String,
-    body: T
-): JAXBElement<S> {
-
-    val response: String = this.postToBank(url, 
XMLUtil.convertJaxbToString(body))
-
-    try {
-        return XMLUtil.convertStringToJaxb(response)
-    } catch (e: Exception) {
-        throw UnparsableResponse(HttpStatusCode.BadRequest, response)
-    }
-}
-
-/**
- * @param size in bits
- */
-fun getNonce(size: Int): ByteArray {
-    val sr = SecureRandom()
-    val ret = ByteArray(size / 8)
-    sr.nextBytes(ret)
-    return ret
-}
-
-fun getGregorianDate(): XMLGregorianCalendar {
-    val gregorianCalendar = GregorianCalendar()
-    val datatypeFactory = DatatypeFactory.newInstance()
-    return datatypeFactory.newXMLGregorianCalendar(gregorianCalendar)
-}
-
 data class NotAnIdError(val statusCode: HttpStatusCode) : Exception("String ID 
not convertible in number")
 data class BankKeyMissing(val statusCode: HttpStatusCode) : 
Exception("Impossible operation: bank keys are missing")
 data class SubscriberNotFoundError(val statusCode: HttpStatusCode) : 
Exception("Subscriber not found in database")
@@ -398,27 +193,50 @@ fun main() {
                 return@get
             }
 
-            get("/ebics/subscribers/{id}/sendHtd") {
+            post("/ebics/subscribers/{id}/sendC52") {
                 val id = expectId(call.parameters["id"])
+                val body = call.receive<EbicsDateRange>()
+
+                val startDate = LocalDate.parse(body.start)
+                val endDate = LocalDate.parse(body.end)
+                // will throw DateTimeParseException if strings are malformed.
+
+
                 val subscriberData = transaction {
                     containerInit(EbicsSubscriberEntity.findById(id) ?: throw 
SubscriberNotFoundError(HttpStatusCode.NotFound))
                 }
 
-
                 val response = client.postToBankSigned<EbicsRequest, 
EbicsResponse>(
                     subscriberData.ebicsUrl,
-                    EbicsRequest.createForDownloadInitializationPhase(
-                        subscriberData.userId,
-                        subscriberData.partnerId,
-                        subscriberData.hostId,
+                    createDownloadInitializationPhase(
+                        subscriberData,
+                        "C52",
                         getNonce(128),
                         getGregorianDate(),
-                        subscriberData.bankEncPub ?: throw 
BankKeyMissing(HttpStatusCode.PreconditionFailed),
-                        subscriberData.bankAuthPub ?: throw 
BankKeyMissing(HttpStatusCode.PreconditionFailed),
-                        "HTD"
+                        getGregorianDate(startDate.year, startDate.monthValue, 
startDate.dayOfMonth),
+                        getGregorianDate(endDate.year, endDate.monthValue, 
endDate.dayOfMonth)
                     ),
                     subscriberData.customerAuthPriv
                 )
+            }
+
+            get("/ebics/subscribers/{id}/sendHtd") {
+                val id = expectId(call.parameters["id"])
+                val subscriberData = transaction {
+                    containerInit(EbicsSubscriberEntity.findById(id) ?: throw 
SubscriberNotFoundError(HttpStatusCode.NotFound))
+                }
+
+                val response = client.postToBankSigned<EbicsRequest, 
EbicsResponse>(
+                    subscriberData.ebicsUrl,
+                    createDownloadInitializationPhase(
+                        subscriberData,
+                        "HTD",
+                        getNonce(128),
+                        getGregorianDate()
+                    ),
+                    subscriberData.customerAuthPriv
+                )
+
                 logger.debug("HTD response: " + 
XMLUtil.convertJaxbToString<EbicsResponse>(response.value))
 
                 if (response.value.body.returnCode.value != "000000") {
@@ -790,7 +608,6 @@ fun main() {
                         EbicsSubscriberEntity.findById(id) ?: throw 
SubscriberNotFoundError(HttpStatusCode.NotFound)
                     )
                 }
-
                 val payload = "PAYLOAD"
                 val usd_encrypted = CryptoUtil.encryptEbicsE002(
                     EbicsOrderUtil.encodeOrderDataXml(
@@ -807,20 +624,15 @@ fun main() {
 
                 val response = client.postToBankSignedAndVerify<EbicsRequest, 
EbicsResponse>(
                     subscriberData.ebicsUrl,
-                    EbicsRequest.createForUploadInitializationPhase(
+                    createUploadInitializationPhase(
+                        subscriberData,
+                        "TST",
                         usd_encrypted,
-                        subscriberData.hostId,
                         getNonce(128),
-                        subscriberData.partnerId,
-                        subscriberData.userId,
-                        getGregorianDate(),
-                        subscriberData.bankAuthPub!!,
-                        subscriberData.bankEncPub!!,
-                        BigInteger.ONE,
-                        "TST"
+                        getGregorianDate()
                     ),
                     subscriberData.bankAuthPub!!,
-                    subscriberData.customerAuthPriv
+                    subscriberData.customerEncPriv
                 )
 
                 if (response.value.body.returnCode.value != "000000") {
@@ -865,8 +677,7 @@ fun main() {
                     HttpStatusCode.OK
                 )
             }
-
-
+            
             post("/ebics/subscribers/{id}/sync") {
                 val id = expectId(call.parameters["id"])
                 val bundle = transaction {
diff --git 
a/sandbox/src/main/kotlin/tech/libeufin/schema/ebics_h004/EbicsRequest.kt 
b/sandbox/src/main/kotlin/tech/libeufin/schema/ebics_h004/EbicsRequest.kt
index da756fb..b733c95 100644
--- a/sandbox/src/main/kotlin/tech/libeufin/schema/ebics_h004/EbicsRequest.kt
+++ b/sandbox/src/main/kotlin/tech/libeufin/schema/ebics_h004/EbicsRequest.kt
@@ -305,6 +305,41 @@ class EbicsRequest {
 
         }
 
+        /* Take a time range (useful for C52 and C53) */
+        fun createForDownloadInitializationPhase(
+            userId: String,
+            partnerId: String,
+            hostId: String,
+            nonceArg: ByteArray,
+            date: XMLGregorianCalendar,
+            bankEncPub: RSAPublicKey,
+            bankAuthPub: RSAPublicKey,
+            aOrderType: String,
+            dateStart: XMLGregorianCalendar,
+            dateEnd: XMLGregorianCalendar
+        ): EbicsRequest {
+
+            val tmp = this.createForDownloadInitializationPhase(
+                userId,
+                partnerId,
+                hostId,
+                nonceArg,
+                date,
+                bankEncPub,
+                bankAuthPub,
+                aOrderType
+            )
+
+            (tmp.header.static.orderDetails?.orderParams as 
StandardOrderParams).apply {
+                dateRange?.apply {
+                    start = dateStart
+                    end = dateEnd
+                }
+            }
+
+            return tmp
+        }
+
         fun createForDownloadInitializationPhase(
             userId: String,
             partnerId: String,

-- 
To stop receiving notification emails like this one, please contact
address@hidden.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]