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:
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"]
)