libeufin

Integration and sandbox testing for FinTech APIs and data formats
Log | Files | Refs | Submodules | README | LICENSE

commit abe150db818a66826589ab793917dd8bc5d83ddf
parent 849bca95be1cd6f772457ab5f974c58c62ecf6bf
Author: Marcello Stanisci <stanisci.m@gmail.com>
Date:   Tue, 28 Jan 2020 20:50:44 +0100

Implement HEV in the Nexus (to test).

Diffstat:
Mnexus/src/main/kotlin/tech/libeufin/nexus/Containers.kt | 9---------
Mnexus/src/main/kotlin/tech/libeufin/nexus/Helpers.kt | 8+++++---
Mnexus/src/main/kotlin/tech/libeufin/nexus/JSON.kt | 7++++---
Mnexus/src/main/kotlin/tech/libeufin/nexus/Main.kt | 53++++++++++++++++++++---------------------------------
Msandbox/src/main/python/libeufin-cli | 17+++++++++++++++++
Mutil/src/main/kotlin/ebics_hev/EbicsMessages.kt | 10++++++++++
6 files changed, 56 insertions(+), 48 deletions(-)

diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/Containers.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/Containers.kt @@ -15,26 +15,17 @@ import javax.xml.bind.JAXBElement * the time. */ data class EbicsContainer( - val partnerId: String, - val userId: String, - - var bankAuthPub: RSAPublicKey?, var bankEncPub: RSAPublicKey?, - // needed to send the message val ebicsUrl: String, - // needed to craft further messages val hostId: String, - // needed to decrypt data coming from the bank val customerEncPriv: RSAPrivateCrtKey, - // needed to sign documents val customerAuthPriv: RSAPrivateCrtKey, - val customerSignPriv: RSAPrivateCrtKey ) \ No newline at end of file diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/Helpers.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/Helpers.kt @@ -110,8 +110,12 @@ fun createUploadInitializationPhase( ) } +/** + * Usually, queries must return lots of data from within a transaction + * block. For convenience, we wrap such data into a EbicsContainer, so + * that only one object is always returned from the transaction block. + */ fun containerInit(subscriber: EbicsSubscriberEntity): EbicsContainer { - var bankAuthPubValue: RSAPublicKey? = null if (subscriber.bankAuthenticationPublicKey != null) { bankAuthPubValue = CryptoUtil.loadRsaPublicKey( @@ -124,7 +128,6 @@ fun containerInit(subscriber: EbicsSubscriberEntity): EbicsContainer { subscriber.bankEncryptionPublicKey?.toByteArray()!! ) } - return EbicsContainer( bankAuthPub = bankAuthPubValue, bankEncPub = bankEncPubValue, @@ -138,7 +141,6 @@ fun containerInit(subscriber: EbicsSubscriberEntity): EbicsContainer { customerAuthPriv = CryptoUtil.loadRsaPrivateKey(subscriber.authenticationPrivateKey.toByteArray()), customerEncPriv = CryptoUtil.loadRsaPrivateKey(subscriber.authenticationPrivateKey.toByteArray()) ) - } /** diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/JSON.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/JSON.kt @@ -1,8 +1,5 @@ package tech.libeufin.nexus -import com.squareup.moshi.JsonClass - - data class EbicsBackupRequest( val passphrase: String ) @@ -56,4 +53,8 @@ data class EbicsSubscriberInfoResponse( */ data class EbicsSubscribersResponse( val ebicsSubscribers: MutableList<EbicsSubscriberInfoResponse> = mutableListOf() +) + +data class EbicsHevResponse( + val versions: List<String> ) \ No newline at end of file diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/Main.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/Main.kt @@ -51,6 +51,8 @@ import tech.libeufin.util.toHexString import tech.libeufin.util.CryptoUtil import tech.libeufin.util.EbicsOrderUtil import tech.libeufin.util.XMLUtil +import tech.libeufin.util.ebics_hev.HEVRequest +import tech.libeufin.util.ebics_hev.HEVResponse import java.math.BigInteger import java.text.SimpleDateFormat import java.util.* @@ -499,17 +501,31 @@ fun main() { call.respond(HttpStatusCode.OK, response) return@get } + get("/ebics/{id}/sendHev") { + val id = expectId(call.parameters["id"]) + val (ebicsUrl, hostID) = transaction { + val customer = EbicsSubscriberEntity.findById(id) + ?: throw SubscriberNotFoundError(HttpStatusCode.NotFound) + Pair(customer.ebicsURL, customer.hostID) + } + val request = HEVRequest().apply { + hostId = hostID + } + val response = client.postToBankUnsigned<HEVRequest, HEVResponse>(ebicsUrl, request) + call.respond( + HttpStatusCode.OK, + EbicsHevResponse(response.value.versionNumber as List<String>) + ) + return@get + } post("/ebics/subscribers") { val body = call.receive<EbicsSubscriberInfoRequest>() - val pairA = CryptoUtil.generateRsaKeyPair(2048) val pairB = CryptoUtil.generateRsaKeyPair(2048) val pairC = CryptoUtil.generateRsaKeyPair(2048) - val id = transaction { - EbicsSubscriberEntity.new { ebicsURL = body.ebicsURL hostID = body.hostID @@ -519,10 +535,8 @@ fun main() { signaturePrivateKey = SerialBlob(pairA.private.encoded) encryptionPrivateKey = SerialBlob(pairB.private.encoded) authenticationPrivateKey = SerialBlob(pairC.private.encoded) - }.id.value } - call.respondText( "Subscriber registered, ID: ${id}", ContentType.Text.Plain, @@ -530,12 +544,8 @@ fun main() { ) return@post } - - post("/ebics/subscribers/{id}/sendIni") { - - val id = - expectId(call.parameters["id"]) // caught above + val id = expectId(call.parameters["id"]) val subscriberData = transaction { containerInit( EbicsSubscriberEntity.findById(id) @@ -544,72 +554,56 @@ fun main() { ) ) } - val iniRequest = EbicsUnsecuredRequest.createIni( subscriberData.hostId, subscriberData.userId, subscriberData.partnerId, subscriberData.customerSignPriv ) - val responseJaxb = client.postToBankUnsigned<EbicsUnsecuredRequest, EbicsKeyManagementResponse>( subscriberData.ebicsUrl, iniRequest ) - if (responseJaxb.value.body.returnCode.value != "000000") { throw EbicsError(responseJaxb.value.body.returnCode.value) } - call.respondText("Bank accepted signature key\n", ContentType.Text.Plain, HttpStatusCode.OK) return@post } post("/ebics/subscribers/{id}/restoreBackup") { - val body = call.receive<EbicsKeysBackup>() val id = expectId(call.parameters["id"]) - val (authKey, encKey, sigKey) = try { - Triple( - CryptoUtil.decryptKey( EncryptedPrivateKeyInfo(body.authBlob), body.passphrase!! ), - CryptoUtil.decryptKey( EncryptedPrivateKeyInfo(body.encBlob), body.passphrase ), - CryptoUtil.decryptKey( EncryptedPrivateKeyInfo(body.sigBlob), body.passphrase ) ) - } catch (e: Exception) { e.printStackTrace() throw BadBackup(HttpStatusCode.BadRequest) } - transaction { val subscriber = EbicsSubscriberEntity.findById(id) ?: throw SubscriberNotFoundError( HttpStatusCode.NotFound ) - subscriber.encryptionPrivateKey = SerialBlob(encKey.encoded) subscriber.authenticationPrivateKey = SerialBlob(authKey.encoded) subscriber.signaturePrivateKey = SerialBlob(sigKey.encoded) } - call.respondText( "Keys successfully restored", ContentType.Text.Plain, HttpStatusCode.OK ) - } - post("/ebics/subscribers/{id}/backup") { val id = expectId(call.parameters["id"]) @@ -619,33 +613,26 @@ fun main() { val subscriber = EbicsSubscriberEntity.findById(id) ?: throw SubscriberNotFoundError( HttpStatusCode.NotFound ) - - EbicsKeysBackup( - authBlob = CryptoUtil.encryptKey( subscriber.authenticationPrivateKey.toByteArray(), body.passphrase ), - encBlob = CryptoUtil.encryptKey( subscriber.encryptionPrivateKey.toByteArray(), body.passphrase ), - sigBlob = CryptoUtil.encryptKey( subscriber.signaturePrivateKey.toByteArray(), body.passphrase ) ) } - call.response.headers.append("Content-Disposition", "attachment") call.respond( HttpStatusCode.OK, content ) - } post("/ebics/subscribers/{id}/sendTst") { diff --git a/sandbox/src/main/python/libeufin-cli b/sandbox/src/main/python/libeufin-cli @@ -109,6 +109,23 @@ def native(ctx, sandbox_base_url): ctx.obj.update(sandbox_base_url=sandbox_base_url) pass +@ebics.command(help="Send the HEV message to the bank.") +@click.pass_obj +@click.option( + "--customer_id", + help="Customer id", + required=True +) +def send_hev(customer_id): + url = urljoin(obj["nexus_base_url"], "/ebics/{}/sendHev".format(customer_id)) + try: + resp = get(url) + except Exception: + print("Unsuccessful request") + return + + print(resp.content.decode("utf-8")) + @ebics.command(help="Restore private keys backup.") @click.pass_obj @click.option( diff --git a/util/src/main/kotlin/ebics_hev/EbicsMessages.kt b/util/src/main/kotlin/ebics_hev/EbicsMessages.kt @@ -26,6 +26,16 @@ import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter @XmlAccessorType(XmlAccessType.NONE) @XmlType( + name = "HEVRequestDataType" +) +@XmlRootElement(name = "ebicsHEVRequest") +class HEVRequest{ + @get:XmlElement(name = "HostID", required = true) + lateinit var hostId: String +} + +@XmlAccessorType(XmlAccessType.NONE) +@XmlType( name = "HEVResponseDataType", propOrder = ["systemReturnCode", "versionNumber", "any"] )