gnunet-svn
[Top][All Lists]
Advanced

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

[libeufin] branch master updated (f1674d9 -> 2ae33e7)


From: gnunet
Subject: [libeufin] branch master updated (f1674d9 -> 2ae33e7)
Date: Fri, 08 Nov 2019 20:08:49 +0100

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

dold pushed a change to branch master
in repository libeufin.

    from f1674d9  Add helper function to chunk strings.
     new cccc4ac  gitignore
     new 2ae33e7  start with HKD

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:
 .gitignore                                         |   2 +
 .idea/gradle.xml                                   |   1 -
 sandbox/build.gradle                               |   1 +
 .../kotlin/tech/libeufin/sandbox/CryptoUtil.kt     |   8 +-
 .../src/main/kotlin/tech/libeufin/sandbox/DB.kt    |  16 +-
 .../kotlin/tech/libeufin/sandbox/EbicsOrderUtil.kt |   2 +-
 .../tech/libeufin/sandbox/EbicsProtocolBackend.kt  | 229 +++++++++------------
 .../main/kotlin/tech/libeufin/sandbox/XMLUtil.kt   |  11 +
 .../libeufin/schema/ebics_h004/EbicsResponse.kt    | 152 +++++++++++++-
 .../tech/libeufin/schema/ebics_h004/EbicsTypes.kt  | 186 +++++++++++++++++
 .../schema/ebics_h004/HKDResponseOrderData.kt      |  15 ++
 .../schema/ebics_h004/HTDResponseOrderData.kt      | 190 +----------------
 sandbox/src/test/kotlin/EbicsMessagesTest.kt       |  20 +-
 13 files changed, 489 insertions(+), 344 deletions(-)
 create mode 100644 
sandbox/src/main/kotlin/tech/libeufin/schema/ebics_h004/HKDResponseOrderData.kt

diff --git a/.gitignore b/.gitignore
index 91ea741..8425854 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,4 @@
 build
 .gradle
+out
+*.sqlite3
diff --git a/.idea/gradle.xml b/.idea/gradle.xml
index 70bf921..49f0342 100644
--- a/.idea/gradle.xml
+++ b/.idea/gradle.xml
@@ -17,7 +17,6 @@
             <option value="$PROJECT_DIR$/sandbox" />
           </set>
         </option>
-        <option name="useAutoImport" value="true" />
         <option name="useQualifiedModuleNames" value="true" />
       </GradleProjectSettings>
     </option>
diff --git a/sandbox/build.gradle b/sandbox/build.gradle
index 71e4896..b02a96b 100644
--- a/sandbox/build.gradle
+++ b/sandbox/build.gradle
@@ -39,6 +39,7 @@ dependencies {
     implementation "org.glassfish.jaxb:jaxb-runtime:2.3.1"
     implementation 'org.apache.santuario:xmlsec:2.1.4'
     implementation group: 'org.bouncycastle', name: 'bcprov-jdk16', version: 
'1.45'
+    implementation group: 'org.xerial', name: 'sqlite-jdbc', version: '3.28.0'
 
     testImplementation group: 'junit', name: 'junit', version: '4.12'
     testImplementation 'org.jetbrains.kotlin:kotlin-test-junit:1.3.50'
diff --git a/sandbox/src/main/kotlin/tech/libeufin/sandbox/CryptoUtil.kt 
b/sandbox/src/main/kotlin/tech/libeufin/sandbox/CryptoUtil.kt
index b3ca595..5843356 100644
--- a/sandbox/src/main/kotlin/tech/libeufin/sandbox/CryptoUtil.kt
+++ b/sandbox/src/main/kotlin/tech/libeufin/sandbox/CryptoUtil.kt
@@ -151,14 +151,18 @@ object CryptoUtil {
     }
 
     fun decryptEbicsE002(enc: EncryptionResult, privateKey: RSAPrivateCrtKey): 
ByteArray {
+        return decryptEbicsE002(enc.encryptedTransactionKey, 
enc.encryptedData, privateKey)
+    }
+
+    fun decryptEbicsE002(encryptedTransactionKey: ByteArray, encryptedData: 
ByteArray, privateKey: RSAPrivateCrtKey): ByteArray {
         val asymmetricCipher = Cipher.getInstance("RSA/None/PKCS1Padding", 
bouncyCastleProvider)
         asymmetricCipher.init(Cipher.DECRYPT_MODE, privateKey)
-        val transactionKeyBytes = 
asymmetricCipher.doFinal(enc.encryptedTransactionKey)
+        val transactionKeyBytes = 
asymmetricCipher.doFinal(encryptedTransactionKey)
         val secretKeySpec = SecretKeySpec(transactionKeyBytes, "AES")
         val symmetricCipher = Cipher.getInstance("AES/CBC/X9.23Padding", 
bouncyCastleProvider)
         val ivParameterSpec = IvParameterSpec(ByteArray(16))
         symmetricCipher.init(Cipher.DECRYPT_MODE, secretKeySpec, 
ivParameterSpec)
-        val data = symmetricCipher.doFinal(enc.encryptedData)
+        val data = symmetricCipher.doFinal(encryptedData)
         return data
     }
 }
diff --git a/sandbox/src/main/kotlin/tech/libeufin/sandbox/DB.kt 
b/sandbox/src/main/kotlin/tech/libeufin/sandbox/DB.kt
index b4cb2f6..2b48dd7 100644
--- a/sandbox/src/main/kotlin/tech/libeufin/sandbox/DB.kt
+++ b/sandbox/src/main/kotlin/tech/libeufin/sandbox/DB.kt
@@ -21,10 +21,11 @@ package tech.libeufin.sandbox
 
 import org.jetbrains.exposed.dao.*
 import org.jetbrains.exposed.sql.Database
-import org.jetbrains.exposed.sql.ReferenceOption
+import org.jetbrains.exposed.sql.transactions.TransactionManager
 import org.jetbrains.exposed.sql.SchemaUtils
 import org.jetbrains.exposed.sql.transactions.transaction
 import java.sql.Blob
+import java.sql.Connection
 
 const val CUSTOMER_NAME_MAX_LENGTH = 20
 const val EBICS_HOST_ID_MAX_LENGTH = 10
@@ -229,13 +230,13 @@ class EbicsUploadTransactionEntity(id: EntityID<String>) 
: Entity<String>(id) {
     var subscriber by EbicsSubscriberEntity referencedOn 
EbicsUploadTransactionsTable.subscriber
     var numSegments by EbicsUploadTransactionsTable.numSegments
     var lastSeenSegment by EbicsUploadTransactionsTable.lastSeenSegment
-    var transactionKeyEnc by EbicsDownloadTransactionsTable.transactionKeyEnc
+    var transactionKeyEnc by EbicsUploadTransactionsTable.transactionKeyEnc
 }
 
 
 object EbicsUploadTransactionChunksTable : IdTable<String>() {
     override val id =
-        
text("transactionID").entityId().references(EbicsUploadTransactionsTable.id, 
ReferenceOption.CASCADE)
+        text("transactionID").entityId()
     val chunkIndex = integer("chunkIndex")
     val chunkContent = blob("chunkContent")
 }
@@ -250,16 +251,19 @@ class EbicsUploadTransactionChunkEntity(id : 
EntityID<String>): Entity<String>(i
 
 
 fun dbCreateTables() {
-    Database.connect("jdbc:h2:mem:test;DB_CLOSE_DELAY=-1", driver = 
"org.h2.Driver")
+    Database.connect("jdbc:sqlite:libeufin-sandbox.sqlite3", "org.sqlite.JDBC")
+    TransactionManager.manager.defaultIsolationLevel = 
Connection.TRANSACTION_SERIALIZABLE
 
     transaction {
         // addLogger(StdOutSqlLogger)
 
-        SchemaUtils.create(
+        SchemaUtils.createMissingTablesAndColumns(
             BankCustomersTable,
             EbicsSubscribersTable,
             EbicsHostsTable,
-            EbicsDownloadTransactionsTable
+            EbicsDownloadTransactionsTable,
+            EbicsUploadTransactionsTable,
+            EbicsUploadTransactionChunksTable
         )
     }
 }
diff --git a/sandbox/src/main/kotlin/tech/libeufin/sandbox/EbicsOrderUtil.kt 
b/sandbox/src/main/kotlin/tech/libeufin/sandbox/EbicsOrderUtil.kt
index 7fcd812..2edfd8e 100644
--- a/sandbox/src/main/kotlin/tech/libeufin/sandbox/EbicsOrderUtil.kt
+++ b/sandbox/src/main/kotlin/tech/libeufin/sandbox/EbicsOrderUtil.kt
@@ -46,7 +46,7 @@ object EbicsOrderUtil {
         val rng = SecureRandom()
         val res = ByteArray(16)
         rng.nextBytes(res)
-        return res.toHexString()
+        return res.toHexString().toUpperCase()
     }
 
     /**
diff --git 
a/sandbox/src/main/kotlin/tech/libeufin/sandbox/EbicsProtocolBackend.kt 
b/sandbox/src/main/kotlin/tech/libeufin/sandbox/EbicsProtocolBackend.kt
index cd6a922..73b031d 100644
--- a/sandbox/src/main/kotlin/tech/libeufin/sandbox/EbicsProtocolBackend.kt
+++ b/sandbox/src/main/kotlin/tech/libeufin/sandbox/EbicsProtocolBackend.kt
@@ -28,15 +28,20 @@ import io.ktor.response.respond
 import io.ktor.response.respondText
 import org.apache.xml.security.binding.xmldsig.RSAKeyValueType
 import org.apache.xml.security.binding.xmldsig.SignatureType
+import org.jetbrains.exposed.sql.lowerCase
 import org.jetbrains.exposed.sql.transactions.transaction
+import org.jetbrains.exposed.sql.upperCase
 import org.w3c.dom.Document
 import tech.libeufin.schema.ebics_h004.*
 import tech.libeufin.schema.ebics_hev.HEVResponse
 import tech.libeufin.schema.ebics_hev.SystemReturnCodeType
 import tech.libeufin.schema.ebics_s001.SignaturePubKeyOrderData
 import java.math.BigInteger
+import java.security.PrivateKey
+import java.security.interfaces.RSAPrivateCrtKey
 import java.util.*
 import java.util.zip.DeflaterInputStream
+import java.util.zip.InflaterInputStream
 import javax.sql.rowset.serial.SerialBlob
 
 
@@ -225,7 +230,7 @@ private suspend fun ApplicationCall.handleEbicsHpb(
  */
 private fun ApplicationCall.ensureEbicsHost(requestHostID: String): 
EbicsHostPublicInfo {
     return transaction {
-        val ebicsHost = EbicsHostEntity.find { EbicsHostsTable.hostID eq 
requestHostID }.firstOrNull()
+        val ebicsHost = EbicsHostEntity.find { 
EbicsHostsTable.hostID.upperCase() eq requestHostID.toUpperCase() 
}.firstOrNull()
         if (ebicsHost == null) {
             logger.warn("client requested unknown HostID")
             throw EbicsKeyManagementError("[EBICS_INVALID_HOST_ID]", "091011")
@@ -254,13 +259,13 @@ private suspend fun ApplicationCall.receiveEbicsXml(): 
Document {
 
 fun handleEbicsHtd(): ByteArray {
     val htd = HTDResponseOrderData().apply {
-        this.partnerInfo = HTDResponseOrderData.PartnerInfo().apply {
+        this.partnerInfo = EbicsTypes.PartnerInfo().apply {
             this.accountInfoList = listOf(
-                HTDResponseOrderData.AccountInfo().apply {
+                EbicsTypes.AccountInfo().apply {
                     this.id = "acctid1"
                     this.accountHolder = "Mina Musterfrau"
                     this.accountNumberList = listOf(
-                        HTDResponseOrderData.GeneralAccountNumber().apply {
+                        EbicsTypes.GeneralAccountNumber().apply {
                             this.international = true
                             this.value = "DE21500105174751659277"
                         }
@@ -268,17 +273,17 @@ fun handleEbicsHtd(): ByteArray {
                     this.currency = "EUR"
                     this.description = "ACCT"
                     this.bankCodeList = listOf(
-                        HTDResponseOrderData.GeneralBankCode().apply {
+                        EbicsTypes.GeneralBankCode().apply {
                             this.international = true
                             this.value = "INGDDEFFXXX"
                         }
                     )
                 },
-                HTDResponseOrderData.AccountInfo().apply {
+                EbicsTypes.AccountInfo().apply {
                     this.id = "glsdemo"
                     this.accountHolder = "Mina Musterfrau"
                     this.accountNumberList = listOf(
-                        HTDResponseOrderData.GeneralAccountNumber().apply {
+                        EbicsTypes.GeneralAccountNumber().apply {
                             this.international = true
                             this.value = "DE91430609670123123123"
                         }
@@ -286,45 +291,45 @@ fun handleEbicsHtd(): ByteArray {
                     this.currency = "EUR"
                     this.description = "glsdemoacct"
                     this.bankCodeList = listOf(
-                        HTDResponseOrderData.GeneralBankCode().apply {
+                        EbicsTypes.GeneralBankCode().apply {
                             this.international = true
                             this.value = "GENODEM1GLS"
                         }
                     )
                 }
             )
-            this.addressInfo = HTDResponseOrderData.AddressInfo().apply {
+            this.addressInfo = EbicsTypes.AddressInfo().apply {
                 this.name = "Foo"
             }
-            this.bankInfo = HTDResponseOrderData.BankInfo().apply {
+            this.bankInfo = EbicsTypes.BankInfo().apply {
                 this.hostID = "host01"
             }
             this.orderInfoList = listOf(
-                HTDResponseOrderData.AuthOrderInfoType().apply {
+                EbicsTypes.AuthOrderInfoType().apply {
                     this.description = "foo"
                     this.orderType = "C53"
                     this.transferType = "Download"
                 },
-                HTDResponseOrderData.AuthOrderInfoType().apply {
+                EbicsTypes.AuthOrderInfoType().apply {
                     this.description = "foo"
                     this.orderType = "C52"
                     this.transferType = "Download"
                 },
-                HTDResponseOrderData.AuthOrderInfoType().apply {
+                EbicsTypes.AuthOrderInfoType().apply {
                     this.description = "foo"
                     this.orderType = "CCC"
                     this.transferType = "Upload"
                 }
             )
         }
-        this.userInfo = HTDResponseOrderData.UserInfo().apply {
+        this.userInfo = EbicsTypes.UserInfo().apply {
             this.name = "Some User"
-            this.userID = HTDResponseOrderData.UserIDType().apply {
+            this.userID = EbicsTypes.UserIDType().apply {
                 this.status = 5
                 this.value = "USER1"
             }
             this.permissionList = listOf(
-                HTDResponseOrderData.UserPermission().apply {
+                EbicsTypes.UserPermission().apply {
                     this.orderTypes = "C54 C53 C52 CCC"
                 }
             )
@@ -336,111 +341,22 @@ fun handleEbicsHtd(): ByteArray {
 }
 
 
-fun createEbicsResponseForDownloadInitializationPhase(
-    transactionID: String,
-    numSegments: Int,
-    segmentSize: Int,
-    enc: CryptoUtil.EncryptionResult,
-    encodedData: String
-): EbicsResponse {
-    return EbicsResponse().apply {
-        this.version = "H004"
-        this.revision = 1
-        this.header = EbicsResponse.Header().apply {
-            this.authenticate = true
-            this._static = EbicsResponse.StaticHeaderType().apply {
-                this.transactionID = transactionID
-                this.numSegments = BigInteger.valueOf(numSegments.toLong())
-            }
-            this.mutable = EbicsResponse.MutableHeaderType().apply {
-                this.transactionPhase = 
EbicsTypes.TransactionPhaseType.INITIALISATION
-                this.segmentNumber = EbicsResponse.SegmentNumber().apply {
-                    this.lastSegment = (numSegments == 1)
-                    this.value = BigInteger.valueOf(1)
-                }
-                this.reportText = "[EBICS_OK] OK"
-                this.returnCode = "000000"
-            }
-        }
-        this.authSignature = SignatureType()
-        this.body = EbicsResponse.Body().apply {
-            this.returnCode = EbicsResponse.ReturnCode().apply {
-                this.authenticate = true
-                this.value = "000000"
-            }
-            this.dataTransfer = EbicsResponse.DataTransferResponseType().apply 
{
-                this.dataEncryptionInfo = 
EbicsTypes.DataEncryptionInfo().apply {
-                    this.authenticate = true
-                    this.encryptionPubKeyDigest = 
EbicsTypes.PubKeyDigest().apply {
-                        this.algorithm = 
"http://www.w3.org/2001/04/xmlenc#sha256";
-                        this.version = "E002"
-                        this.value = enc.pubKeyDigest
-                    }
-                    this.transactionKey = enc.encryptedTransactionKey
-                }
-                this.orderData = EbicsResponse.OrderData().apply {
-                    this.value = encodedData.substring(0, 
Math.min(segmentSize, encodedData.length))
-                }
-            }
-        }
-    }
+fun signEbicsResponseX002(ebicsResponse: EbicsResponse, privateKey: 
RSAPrivateCrtKey): String {
+    val doc = XMLUtil.convertJaxbToDocument(ebicsResponse)
+    XMLUtil.signEbicsDocument(doc, privateKey)
+    val signedDoc = XMLUtil.convertDomToString(doc)
+    println("response: $signedDoc")
+    return signedDoc
 }
 
 
-fun createEbicsResponseForDownloadReceiptPhase(transactionID: String, 
positiveAck: Boolean): EbicsResponse {
-    return EbicsResponse().apply {
-        this.version = "H004"
-        this.revision = 1
-        this.header = EbicsResponse.Header().apply {
-            this.authenticate = true
-            this._static = EbicsResponse.StaticHeaderType().apply {
-                this.transactionID = transactionID
-            }
-            this.mutable = EbicsResponse.MutableHeaderType().apply {
-                this.transactionPhase = EbicsTypes.TransactionPhaseType.RECEIPT
-                if (positiveAck) {
-                    this.reportText = "[EBICS_DOWNLOAD_POSTPROCESS_DONE] 
Received positive receipt"
-                    this.returnCode = "011000"
-                } else {
-                    this.reportText = "[EBICS_DOWNLOAD_POSTPROCESS_SKIPPED] 
Received negative receipt"
-                    this.returnCode = "011001"
-                }
-            }
-        }
-        this.authSignature = SignatureType()
-        this.body = EbicsResponse.Body().apply {
-            this.returnCode = EbicsResponse.ReturnCode().apply {
-                this.authenticate = true
-                this.value = "000000"
-            }
-        }
-    }
-}
+class EbicsTransactionDetails(
 
-fun createEbicsResponseForUploadInitializationPhase(transactionID: String, 
orderID: String): EbicsResponse {
-    return EbicsResponse().apply {
-        this.version = "H004"
-        this.revision = 1
-        this.header = EbicsResponse.Header().apply {
-            this.authenticate = true
-            this._static = EbicsResponse.StaticHeaderType().apply {
-                this.transactionID = transactionID
-            }
-            this.mutable = EbicsResponse.MutableHeaderType().apply {
-                this.transactionPhase = 
EbicsTypes.TransactionPhaseType.INITIALISATION
-                this.orderID = orderID
-                this.reportText = "[EBICS_OK] OK"
-                this.returnCode = "000000"
-            }
-        }
-        this.authSignature = SignatureType()
-        this.body = EbicsResponse.Body().apply {
-            this.returnCode = EbicsResponse.ReturnCode().apply {
-                this.authenticate = true
-                this.value = "000000"
-            }
-        }
-    }
+)
+
+
+fun queryEbicsTransactionDetails(ebicsRequest: EbicsRequest): 
EbicsTransactionDetails {
+    throw NotImplementedError()
 }
 
 
@@ -492,12 +408,14 @@ suspend fun ApplicationCall.ebicsweb() {
             val responseXmlStr = transaction {
                 // Step 1 of 3:  Get information about the host and subscriber
 
-                val ebicsHost = EbicsHostEntity.find { EbicsHostsTable.hostID 
eq requestedHostId }.firstOrNull()
+                val ebicsHost = EbicsHostEntity.find { 
EbicsHostsTable.hostID.upperCase() eq requestedHostId.toUpperCase() 
}.firstOrNull()
                 val requestTransactionID = 
requestObject.header.static.transactionID
                 var downloadTransaction: EbicsDownloadTransactionEntity? = null
-                var uploadTransaction: EbicsUploadTransactionEntity? = null
+                var uploadTransaction: EbicsUploadTransactionEntity? =
+                    null
                 val subscriber = if (requestTransactionID != null) {
-                    downloadTransaction = 
EbicsDownloadTransactionEntity.findById(requestTransactionID)
+                    println("finding subscriber by transactionID 
$requestTransactionID")
+                    downloadTransaction = 
EbicsDownloadTransactionEntity.findById(requestTransactionID.toUpperCase())
                     if (downloadTransaction != null) {
                         downloadTransaction.subscriber
                     } else {
@@ -517,6 +435,10 @@ suspend fun ApplicationCall.ebicsweb() {
                     ebicsHost.authenticationPrivateKey
                         .toByteArray()
                 )
+                val hostEncPriv = CryptoUtil.loadRsaPrivateKey(
+                    ebicsHost.encryptionPrivateKey
+                        .toByteArray()
+                )
                 val clientAuthPub =
                     
CryptoUtil.loadRsaPublicKey(subscriber.authenticationKey!!.rsaPublicKey.toByteArray())
                 val clientEncPub =
@@ -534,6 +456,7 @@ suspend fun ApplicationCall.ebicsweb() {
                         val orderType =
                             
requestObject.header.static.orderDetails?.orderType ?: throw 
EbicsInvalidRequestError()
                         if (staticHeader.numSegments == null) {
+                            println("handling initialization for order type 
$orderType")
                             val response = when (orderType) {
                                 "HTD" -> handleEbicsHtd()
                                 else -> throw EbicsInvalidXmlError()
@@ -560,7 +483,7 @@ suspend fun ApplicationCall.ebicsweb() {
                                 this.numSegments = numSegments
                                 this.receiptReceived = false
                             }
-                            createEbicsResponseForDownloadInitializationPhase(
+                            EbicsResponse.createForDownloadInitializationPhase(
                                 transactionID,
                                 numSegments,
                                 segmentSize,
@@ -571,15 +494,30 @@ suspend fun ApplicationCall.ebicsweb() {
                             val oidn = subscriber.nextOrderID++
                             if (EbicsOrderUtil.checkOrderIDOverflow(oidn)) 
throw NotImplementedError()
                             val orderID = 
EbicsOrderUtil.computeOrderIDFromNumber(oidn)
-                            val signatureData = 
requestObject.body.dataTransfer?.signatureData
-                            if (signatureData != null) {
-                                println("signature data: 
${signatureData.toString(Charsets.UTF_8)}")
-                            }
                             val numSegments =
                                 requestObject.header.static.numSegments ?: 
throw EbicsInvalidRequestError()
                             val transactionKeyEnc =
                                 
requestObject.body.dataTransfer?.dataEncryptionInfo?.transactionKey
                                     ?: throw EbicsInvalidRequestError()
+                            val encPubKeyDigest =
+                                
requestObject.body.dataTransfer?.dataEncryptionInfo?.encryptionPubKeyDigest?.value
+                            if (encPubKeyDigest == null)
+                                throw EbicsInvalidRequestError()
+                            val encSigData = 
requestObject.body.dataTransfer?.signatureData
+                            if (encSigData == null)
+                                throw EbicsInvalidRequestError()
+                            val decryptedSignatureData = 
CryptoUtil.decryptEbicsE002(
+                                CryptoUtil.EncryptionResult(
+                                    transactionKeyEnc,
+                                    encPubKeyDigest,
+                                    encSigData
+                                ), hostEncPriv
+                            )
+                            val plainSigData = 
InflaterInputStream(decryptedSignatureData.inputStream()).use {
+                                it.readAllBytes()
+                            }
+                            println("signature data: 
${plainSigData.toString(Charsets.UTF_8)}")
+                            println("creating upload transaction for 
transactionID $transactionID")
                             EbicsUploadTransactionEntity.new(transactionID) {
                                 this.host = ebicsHost
                                 this.subscriber = subscriber
@@ -589,11 +527,39 @@ suspend fun ApplicationCall.ebicsweb() {
                                 this.numSegments = numSegments.toInt()
                                 this.transactionKeyEnc = 
SerialBlob(transactionKeyEnc)
                             }
-                            
createEbicsResponseForUploadInitializationPhase(transactionID, orderID)
+                            
EbicsResponse.createForUploadInitializationPhase(transactionID, orderID)
                         }
                     }
                     EbicsTypes.TransactionPhaseType.TRANSFER -> {
-                        throw NotImplementedError()
+                        requestTransactionID ?: throw 
EbicsInvalidRequestError()
+                        val requestSegmentNumber =
+                            
requestObject.header.mutable.segmentNumber?.toInt() ?: throw 
EbicsInvalidRequestError()
+                        if (uploadTransaction != null) {
+                            if (requestSegmentNumber == 1 && 
uploadTransaction.numSegments == 1) {
+                                val encOrderData =
+                                    requestObject.body.dataTransfer?.orderData 
?: throw EbicsInvalidRequestError()
+                                val zippedData = CryptoUtil.decryptEbicsE002(
+                                    
uploadTransaction.transactionKeyEnc.toByteArray(),
+                                    encOrderData,
+                                    hostEncPriv
+                                )
+                                val unzippedData =
+                                    
InflaterInputStream(zippedData.inputStream()).use { it.readAllBytes() }
+                                println("got upload data: 
${unzippedData.toString(Charsets.UTF_8)}")
+                                EbicsResponse.createForUploadTransferPhase(
+                                    requestTransactionID,
+                                    requestSegmentNumber,
+                                    true,
+                                    uploadTransaction.orderID
+                                )
+                            } else {
+                                throw NotImplementedError()
+                            }
+                        } else if (downloadTransaction != null) {
+                            throw NotImplementedError()
+                        } else {
+                            throw AssertionError()
+                        }
                     }
                     EbicsTypes.TransactionPhaseType.RECEIPT -> {
                         requestTransactionID ?: throw 
EbicsInvalidRequestError()
@@ -601,15 +567,10 @@ suspend fun ApplicationCall.ebicsweb() {
                             throw EbicsInvalidRequestError()
                         val receiptCode =
                             requestObject.body.transferReceipt?.receiptCode ?: 
throw EbicsInvalidRequestError()
-                        
createEbicsResponseForDownloadReceiptPhase(requestTransactionID, receiptCode == 
0)
+                        
EbicsResponse.createForDownloadReceiptPhase(requestTransactionID, receiptCode 
== 0)
                     }
                 }
-                val docText = XMLUtil.convertJaxbToString(ebicsResponse)
-                val doc = XMLUtil.parseStringIntoDom(docText)
-                XMLUtil.signEbicsDocument(doc, hostAuthPriv)
-                val signedDoc = XMLUtil.convertDomToString(doc)
-                println("response: $signedDoc")
-                docText
+                signEbicsResponseX002(ebicsResponse, hostAuthPriv)
             }
             respondText(responseXmlStr, ContentType.Application.Xml, 
HttpStatusCode.OK)
         }
diff --git a/sandbox/src/main/kotlin/tech/libeufin/sandbox/XMLUtil.kt 
b/sandbox/src/main/kotlin/tech/libeufin/sandbox/XMLUtil.kt
index 5195478..0538984 100644
--- a/sandbox/src/main/kotlin/tech/libeufin/sandbox/XMLUtil.kt
+++ b/sandbox/src/main/kotlin/tech/libeufin/sandbox/XMLUtil.kt
@@ -203,6 +203,17 @@ class XMLUtil private constructor() {
             return sw.toString()
         }
 
+        inline fun <reified T> convertJaxbToDocument(obj: T): Document {
+            val dbf: DocumentBuilderFactory  = 
DocumentBuilderFactory.newInstance()
+            dbf.isNamespaceAware = true
+            val doc = dbf.newDocumentBuilder().newDocument()
+            val jc = JAXBContext.newInstance(T::class.java)
+            val m = jc.createMarshaller()
+            m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true)
+            m.marshal(obj, doc)
+            return doc
+        }
+
         /**
          * Convert a XML string to the JAXB representation.
          *
diff --git 
a/sandbox/src/main/kotlin/tech/libeufin/schema/ebics_h004/EbicsResponse.kt 
b/sandbox/src/main/kotlin/tech/libeufin/schema/ebics_h004/EbicsResponse.kt
index 4ef5d2e..1e088da 100644
--- a/sandbox/src/main/kotlin/tech/libeufin/schema/ebics_h004/EbicsResponse.kt
+++ b/sandbox/src/main/kotlin/tech/libeufin/schema/ebics_h004/EbicsResponse.kt
@@ -1,6 +1,7 @@
 package tech.libeufin.schema.ebics_h004
 
 import org.apache.xml.security.binding.xmldsig.SignatureType
+import tech.libeufin.sandbox.CryptoUtil
 import java.math.BigInteger
 import javax.xml.bind.annotation.*
 import javax.xml.bind.annotation.adapters.CollapsedStringAdapter
@@ -91,8 +92,8 @@ class EbicsResponse {
         @XmlValue
         lateinit var value: BigInteger
 
-        @XmlAttribute(name = "lastSegment", required = true)
-        var lastSegment: Boolean = false
+        @XmlAttribute(name = "lastSegment")
+        var lastSegment: Boolean? = null
     }
 
     @XmlAccessorType(XmlAccessType.NONE)
@@ -132,4 +133,151 @@ class EbicsResponse {
         @get:XmlSchemaType(name = "positiveInteger")
         var numSegments: BigInteger? = null
     }
+
+    companion object {
+        fun createForUploadInitializationPhase(transactionID: String, orderID: 
String): EbicsResponse {
+            return EbicsResponse().apply {
+                this.version = "H004"
+                this.revision = 1
+                this.header = EbicsResponse.Header().apply {
+                    this.authenticate = true
+                    this._static = EbicsResponse.StaticHeaderType().apply {
+                        this.transactionID = transactionID
+                    }
+                    this.mutable = EbicsResponse.MutableHeaderType().apply {
+                        this.transactionPhase = 
EbicsTypes.TransactionPhaseType.INITIALISATION
+                        this.orderID = orderID
+                        this.reportText = "[EBICS_OK] OK"
+                        this.returnCode = "000000"
+                    }
+                }
+                this.authSignature = SignatureType()
+                this.body = EbicsResponse.Body().apply {
+                    this.returnCode = EbicsResponse.ReturnCode().apply {
+                        this.authenticate = true
+                        this.value = "000000"
+                    }
+                }
+            }
+        }
+
+
+        fun createForDownloadReceiptPhase(transactionID: String, positiveAck: 
Boolean): EbicsResponse {
+            return EbicsResponse().apply {
+                this.version = "H004"
+                this.revision = 1
+                this.header = EbicsResponse.Header().apply {
+                    this.authenticate = true
+                    this._static = EbicsResponse.StaticHeaderType().apply {
+                        this.transactionID = transactionID
+                    }
+                    this.mutable = EbicsResponse.MutableHeaderType().apply {
+                        this.transactionPhase = 
EbicsTypes.TransactionPhaseType.RECEIPT
+                        if (positiveAck) {
+                            this.reportText = 
"[EBICS_DOWNLOAD_POSTPROCESS_DONE] Received positive receipt"
+                            this.returnCode = "011000"
+                        } else {
+                            this.reportText = 
"[EBICS_DOWNLOAD_POSTPROCESS_SKIPPED] Received negative receipt"
+                            this.returnCode = "011001"
+                        }
+                    }
+                }
+                this.authSignature = SignatureType()
+                this.body = EbicsResponse.Body().apply {
+                    this.returnCode = EbicsResponse.ReturnCode().apply {
+                        this.authenticate = true
+                        this.value = "000000"
+                    }
+                }
+            }
+        }
+
+
+        fun createForUploadTransferPhase(
+            transactionID: String,
+            segmentNumber: Int,
+            lastSegment: Boolean,
+            orderID: String
+        ): EbicsResponse {
+            return EbicsResponse().apply {
+                this.version = "H004"
+                this.revision = 1
+                this.header = EbicsResponse.Header().apply {
+                    this.authenticate = true
+                    this._static = EbicsResponse.StaticHeaderType().apply {
+                        this.transactionID = transactionID
+                    }
+                    this.mutable = EbicsResponse.MutableHeaderType().apply {
+                        this.transactionPhase = 
EbicsTypes.TransactionPhaseType.TRANSFER
+                        this.segmentNumber = 
EbicsResponse.SegmentNumber().apply {
+                            this.value = 
BigInteger.valueOf(segmentNumber.toLong())
+                            if (lastSegment) {
+                                this.lastSegment = true
+                            }
+                        }
+                        this.orderID = orderID
+                        this.reportText = "[EBICS_OK] OK"
+                        this.returnCode = "000000"
+                    }
+                }
+                this.authSignature = SignatureType()
+                this.body = EbicsResponse.Body().apply {
+                    this.returnCode = EbicsResponse.ReturnCode().apply {
+                        this.authenticate = true
+                        this.value = "000000"
+                    }
+                }
+            }
+        }
+
+        fun createForDownloadInitializationPhase(
+            transactionID: String,
+            numSegments: Int,
+            segmentSize: Int,
+            enc: CryptoUtil.EncryptionResult,
+            encodedData: String
+        ): EbicsResponse {
+            return EbicsResponse().apply {
+                this.version = "H004"
+                this.revision = 1
+                this.header = EbicsResponse.Header().apply {
+                    this.authenticate = true
+                    this._static = EbicsResponse.StaticHeaderType().apply {
+                        this.transactionID = transactionID
+                        this.numSegments = 
BigInteger.valueOf(numSegments.toLong())
+                    }
+                    this.mutable = EbicsResponse.MutableHeaderType().apply {
+                        this.transactionPhase = 
EbicsTypes.TransactionPhaseType.INITIALISATION
+                        this.segmentNumber = 
EbicsResponse.SegmentNumber().apply {
+                            this.lastSegment = (numSegments == 1)
+                            this.value = BigInteger.valueOf(1)
+                        }
+                        this.reportText = "[EBICS_OK] OK"
+                        this.returnCode = "000000"
+                    }
+                }
+                this.authSignature = SignatureType()
+                this.body = EbicsResponse.Body().apply {
+                    this.returnCode = EbicsResponse.ReturnCode().apply {
+                        this.authenticate = true
+                        this.value = "000000"
+                    }
+                    this.dataTransfer = 
EbicsResponse.DataTransferResponseType().apply {
+                        this.dataEncryptionInfo = 
EbicsTypes.DataEncryptionInfo().apply {
+                            this.authenticate = true
+                            this.encryptionPubKeyDigest = 
EbicsTypes.PubKeyDigest().apply {
+                                this.algorithm = 
"http://www.w3.org/2001/04/xmlenc#sha256";
+                                this.version = "E002"
+                                this.value = enc.pubKeyDigest
+                            }
+                            this.transactionKey = enc.encryptedTransactionKey
+                        }
+                        this.orderData = EbicsResponse.OrderData().apply {
+                            this.value = encodedData.substring(0, 
Math.min(segmentSize, encodedData.length))
+                        }
+                    }
+                }
+            }
+        }
+    }
 }
diff --git 
a/sandbox/src/main/kotlin/tech/libeufin/schema/ebics_h004/EbicsTypes.kt 
b/sandbox/src/main/kotlin/tech/libeufin/schema/ebics_h004/EbicsTypes.kt
index b8b7b2c..0d25014 100644
--- a/sandbox/src/main/kotlin/tech/libeufin/schema/ebics_h004/EbicsTypes.kt
+++ b/sandbox/src/main/kotlin/tech/libeufin/schema/ebics_h004/EbicsTypes.kt
@@ -202,4 +202,190 @@ class EbicsTypes private constructor() {
         @get:XmlElement(name = "Value", required = true)
         lateinit var value: String
     }
+
+    @XmlAccessorType(XmlAccessType.NONE)
+    @XmlType(name = "", propOrder = ["addressInfo", "bankInfo", 
"accountInfoList", "orderInfoList"])
+    class PartnerInfo {
+        @get:XmlElement(name = "AddressInfo", required = true)
+        lateinit var addressInfo: AddressInfo
+
+        @get:XmlElement(name = "BankInfo", required = true)
+        lateinit var bankInfo: BankInfo
+
+        @get:XmlElement(name = "AccountInfo", required = true)
+        var accountInfoList: List<AccountInfo>? = null
+
+        @get:XmlElement(name = "OrderInfo")
+        lateinit var orderInfoList: List<AuthOrderInfoType>
+    }
+
+    @XmlAccessorType(XmlAccessType.NONE)
+    @XmlType(
+        name = "",
+        propOrder = ["orderType", "fileFormat", "transferType", "orderFormat", 
"description", "numSigRequired"]
+    )
+    class AuthOrderInfoType {
+        @get:XmlElement(name = "OrderType")
+        lateinit var orderType: String
+
+        @get:XmlElement(name = "FileFormat")
+        val fileFormat: EbicsTypes.FileFormatType? = null
+
+        @get:XmlElement(name = "TransferType")
+        lateinit var transferType: String
+
+        @get:XmlElement(name = "OrderFormat", required = false)
+        var orderFormat: String? = null
+
+        @get:XmlElement(name = "Description")
+        lateinit var description: String
+
+        @get:XmlElement(name = "NumSigRequired")
+        var numSigRequired: Int? = null
+
+    }
+
+    @XmlAccessorType(XmlAccessType.NONE)
+    class UserIDType {
+        @get:XmlValue
+        lateinit var value: String;
+
+        @get:XmlAttribute(name = "Status")
+        var status: Int? = null
+    }
+
+    @XmlAccessorType(XmlAccessType.NONE)
+    @XmlType(name = "", propOrder = ["userID", "name", "permissionList"])
+    class UserInfo {
+        @get:XmlElement(name = "UserID", required = true)
+        lateinit var userID: UserIDType
+
+        @get:XmlElement(name = "Name")
+        var name: String? = null
+
+        @get:XmlElement(name = "Permission", type = UserPermission::class)
+        var permissionList: List<UserPermission>? = null
+    }
+
+    @XmlAccessorType(XmlAccessType.NONE)
+    @XmlType(name = "", propOrder = ["orderTypes", "fileFormat", "accountID", 
"maxAmount"])
+    class UserPermission {
+        @get:XmlAttribute(name = "AuthorizationLevel")
+        var authorizationLevel: String? = null
+
+        @get:XmlElement(name = "OrderTypes")
+        var orderTypes: String? = null
+
+        @get:XmlElement(name = "FileFormat")
+        val fileFormat: EbicsTypes.FileFormatType? = null
+
+        @get:XmlElement(name = "AccountID")
+        val accountID: String? = null
+
+        @get:XmlElement(name = "MaxAmount")
+        val maxAmount: String? = null
+    }
+
+    @XmlAccessorType(XmlAccessType.NONE)
+    @XmlType(name = "", propOrder = ["name", "street", "postCode", "city", 
"region", "country"])
+    class AddressInfo {
+        @get:XmlElement(name = "Name")
+        var name: String? = null
+
+        @get:XmlElement(name = "Street")
+        var street: String? = null
+
+        @get:XmlElement(name = "PostCode")
+        var postCode: String? = null
+
+        @get:XmlElement(name = "City")
+        var city: String? = null
+
+        @get:XmlElement(name = "Region")
+        var region: String? = null
+
+        @get:XmlElement(name = "Country")
+        var country: String? = null
+    }
+
+
+    @XmlAccessorType(XmlAccessType.NONE)
+    class BankInfo {
+        @get:XmlElement(name = "HostID")
+        lateinit var hostID: String
+
+        @get:XmlElement(type = EbicsTypes.Parameter::class)
+        var parameters: List<EbicsTypes.Parameter>? = null
+    }
+
+    @XmlAccessorType(XmlAccessType.NONE)
+    @XmlType(name = "", propOrder = ["accountNumberList", "bankCodeList", 
"accountHolder"])
+    class AccountInfo {
+        @get:XmlAttribute(name = "Currency")
+        var currency: String? = null
+
+        @get:XmlAttribute(name = "ID")
+        lateinit var id: String
+
+        @get:XmlAttribute(name = "Description")
+        var description: String? = null
+
+        @get:XmlElements(
+            XmlElement(name = "AccountNumber", type = 
GeneralAccountNumber::class),
+            XmlElement(name = "NationalAccountNumber", type = 
NationalAccountNumber::class)
+        )
+        var accountNumberList: List<AbstractAccountNumber>? = null
+
+        @get:XmlElements(
+            XmlElement(name = "BankCode", type = GeneralBankCode::class),
+            XmlElement(name = "NationalBankCode", type = 
NationalBankCode::class)
+        )
+        var bankCodeList: List<AbstractBankCode>? = null
+
+        @get:XmlElement(name = "AccountHolder")
+        var accountHolder: String? = null
+    }
+
+    interface AbstractAccountNumber
+
+    @XmlAccessorType(XmlAccessType.NONE)
+    class GeneralAccountNumber : AbstractAccountNumber {
+        @get:XmlAttribute(name = "international")
+        var international: Boolean = false
+
+        @get:XmlValue
+        lateinit var value: String
+    }
+
+    @XmlAccessorType(XmlAccessType.NONE)
+    class NationalAccountNumber : AbstractAccountNumber {
+        @get:XmlAttribute(name = "format")
+        lateinit var format: String
+
+        @get:XmlValue
+        lateinit var value: String
+    }
+
+    interface AbstractBankCode
+
+    @XmlAccessorType(XmlAccessType.NONE)
+    class GeneralBankCode : AbstractBankCode {
+        @get:XmlAttribute(name = "prefix")
+        var prefix: String? = null
+
+        @get:XmlAttribute(name = "international")
+        var international: Boolean = false
+
+        @get:XmlValue
+        lateinit var value: String
+    }
+
+    @XmlAccessorType(XmlAccessType.NONE)
+    class NationalBankCode : AbstractBankCode {
+        @get:XmlValue
+        lateinit var value: String
+
+        @get:XmlAttribute(name = "format")
+        lateinit var format: String
+    }
 }
\ No newline at end of file
diff --git 
a/sandbox/src/main/kotlin/tech/libeufin/schema/ebics_h004/HKDResponseOrderData.kt
 
b/sandbox/src/main/kotlin/tech/libeufin/schema/ebics_h004/HKDResponseOrderData.kt
new file mode 100644
index 0000000..6cbf05a
--- /dev/null
+++ 
b/sandbox/src/main/kotlin/tech/libeufin/schema/ebics_h004/HKDResponseOrderData.kt
@@ -0,0 +1,15 @@
+package tech.libeufin.schema.ebics_h004
+
+import java.security.Permission
+import javax.xml.bind.annotation.*
+
+@XmlAccessorType(XmlAccessType.NONE)
+@XmlType(name = "", propOrder = ["partnerInfo", "userInfo"])
+@XmlRootElement(name = "HTDResponseOrderData")
+class HKDResponseOrderData {
+    @get:XmlElement(name = "PartnerInfo", required = true)
+    lateinit var partnerInfo: EbicsTypes.PartnerInfo
+
+    @get:XmlElement(name = "UserInfo", type = EbicsTypes.UserInfo::class, 
required = true)
+    lateinit var userInfoList: List<EbicsTypes.UserInfo>
+}
diff --git 
a/sandbox/src/main/kotlin/tech/libeufin/schema/ebics_h004/HTDResponseOrderData.kt
 
b/sandbox/src/main/kotlin/tech/libeufin/schema/ebics_h004/HTDResponseOrderData.kt
index 8928071..9031e58 100644
--- 
a/sandbox/src/main/kotlin/tech/libeufin/schema/ebics_h004/HTDResponseOrderData.kt
+++ 
b/sandbox/src/main/kotlin/tech/libeufin/schema/ebics_h004/HTDResponseOrderData.kt
@@ -8,194 +8,8 @@ import javax.xml.bind.annotation.*
 @XmlRootElement(name = "HTDResponseOrderData")
 class HTDResponseOrderData {
     @get:XmlElement(name = "PartnerInfo", required = true)
-    lateinit var partnerInfo: PartnerInfo
+    lateinit var partnerInfo: EbicsTypes.PartnerInfo
 
     @get:XmlElement(name = "UserInfo", required = true)
-    lateinit var userInfo: UserInfo
-
-    @XmlAccessorType(XmlAccessType.NONE)
-    @XmlType(name = "", propOrder = ["addressInfo", "bankInfo", 
"accountInfoList", "orderInfoList"])
-    class PartnerInfo {
-        @get:XmlElement(name = "AddressInfo", required = true)
-        lateinit var addressInfo: AddressInfo
-
-        @get:XmlElement(name = "BankInfo", required = true)
-        lateinit var bankInfo: BankInfo
-
-        @get:XmlElement(name = "AccountInfo", required = true)
-        var accountInfoList: List<AccountInfo>? = null
-
-        @get:XmlElement(name = "OrderInfo")
-        lateinit var orderInfoList: List<AuthOrderInfoType>
-    }
-
-    @XmlAccessorType(XmlAccessType.NONE)
-    @XmlType(
-        name = "",
-        propOrder = ["orderType", "fileFormat", "transferType", "orderFormat", 
"description", "numSigRequired"]
-    )
-    class AuthOrderInfoType {
-        @get:XmlElement(name = "OrderType")
-        lateinit var orderType: String
-
-        @get:XmlElement(name = "FileFormat")
-        val fileFormat: EbicsTypes.FileFormatType? = null
-
-        @get:XmlElement(name = "TransferType")
-        lateinit var transferType: String
-
-        @get:XmlElement(name = "OrderFormat", required = false)
-        var orderFormat: String? = null
-
-        @get:XmlElement(name = "Description")
-        lateinit var description: String
-
-        @get:XmlElement(name = "NumSigRequired")
-        var numSigRequired: Int? = null
-
-    }
-
-    @XmlAccessorType(XmlAccessType.NONE)
-    class UserIDType {
-        @get:XmlValue
-        lateinit var value: String;
-
-        @get:XmlAttribute(name = "Status")
-        var status: Int? = null
-    }
-
-    @XmlAccessorType(XmlAccessType.NONE)
-    @XmlType(name = "", propOrder = ["userID", "name", "permissionList"])
-    class UserInfo {
-        @get:XmlElement(name = "UserID", required = true)
-        lateinit var userID: UserIDType
-
-        @get:XmlElement(name = "Name")
-        var name: String? = null
-
-        @get:XmlElement(name = "Permission", type = UserPermission::class)
-        var permissionList: List<UserPermission>? = null
-    }
-
-    @XmlAccessorType(XmlAccessType.NONE)
-    @XmlType(name = "", propOrder = ["orderTypes", "fileFormat", "accountID", 
"maxAmount"])
-    class UserPermission {
-        @get:XmlAttribute(name = "AuthorizationLevel")
-        var authorizationLevel: String? = null
-
-        @get:XmlElement(name = "OrderTypes")
-        var orderTypes: String? = null
-
-        @get:XmlElement(name = "FileFormat")
-        val fileFormat: EbicsTypes.FileFormatType? = null
-
-        @get:XmlElement(name = "AccountID")
-        val accountID: String? = null
-
-        @get:XmlElement(name = "MaxAmount")
-        val maxAmount: String? = null
-    }
-
-    @XmlAccessorType(XmlAccessType.NONE)
-    @XmlType(name = "", propOrder = ["name", "street", "postCode", "city", 
"region", "country"])
-    class AddressInfo {
-        @get:XmlElement(name = "Name")
-        var name: String? = null
-
-        @get:XmlElement(name = "Street")
-        var street: String? = null
-
-        @get:XmlElement(name = "PostCode")
-        var postCode: String? = null
-
-        @get:XmlElement(name = "City")
-        var city: String? = null
-
-        @get:XmlElement(name = "Region")
-        var region: String? = null
-
-        @get:XmlElement(name = "Country")
-        var country: String? = null
-    }
-
-
-    @XmlAccessorType(XmlAccessType.NONE)
-    class BankInfo {
-        @get:XmlElement(name = "HostID")
-        lateinit var hostID: String
-
-        @get:XmlElement(type = EbicsTypes.Parameter::class)
-        var parameters: List<EbicsTypes.Parameter>? = null
-    }
-
-    @XmlAccessorType(XmlAccessType.NONE)
-    @XmlType(name = "", propOrder = ["accountNumberList", "bankCodeList", 
"accountHolder"])
-    class AccountInfo {
-        @get:XmlAttribute(name = "Currency")
-        var currency: String? = null
-
-        @get:XmlAttribute(name = "ID")
-        lateinit var id: String
-
-        @get:XmlAttribute(name = "Description")
-        var description: String? = null
-
-        @get:XmlElements(
-            XmlElement(name = "AccountNumber", type = 
GeneralAccountNumber::class),
-            XmlElement(name = "NationalAccountNumber", type = 
NationalAccountNumber::class)
-        )
-        var accountNumberList: List<AbstractAccountNumber>? = null
-
-        @get:XmlElements(
-            XmlElement(name = "BankCode", type = GeneralBankCode::class),
-            XmlElement(name = "NationalBankCode", type = 
NationalBankCode::class)
-        )
-        var bankCodeList: List<AbstractBankCode>? = null
-
-        @get:XmlElement(name = "AccountHolder")
-        var accountHolder: String? = null
-    }
-
-    interface AbstractAccountNumber
-
-    @XmlAccessorType(XmlAccessType.NONE)
-    class GeneralAccountNumber : AbstractAccountNumber {
-        @get:XmlAttribute(name = "international")
-        var international: Boolean = false
-
-        @get:XmlValue
-        lateinit var value: String
-    }
-
-    @XmlAccessorType(XmlAccessType.NONE)
-    class NationalAccountNumber : AbstractAccountNumber {
-        @get:XmlAttribute(name = "format")
-        lateinit var format: String
-
-        @get:XmlValue
-        lateinit var value: String
-    }
-
-    interface AbstractBankCode
-
-    @XmlAccessorType(XmlAccessType.NONE)
-    class GeneralBankCode : AbstractBankCode {
-        @get:XmlAttribute(name = "prefix")
-        var prefix: String? = null
-
-        @get:XmlAttribute(name = "international")
-        var international: Boolean = false
-
-        @get:XmlValue
-        lateinit var value: String
-    }
-
-    @XmlAccessorType(XmlAccessType.NONE)
-    class NationalBankCode : AbstractBankCode {
-        @get:XmlValue
-        lateinit var value: String
-
-        @get:XmlAttribute(name = "format")
-        lateinit var format: String
-    }
+    lateinit var userInfo: EbicsTypes.UserInfo
 }
diff --git a/sandbox/src/test/kotlin/EbicsMessagesTest.kt 
b/sandbox/src/test/kotlin/EbicsMessagesTest.kt
index 3ab7ce5..d3009d6 100644
--- a/sandbox/src/test/kotlin/EbicsMessagesTest.kt
+++ b/sandbox/src/test/kotlin/EbicsMessagesTest.kt
@@ -177,13 +177,13 @@ class EbicsMessagesTest {
     @Test
     fun testHtd() {
         val htd = HTDResponseOrderData().apply {
-            this.partnerInfo = HTDResponseOrderData.PartnerInfo().apply {
+            this.partnerInfo = EbicsTypes.PartnerInfo().apply {
                 this.accountInfoList = listOf(
-                    HTDResponseOrderData.AccountInfo().apply {
+                    EbicsTypes.AccountInfo().apply {
                         this.id = "acctid1"
                         this.accountHolder = "Mina Musterfrau"
                         this.accountNumberList = listOf(
-                            HTDResponseOrderData.GeneralAccountNumber().apply {
+                            EbicsTypes.GeneralAccountNumber().apply {
                                 this.international = true
                                 this.value = "AT411100000237571500"
                             }
@@ -191,21 +191,21 @@ class EbicsMessagesTest {
                         this.currency = "EUR"
                         this.description = "some account"
                         this.bankCodeList = listOf(
-                            HTDResponseOrderData.GeneralBankCode().apply {
+                            EbicsTypes.GeneralBankCode().apply {
                                 this.international = true
                                 this.value = "ABAGATWWXXX"
                             }
                         )
                     }
                 )
-                this.addressInfo = HTDResponseOrderData.AddressInfo().apply {
+                this.addressInfo = EbicsTypes.AddressInfo().apply {
                     this.name = "Foo"
                 }
-                this.bankInfo = HTDResponseOrderData.BankInfo().apply {
+                this.bankInfo = EbicsTypes.BankInfo().apply {
                     this.hostID = "MYHOST"
                 }
                 this.orderInfoList = listOf(
-                    HTDResponseOrderData.AuthOrderInfoType().apply {
+                    EbicsTypes.AuthOrderInfoType().apply {
                         this.description = "foo"
                         this.orderType = "CCC"
                         this.orderFormat = "foo"
@@ -213,14 +213,14 @@ class EbicsMessagesTest {
                     }
                 )
             }
-            this.userInfo = HTDResponseOrderData.UserInfo().apply {
+            this.userInfo = EbicsTypes.UserInfo().apply {
                 this.name = "Some User"
-                this.userID = HTDResponseOrderData.UserIDType().apply {
+                this.userID = EbicsTypes.UserIDType().apply {
                     this.status = 2
                     this.value = "myuserid"
                 }
                 this.permissionList = listOf(
-                    HTDResponseOrderData.UserPermission().apply {
+                    EbicsTypes.UserPermission().apply {
                         this.orderTypes = "CCC ABC"
                     }
                 )

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



reply via email to

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