gnunet-svn
[Top][All Lists]
Advanced

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

[libeufin] branch master updated (64b3929 -> f73bdad)


From: gnunet
Subject: [libeufin] branch master updated (64b3929 -> f73bdad)
Date: Fri, 08 May 2020 20:04:44 +0200

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

ms pushed a change to branch master
in repository libeufin.

    from 64b3929  new API mere endpoints definition
     new 1985072  Comments.
     new 6aaa8b6  new API.
     new 606a74d  fix compilation
     new cba69c6  GET /user
     new 993dabf  admin authentication helper
     new e732d76  POST /users
     new 089a03b  add GET /bank-accounts, fix GET /user.
     new f73bdad  POST preapred-payments/submit

The 8 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:
 nexus/build.gradle                                 |  11 +-
 nexus/src/main/kotlin/tech/libeufin/nexus/DB.kt    |  15 +-
 .../src/main/kotlin/tech/libeufin/nexus/Helpers.kt |  43 +-
 nexus/src/main/kotlin/tech/libeufin/nexus/JSON.kt  |  30 +-
 nexus/src/main/kotlin/tech/libeufin/nexus/Main.kt  | 822 +++------------------
 nexus/src/main/kotlin/tech/libeufin/nexus/Main2.kt | 181 -----
 .../libeufin/nexus/{Main.kt => MainDeprecated.kt}  |   9 -
 util/src/main/kotlin/DBTypes.kt                    |  26 +-
 8 files changed, 204 insertions(+), 933 deletions(-)
 delete mode 100644 nexus/src/main/kotlin/tech/libeufin/nexus/Main2.kt
 copy nexus/src/main/kotlin/tech/libeufin/nexus/{Main.kt => MainDeprecated.kt} 
(99%)

diff --git a/nexus/build.gradle b/nexus/build.gradle
index 6c31a96..ff58a78 100644
--- a/nexus/build.gradle
+++ b/nexus/build.gradle
@@ -16,7 +16,7 @@ plugins {
 
 sourceSets {
     main.kotlin.srcDirs = ["src/main/kotlin"]
-    main.kotlin.excludes = ["**/Main2.kt"]
+    main.kotlin.excludes = ["**/MainDeprecated.kt"]
 }
 
 task installToPrefix(type: Copy) {
@@ -71,15 +71,16 @@ dependencies {
     testImplementation group: 'junit', name: 'junit', version: '4.12'
 }
 
-application {
-    mainClassName = "tech.libeufin.nexus.MainKt"
-}
-
 dependencies {
     implementation project(":util")
     compile "io.ktor:ktor-client-apache:1.2.4"
 }
 
+application {
+    mainClassName = "tech.libeufin.nexus.MainKt"
+}
+
+
 jar {
     manifest {
         attributes "Main-Class": "tech.libeufin.nexus.MainKt"
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/DB.kt 
b/nexus/src/main/kotlin/tech/libeufin/nexus/DB.kt
index ba22010..ba5f7f8 100644
--- a/nexus/src/main/kotlin/tech/libeufin/nexus/DB.kt
+++ b/nexus/src/main/kotlin/tech/libeufin/nexus/DB.kt
@@ -5,7 +5,9 @@ import org.jetbrains.exposed.dao.*
 import org.jetbrains.exposed.sql.*
 import org.jetbrains.exposed.sql.transactions.TransactionManager
 import org.jetbrains.exposed.sql.transactions.transaction
-import tech.libeufin.util.IntIdTableWithAmount
+import tech.libeufin.nexus.BankAccountsTable.entityId
+import tech.libeufin.nexus.BankAccountsTable.primaryKey
+import tech.libeufin.util.amount
 import java.sql.Connection
 
 const val ID_MAX_LENGTH = 50
@@ -117,8 +119,8 @@ class RawBankTransactionEntity(id: EntityID<Long>) : 
LongEntity(id) {
 /**
  * Represent a prepare payment.
  */
-object Pain001Table : IntIdTableWithAmount() {
-    val msgId = long("msgId").uniqueIndex().autoIncrement()
+object Pain001Table : IdTable<String>() {
+    override val id = BankAccountsTable.varchar("id", 
ID_MAX_LENGTH).entityId().primaryKey()
     val paymentId = long("paymentId")
     val fileDate = long("fileDate")
     val sum = amount("sum")
@@ -139,9 +141,8 @@ object Pain001Table : IntIdTableWithAmount() {
     val invalid = bool("invalid").default(false)
     val nexusUser = reference("nexusUser", NexusUsersTable)
 }
-class Pain001Entity(id: EntityID<Int>) : IntEntity(id) {
-    companion object : IntEntityClass<Pain001Entity>(Pain001Table)
-    var msgId by Pain001Table.msgId
+class Pain001Entity(id: EntityID<String>) : Entity<String>(id) {
+    companion object : EntityClass<String, Pain001Entity>(Pain001Table)
     var paymentId by Pain001Table.paymentId
     var date by Pain001Table.fileDate
     var sum by Pain001Table.sum
@@ -164,7 +165,7 @@ class Pain001Entity(id: EntityID<Int>) : IntEntity(id) {
  */
 object BankAccountsTable : IdTable<String>() {
     override val id = varchar("id", ID_MAX_LENGTH).entityId().primaryKey()
-    val accountHolder = text("accountHolder").nullable()
+    val accountHolder = text("accountHolder")
     val iban = text("iban")
     val bankCode = text("bankCode") 
 }
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/Helpers.kt 
b/nexus/src/main/kotlin/tech/libeufin/nexus/Helpers.kt
index e7663eb..638d2fc 100644
--- a/nexus/src/main/kotlin/tech/libeufin/nexus/Helpers.kt
+++ b/nexus/src/main/kotlin/tech/libeufin/nexus/Helpers.kt
@@ -20,6 +20,10 @@ import java.time.ZonedDateTime
 import java.time.Instant
 import java.time.ZoneId
 
+fun isProduction(): Boolean {
+    return System.getenv("NEXUS_PRODUCTION") != null
+}
+
 fun calculateRefund(amount: String): Amount {
     // fixme: must apply refund fees!
     return Amount(amount)
@@ -77,6 +81,31 @@ fun getBankAccountFromNexusUserId(id: String): 
BankAccountEntity {
     return map.bankAccount
 }
 
+/**
+ * Given a nexus user id, returns the _list_ of bank accounts associated to it.
+ *
+ * @param id the subscriber id
+ * @return the (non-empty) list of bank accounts associated with this user.
+ */
+fun getBankAccountsFromNexusUserId(id: String): MutableList<BankAccountEntity> 
{
+    logger.debug("Looking up bank account of user '$id'")
+    val ret = mutableListOf<BankAccountEntity>()
+    transaction {
+        BankAccountMapEntity.find {
+            BankAccountMapsTable.nexusUser eq id
+        }.forEach {
+            ret.add(it.bankAccount)
+        }
+    }
+    if (ret.isEmpty()) {
+        throw NexusError(
+            HttpStatusCode.NotFound,
+            "Such user '$id' does not have any bank account associated"
+        )
+    }
+    return ret
+}
+
 fun getSubscriberDetailsInternal(subscriber: EbicsSubscriberEntity): 
EbicsClientSubscriberDetails {
     var bankAuthPubValue: RSAPublicKey? = null
     if (subscriber.bankAuthenticationPublicKey != null) {
@@ -259,7 +288,7 @@ fun createPain001document(pain001Entity: Pain001Entity): 
String {
 fun createPain001entity(entry: Pain001Data, nexusUser: NexusUserEntity): 
Pain001Entity {
     val randomId = Random().nextLong()
     return transaction {
-        Pain001Entity.new {
+        Pain001Entity.new(randomId.toString()) {
             subject = entry.subject
             sum = entry.sum
             debitorIban = entry.debitorIban
@@ -270,7 +299,6 @@ fun createPain001entity(entry: Pain001Data, nexusUser: 
NexusUserEntity): Pain001
             creditorIban = entry.creditorIban
             date = DateTime.now().millis
             paymentId = randomId
-            msgId = randomId
             endToEndId = randomId
             this.nexusUser = nexusUser
         }
@@ -325,7 +353,7 @@ fun extractUserAndHashedPassword(authorizationHeader: 
String): Pair<String, Byte
  * and makes sure that the user exists in the system.
  *
  * @param authorization the Authorization:-header line.
- * @return subscriber id
+ * @return user id
  */
 fun authenticateRequest(authorization: String?): String {
     val headerLine = if (authorization == null) throw NexusError(
@@ -340,6 +368,15 @@ fun authenticateRequest(authorization: String?): String {
     return subscriber.id.value
 }
 
+fun authenticateAdminRequest(authorization: String?): String {
+    val userId = authenticateRequest(authorization)
+    if (!userId.equals("admin")) throw NexusError(
+        HttpStatusCode.Forbidden,
+        "Not the 'admin' user"
+    )
+    return userId
+}
+
 /**
  * Check if the subscriber has the right to use the (claimed) bank account.
  * @param subscriber id of the EBICS subscriber to check
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/JSON.kt 
b/nexus/src/main/kotlin/tech/libeufin/nexus/JSON.kt
index 63acf4b..c6d6f01 100644
--- a/nexus/src/main/kotlin/tech/libeufin/nexus/JSON.kt
+++ b/nexus/src/main/kotlin/tech/libeufin/nexus/JSON.kt
@@ -76,15 +76,15 @@ data class EbicsErrorJson(
     val error: EbicsErrorDetailJson
 )
 
-data class BankAccountInfoElement(
-    var accountHolderName: String? = null,
+data class BankAccount(
+    var holder: String,
     var iban: String,
-    var bankCode: String,
-    var accountId: String
+    var bic: String,
+    var account: String
 )
 
-data class BankAccountsInfoResponse(
-    var accounts: MutableList<BankAccountInfoElement> = mutableListOf()
+data class BankAccounts(
+    var accounts: MutableList<BankAccount> = mutableListOf()
 )
 
 /** THE NEXUS USER */
@@ -95,13 +95,20 @@ data class NexusUser(
     val transports: MutableList<Any> = mutableListOf()
 )
 
+/** is "UserResponse" in the API spec */
+data class UserResponse(
+    val username: String,
+    val superuser: Boolean
+)
+
 /** Instructs the nexus to CREATE a new user */
-data class NexusUserRequest(
-    val password: String?
+data class User(
+    val username: String,
+    val password: String
 )
 
 /** Collection of all the nexus users existing in the system */
-data class NexusUsers(
+data class Users(
     val users: MutableList<NexusUser> = mutableListOf()
 )
 
@@ -149,4 +156,9 @@ data class Pain001Data(
 
 data class RawPayments(
     var payments: MutableList<RawPayment> = mutableListOf()
+)
+
+data class SubmitPayment(
+    val uuid: String,
+    val transport: 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
index e0ae928..e0d61f2 100644
--- a/nexus/src/main/kotlin/tech/libeufin/nexus/Main.kt
+++ b/nexus/src/main/kotlin/tech/libeufin/nexus/Main.kt
@@ -58,15 +58,9 @@ import java.util.zip.InflaterInputStream
 import javax.crypto.EncryptedPrivateKeyInfo
 import javax.sql.rowset.serial.SerialBlob
 
-
 data class NexusError(val statusCode: HttpStatusCode, val reason: String) : 
Exception()
-
 val logger: Logger = LoggerFactory.getLogger("tech.libeufin.nexus")
 
-fun isProduction(): Boolean {
-    return System.getenv("NEXUS_PRODUCTION") != null
-}
-
 @ExperimentalIoApi
 @KtorExperimentalAPI
 fun main() {
@@ -120,7 +114,6 @@ fun main() {
                 return@intercept finish()
             }
         }
-
         receivePipeline.intercept(ApplicationReceivePipeline.Before) {
             if (this.context.request.headers["Content-Encoding"] == "deflate") 
{
                 logger.debug("About to inflate received data")
@@ -132,751 +125,172 @@ fun main() {
             proceed()
             return@intercept
         }
-
         routing {
-
-            /** GENERAL / DEBUG ENDPOINTS */
-
-            get("/") {
-                call.respondText("Hello by Nexus!\n")
-                return@get
-            }
-            get("/test-auth") {
-                authenticateRequest(call.request.headers["Authorization"])
-                call.respondText("Authenticated!", ContentType.Text.Plain, 
HttpStatusCode.OK)
-                return@get
-            }
-
-            /** USER endpoints (no EBICS) */
-
-            get("/users/{id}/history") {
-                /** NOTE: behaviour could be augmented by filtering on date 
range.  */
-                val nexusUser = extractNexusUser(call.parameters["id"])
-                val ret = RawPayments()
-                transaction {
-                    RawBankTransactionEntity.find {
-                        RawBankTransactionsTable.nexusUser eq 
nexusUser.id.value
-                    }.forEach {
-                        ret.payments.add(
-                            RawPayment(
-                                debitorIban = it.debitorIban,
-                                creditorIban = it.creditorIban,
-                                subject = it.unstructuredRemittanceInformation,
-                                date = DateTime(it.bookingDate).toDashedDate(),
-                                amount = "${it.currency}:${it.amount}"
-                            )
-                        )
-                    }
-                }
-                call.respond(
-                    HttpStatusCode.OK,
-                    ret
-                )
-                return@get
-            }
-            /** Lists the users known to this system */
-            get("/users") {
-                val ret = NexusUsers()
-                transaction {
-                    NexusUserEntity.all().forEach {
-                        val nexusUser = NexusUser(userID = it.id.value)
-                        val ebicsSubscriber = it.ebicsSubscriber
-                        if (ebicsSubscriber != null) {
-                            nexusUser.transports.add(
-                                EbicsSubscriber(
-                                    userID = ebicsSubscriber.userID,
-                                    ebicsURL = ebicsSubscriber.ebicsURL,
-                                    hostID = ebicsSubscriber.hostID,
-                                    partnerID = ebicsSubscriber.partnerID,
-                                    systemID = ebicsSubscriber.systemID
-                                )
-                            )
-                        }
-                        if (it.testSubscriber != null) {
-                            nexusUser.transports.add(TestSubscriber())
-                        }
-                    }
-                }
-                call.respond(ret)
-                return@get
-            }
-            /** Get all the details associated with a NEXUS user */
-            get("/users/{id}") {
-                val response = transaction {
-                    val nexusUser = extractNexusUser(call.parameters["id"])
-                    NexusUser(
-                        userID = nexusUser.id.value
+            /**
+             * Shows information about the requesting user.
+             */
+            get("/user") {
+                val userId = 
authenticateRequest(call.request.headers["Authorization"])
+                val ret = transaction {
+                    NexusUserEntity.findById(userId)
+                    UserResponse(
+                        username = userId,
+                        superuser = userId.equals("admin")
                     )
                 }
-                call.respond(HttpStatusCode.OK, response)
-                return@get
-            }
-            /** Make a new NEXUS user in the system */
-            post("/users/{id}") {
-                val newUserId = expectId(call.parameters["id"])
-                val body = call.receive<NexusUserRequest>()
-                transaction {
-                    NexusUserEntity.new(id = newUserId) {
-                        password = if (body.password != null) {
-                            
SerialBlob(CryptoUtil.hashStringSHA256(body.password))
-                        } else {
-                            logger.debug("No password set for $newUserId")
-                            null
-                        }
-                    }
-                }
-                call.respondText(
-                    "New NEXUS user registered. ID: $newUserId",
-                    ContentType.Text.Plain,
-                    HttpStatusCode.OK
-                )
-                return@post
-            }
-            /** Show bank accounts associated with a given NEXUS user */
-            get("/users/{id}/accounts") {
-                // this information is only avaiable *after* HTD or HKD has 
been called
-                val id = expectId(call.parameters["id"])
-                val ret = BankAccountsInfoResponse()
-                transaction {
-                    BankAccountMapEntity.find {
-                        BankAccountMapsTable.nexusUser eq id
-                    }.forEach {
-                        ret.accounts.add(
-                            BankAccountInfoElement(
-                                accountHolderName = 
it.bankAccount.accountHolder,
-                                iban = it.bankAccount.iban,
-                                bankCode = it.bankAccount.bankCode,
-                                accountId = it.bankAccount.id.value
-                            )
-                        )
-                    }
-                }
-                call.respond(
-                    HttpStatusCode.OK,
-                    ret
-                )
-                return@get
-            }
-            /** Show PREPARED payments */
-            get("/users/{id}/payments") {
-                val nexusUserId = expectId(call.parameters["id"])
-                val ret = RawPayments()
-                transaction {
-                    val nexusUser = extractNexusUser(nexusUserId)
-                    val bankAccountsMap = BankAccountMapEntity.find {
-                        BankAccountMapsTable.nexusUser eq nexusUser.id
-                    }
-                    bankAccountsMap.forEach {
-                        Pain001Entity.find {
-                            Pain001Table.debitorIban eq it.bankAccount.iban
-                        }.forEach {
-                            ret.payments.add(
-                                RawPayment(
-                                    creditorIban = it.creditorIban,
-                                    debitorIban = it.debitorIban,
-                                    subject = it.subject,
-                                    amount = "${it.currency}:${it.sum}",
-                                    date = DateTime(it.date).toDashedDate()
-                                )
-                            )
-                        }
-                    }
-                }
-                call.respond(ret)
+                call.respond(HttpStatusCode.OK, ret)
                 return@get
             }
-            post("/users/{id}/prepare-payment") {
-                val nexusUser = extractNexusUser(call.parameters["id"])
-                val pain001data = call.receive<Pain001Data>()
-                transaction {
-                    if (!userHasRights(nexusUser, pain001data.debitorIban)) {
-                        throw NexusError(
-                            HttpStatusCode.BadRequest,
-                            "User ${nexusUser.id.value} can't access 
${pain001data.debitorIban}"
-                        )
-                    }
-                }
-                createPain001entity(pain001data, nexusUser)
-                call.respondText(
-                    "Payment instructions persisted in DB",
-                    ContentType.Text.Plain, HttpStatusCode.OK
-                )
-                return@post
-            }
-            get("/users/{id}/raw-payments") {
-                val nexusUser = extractNexusUser(call.parameters["id"])
-                var ret = RawPayments()
-                transaction {
-                    RawBankTransactionEntity.find {
-                        RawBankTransactionsTable.nexusUser eq 
nexusUser.id.value
-                    }.forEach {
-                        ret.payments.add(
-                            RawPayment(
-                                creditorIban = it.creditorIban,
-                                debitorIban = it.debitorIban,
-                                subject = it.unstructuredRemittanceInformation,
-                                date = DateTime(it.bookingDate).toDashedDate(),
-                                amount = it.amount + " " + it.currency
-                            )
-                        )
-                    }
-                }
-                call.respond(
-                    HttpStatusCode.OK,
-                    ret
+            /**
+             * Add a new ordinary user in the system (requires "admin" 
privileges)
+             */
+            post("/users") {
+                authenticateAdminRequest(call.request.headers["Authorization"])
+                val body = call.receive<User>()
+                if (body.username.equals("admin")) throw NexusError(
+                    HttpStatusCode.Forbidden,
+                    "'admin' is a reserved username"
                 )
-                return@get
-            }
-            /** Associate a EBICS subscriber to the existing user */
-            post("/ebics/subscribers/{id}") {
-                val nexusUser = extractNexusUser(call.parameters["id"])
-                val body = call.receive<EbicsSubscriber>()
-                val pairA = CryptoUtil.generateRsaKeyPair(2048)
-                val pairB = CryptoUtil.generateRsaKeyPair(2048)
-                val pairC = CryptoUtil.generateRsaKeyPair(2048)
                 transaction {
-                    val newEbicsSubscriber = EbicsSubscriberEntity.new {
-                        ebicsURL = body.ebicsURL
-                        hostID = body.hostID
-                        partnerID = body.partnerID
-                        userID = body.userID
-                        systemID = body.systemID
-                        signaturePrivateKey = SerialBlob(pairA.private.encoded)
-                        encryptionPrivateKey = 
SerialBlob(pairB.private.encoded)
-                        authenticationPrivateKey = 
SerialBlob(pairC.private.encoded)
+                    NexusUserEntity.new(body.username) {
+                        password = 
SerialBlob(CryptoUtil.hashStringSHA256(body.password))
                     }
-                    nexusUser.ebicsSubscriber = newEbicsSubscriber
                 }
                 call.respondText(
-                    "EBICS user successfully created",
+                    "New NEXUS user registered. ID: ${body.username}",
                     ContentType.Text.Plain,
                     HttpStatusCode.OK
                 )
                 return@post
             }
-            post("/ebics/subscribers/{id}/restoreBackup") {
-                val body = call.receive<EbicsKeysBackupJson>()
-                val nexusId = expectId(call.parameters["id"])
-                val subscriber = transaction {
-                    NexusUserEntity.findById(nexusId)
-                }
-                if (subscriber != null) {
-                    call.respond(
-                        HttpStatusCode.Conflict,
-                        NexusErrorJson("ID exists, please choose a new one")
-                    )
-                    return@post
-                }
-                val (authKey, encKey, sigKey) = try {
-                    Triple(
-                        CryptoUtil.decryptKey(
-                            
EncryptedPrivateKeyInfo(base64ToBytes(body.authBlob)), body.passphrase!!
-                        ),
-                        CryptoUtil.decryptKey(
-                            
EncryptedPrivateKeyInfo(base64ToBytes(body.encBlob)), body.passphrase
-                        ),
-                        CryptoUtil.decryptKey(
-                            
EncryptedPrivateKeyInfo(base64ToBytes(body.sigBlob)), body.passphrase
+            /**
+             * Shows the bank accounts belonging to the requesting user.
+             */
+            get("/bank-accounts") {
+                val userId = 
authenticateRequest(call.request.headers["Authorization"])
+                val bankAccounts = BankAccounts()
+                getBankAccountsFromNexusUserId(userId).forEach {
+                    bankAccounts.accounts.add(
+                        BankAccount(
+                            holder = it.accountHolder,
+                            iban = it.iban,
+                            bic = it.bankCode,
+                            account = it.id.value
                         )
                     )
-                } catch (e: Exception) {
-                    e.printStackTrace()
-                    logger.info("Restoring keys failed, probably due to wrong 
passphrase")
-                    throw NexusError(HttpStatusCode.BadRequest, reason = "Bad 
backup given")
                 }
-                logger.info("Restoring keys, creating new user: $nexusId")
-                try {
-                    transaction {
-                        NexusUserEntity.new(id = nexusId) {
-                            ebicsSubscriber = EbicsSubscriberEntity.new {
-                                ebicsURL = body.ebicsURL
-                                hostID = body.hostID
-                                partnerID = body.partnerID
-                                userID = body.userID
-                                signaturePrivateKey = 
SerialBlob(sigKey.encoded)
-                                encryptionPrivateKey = 
SerialBlob(encKey.encoded)
-                                authenticationPrivateKey = 
SerialBlob(authKey.encoded)
-                            }
-                        }
-                    }
-                } catch (e: Exception) {
-                    print(e)
-                    call.respond(NexusErrorJson("Could not store the new 
account into database"))
-                    return@post
-                }
-                call.respondText(
-                    "Keys successfully restored",
-                    ContentType.Text.Plain,
-                    HttpStatusCode.OK
-                )
-                return@post
-            }
-
-            /** EBICS CONVENIENCE */
-
-            get("/ebics/subscribers/{id}/pubkeys") {
-                val nexusUser = extractNexusUser(call.parameters["id"])
-                val response = transaction {
-                    val subscriber = getEbicsSubscriberFromUser(nexusUser)
-                    val authPriv = 
CryptoUtil.loadRsaPrivateKey(subscriber.authenticationPrivateKey.toByteArray())
-                    val authPub = CryptoUtil.getRsaPublicFromPrivate(authPriv)
-                    val encPriv = 
CryptoUtil.loadRsaPrivateKey(subscriber.encryptionPrivateKey.toByteArray())
-                    val encPub = CryptoUtil.getRsaPublicFromPrivate(encPriv)
-                    val sigPriv = 
CryptoUtil.loadRsaPrivateKey(subscriber.signaturePrivateKey.toByteArray())
-                    val sigPub = CryptoUtil.getRsaPublicFromPrivate(sigPriv)
-                    EbicsPubKeyInfo(
-                        bytesToBase64(authPub.encoded),
-                        bytesToBase64(encPub.encoded),
-                        bytesToBase64(sigPub.encoded)
-                    )
-                }
-                call.respond(
-                    HttpStatusCode.OK,
-                    response
-                )
+                return@get
             }
-            get("/ebics/subscribers/{id}/keyletter") {
-                val nexusUserId = expectId(call.parameters["id"])
-                var usernameLine = "TODO"
-                var recipientLine = "TODO"
-                val customerIdLine = "TODO"
-                var userIdLine = ""
-                var esExponentLine = ""
-                var esModulusLine = ""
-                var authExponentLine = ""
-                var authModulusLine = ""
-                var encExponentLine = ""
-                var encModulusLine = ""
-                var esKeyHashLine = ""
-                var encKeyHashLine = ""
-                var authKeyHashLine = ""
-                val esVersionLine = "A006"
-                val authVersionLine = "X002"
-                val encVersionLine = "E002"
-                val now = Date()
-                val dateFormat = SimpleDateFormat("DD.MM.YYYY")
-                val timeFormat = SimpleDateFormat("HH:mm:ss")
-                val dateLine = dateFormat.format(now)
-                val timeLine = timeFormat.format(now)
-                var hostID = ""
-                transaction {
-                    val nexusUser = extractNexusUser(nexusUserId)
-                    val subscriber = getEbicsSubscriberFromUser(nexusUser)
-                    val signPubTmp = CryptoUtil.getRsaPublicFromPrivate(
-                        
CryptoUtil.loadRsaPrivateKey(subscriber.signaturePrivateKey.toByteArray())
-                    )
-                    val authPubTmp = CryptoUtil.getRsaPublicFromPrivate(
-                        
CryptoUtil.loadRsaPrivateKey(subscriber.authenticationPrivateKey.toByteArray())
-                    )
-                    val encPubTmp = CryptoUtil.getRsaPublicFromPrivate(
-                        
CryptoUtil.loadRsaPrivateKey(subscriber.encryptionPrivateKey.toByteArray())
-                    )
-                    hostID = subscriber.hostID
-                    userIdLine = subscriber.userID
-                    esExponentLine = 
signPubTmp.publicExponent.toUnsignedHexString()
-                    esModulusLine = signPubTmp.modulus.toUnsignedHexString()
-                    encExponentLine = 
encPubTmp.publicExponent.toUnsignedHexString()
-                    encModulusLine = encPubTmp.modulus.toUnsignedHexString()
-                    authExponentLine = 
authPubTmp.publicExponent.toUnsignedHexString()
-                    authModulusLine = authPubTmp.modulus.toUnsignedHexString()
-                    esKeyHashLine = 
CryptoUtil.getEbicsPublicKeyHash(signPubTmp).toHexString()
-                    encKeyHashLine = 
CryptoUtil.getEbicsPublicKeyHash(encPubTmp).toHexString()
-                    authKeyHashLine = 
CryptoUtil.getEbicsPublicKeyHash(authPubTmp).toHexString()
-                }
-                val iniLetter = """
-                    |Name: ${usernameLine}
-                    |Date: ${dateLine}
-                    |Time: ${timeLine}
-                    |Recipient: ${recipientLine}
-                    |Host ID: ${hostID}
-                    |User ID: ${userIdLine}
-                    |Partner ID: ${customerIdLine}
-                    |ES version: ${esVersionLine}
-                    
-                    |Public key for the electronic signature:
-                    
-                    |Exponent:
-                    |${chunkString(esExponentLine)}
-                    
-                    |Modulus:
-                    |${chunkString(esModulusLine)}
-                    
-                    |SHA-256 hash:
-                    |${chunkString(esKeyHashLine)}
-                    
-                    |I hereby confirm the above public keys for my electronic 
signature.
-                    
-                    |__________
-                    |Place/date
-                    
-                    |__________
-                    |Signature
-                    |
-                """.trimMargin()
-
-                val hiaLetter = """
-                    |Name: ${usernameLine}
-                    |Date: ${dateLine}
-                    |Time: ${timeLine}
-                    |Recipient: ${recipientLine}
-                    |Host ID: ${hostID}
-                    |User ID: ${userIdLine}
-                    |Partner ID: ${customerIdLine}
-                    |Identification and authentication signature version: 
${authVersionLine}
-                    |Encryption version: ${encVersionLine}
-                    
-                    |Public key for the identification and authentication 
signature:
-                    
-                    |Exponent:
-                    |${chunkString(authExponentLine)}
-                    
-                    |Modulus:
-                    |${chunkString(authModulusLine)}
-                    
-                    |SHA-256 hash:
-                    |${chunkString(authKeyHashLine)}
-                    
-                    |Public encryption key:
-                    
-                    |Exponent:
-                    |${chunkString(encExponentLine)}
-                    
-                    |Modulus:
-                    |${chunkString(encModulusLine)}
-                    
-                    |SHA-256 hash:
-                    |${chunkString(encKeyHashLine)}              
-
-                    |I hereby confirm the above public keys for my electronic 
signature.
-                    
-                    |__________
-                    |Place/date
-                    
-                    |__________
-                    |Signature
-                    |
-                """.trimMargin()
+            /**
+             * Submit one particular payment at the bank.
+             */
+            post("/bank-accounts/{accountid}/prepared-payments/submit") {
+                val userId = 
authenticateRequest(call.request.headers["Authorization"])
+                val body = call.receive<SubmitPayment>()
 
-                call.respondText(
-                    
"####INI####:\n${iniLetter}\n\n\n####HIA####:\n${hiaLetter}",
-                    ContentType.Text.Plain,
-                    HttpStatusCode.OK
+                // 1 find payment.
+                val preparedPayment = transaction {
+                    Pain001Entity.findById(body.uuid)
+                } ?: throw NexusError(
+                    HttpStatusCode.NotFound,
+                    "Could not find prepared payment: ${body.uuid}"
                 )
-            }
-
 
-            /** STATE CHANGES VIA EBICS */
-
-            post("/ebics/execute-payments") {
-                val (paymentRowId, painDoc, subscriber) = transaction {
-                    val entity = Pain001Entity.find {
-                        (Pain001Table.submitted eq false) and 
(Pain001Table.invalid eq false)
-                    }.firstOrNull() ?: throw 
NexusError(HttpStatusCode.Accepted, reason = "No ready payments found")
-                    Triple(entity.id, createPain001document(entity), 
entity.nexusUser.ebicsSubscriber)
-                }
-                if (subscriber == null) {
+                // 2 check if was submitted yet
+                if (preparedPayment.submitted) {
                     throw NexusError(
-                        HttpStatusCode.NotFound,
-                        "Ebics subscriber wasn't found for this prepared 
payment."
-                    )
-                }
-                logger.debug("Uploading PAIN.001: ${painDoc}")
-                doEbicsUploadTransaction(
-                    client,
-                    getSubscriberDetailsInternal(subscriber),
-                    "CCT",
-                    painDoc.toByteArray(Charsets.UTF_8),
-                    EbicsStandardOrderParams()
-                )
-                /* flow here == no errors occurred */
-                transaction {
-                    val payment = Pain001Entity.findById(paymentRowId) ?: 
throw NexusError(
-                        HttpStatusCode.InternalServerError,
-                        "Severe internal error: could not find payment in DB 
after having submitted it to the bank"
+                        HttpStatusCode.PreconditionFailed,
+                        "Payment ${body.uuid} was submitted already"
                     )
-                    payment.submitted = true
                 }
-                call.respondText(
-                    "CCT message submitted to the bank",
-                    ContentType.Text.Plain,
-                    HttpStatusCode.OK
-                )
-                return@post
-            }
-            /** exports keys backup copy */
-            post("/ebics/subscribers/{id}/backup") {
-                val body = call.receive<EbicsBackupRequestJson>()
-                val response = transaction {
-                    val nexusUser = extractNexusUser(call.parameters["id"])
-                    val subscriber = getEbicsSubscriberFromUser(nexusUser)
-                    EbicsKeysBackupJson(
-                        userID = subscriber.userID,
-                        hostID = subscriber.hostID,
-                        partnerID = subscriber.partnerID,
-                        ebicsURL = subscriber.ebicsURL,
-                        authBlob = bytesToBase64(
-                            CryptoUtil.encryptKey(
-                                
subscriber.authenticationPrivateKey.toByteArray(),
-                                body.passphrase
-                            )
-                        ),
-                        encBlob = bytesToBase64(
-                            CryptoUtil.encryptKey(
-                                subscriber.encryptionPrivateKey.toByteArray(),
-                                body.passphrase
-                            )
-                        ),
-                        sigBlob = bytesToBase64(
-                            CryptoUtil.encryptKey(
-                                subscriber.signaturePrivateKey.toByteArray(),
-                                body.passphrase
-                            )
-                        )
-                    )
-                }
-                call.response.headers.append("Content-Disposition", 
"attachment")
-                call.respond(
-                    HttpStatusCode.OK,
-                    response
-                )
-            }
-            /** Download keys from bank */
-            post("/ebics/subscribers/{id}/sync") {
-                val nexusUser = extractNexusUser(call.parameters["id"])
-                val subscriberDetails = 
getSubscriberDetailsFromNexusUserId(nexusUser.id.value)
-                val hpbRequest = makeEbicsHpbRequest(subscriberDetails)
-                val responseStr = 
client.postToBank(subscriberDetails.ebicsUrl, hpbRequest)
-                val response = 
parseAndDecryptEbicsKeyManagementResponse(subscriberDetails, responseStr)
-                val orderData = response.orderData ?: throw NexusError(
-                    HttpStatusCode.InternalServerError,
-                    "HPB response has no order data"
-                )
-                val hpbData = parseEbicsHpbOrder(orderData)
-                // put bank's keys into database.
-                transaction {
-                    val ebicsSubscriber = getEbicsSubscriberFromUser(nexusUser)
-                    ebicsSubscriber.bankAuthenticationPublicKey = 
SerialBlob(hpbData.authenticationPubKey.encoded)
-                    ebicsSubscriber.bankEncryptionPublicKey = 
SerialBlob(hpbData.encryptionPubKey.encoded)
-                }
-                call.respondText("Bank keys stored in database\n", 
ContentType.Text.Plain, HttpStatusCode.OK)
-                return@post
-            }
-            post("/ebics/subscribers/{id}/fetch-payment-status") {
-                val id = expectId(call.parameters["id"])
-                val paramsJson = call.receive<EbicsStandardOrderParamsJson>()
-                val orderParams = paramsJson.toOrderParams()
-                val subscriberData = getSubscriberDetailsFromNexusUserId(id)
-                val response = doEbicsDownloadTransaction(
-                    client,
-                    subscriberData,
-                    "CRZ",
-                    orderParams
-                )
-                when (response) {
-                    is EbicsDownloadSuccessResult ->
-                        call.respondText(
-                            response.orderData.toString(Charsets.UTF_8),
-                            ContentType.Text.Plain,
-                            HttpStatusCode.OK
+
+                // 3 submit
+                val pain001document = createPain001document(preparedPayment)
+
+                // 4 check if the user has a instance in such bank transport.
+                when (body.transport) {
+                    "ebics" -> {
+                        val subscriberDetails = 
getSubscriberDetailsFromNexusUserId(userId)
+                        logger.debug("Uploading PAIN.001: ${pain001document}")
+                        doEbicsUploadTransaction(
+                            client,
+                            subscriberDetails,
+                            "CCT",
+                            pain001document.toByteArray(Charsets.UTF_8),
+                            EbicsStandardOrderParams()
                         )
-                    /**
-                     * NOTE: flow gets here when the bank-technical return 
code is
-                     * different from 000000.  This happens also for 090005 
(no data available)
-                     */
-                    else -> call.respond(NexusErrorJson("Could not download 
any PAIN.002"))
-                }
-                return@post
-            }
-            post("/ebics/subscribers/{id}/collect-transactions-c53") {
-                val id = expectId(call.parameters["id"])
-                val paramsJson = call.receive<EbicsStandardOrderParamsJson>()
-                val orderParams = paramsJson.toOrderParams()
-                val subscriberData = getSubscriberDetailsFromNexusUserId(id)
-                when (val response = doEbicsDownloadTransaction(client, 
subscriberData, "C53", orderParams)) {
-                    is EbicsDownloadSuccessResult -> {
-                        /**
-                         * The current code is _heavily_ dependent on the way 
GLS returns
-                         * data.  For example, GLS makes one ZIP entry for 
each "Ntry" element
-                         * (a bank transfer), but per the specifications one 
bank can choose to
-                         * return all the "Ntry" elements into one single ZIP 
entry, or even unzipped
-                         * at all.
-                         */
-                        response.orderData.unzipWithLambda {
-                            logger.debug("C53 entry: ${it.second}")
-                            val fileName = it.first
-                            val camt53doc = 
XMLUtil.parseStringIntoDom(it.second)
-                            transaction {
-                                RawBankTransactionEntity.new {
-                                    sourceFileName = fileName
-                                    unstructuredRemittanceInformation = 
camt53doc.pickString("//*[local-name()='Ntry']//*[local-name()='Ustrd']")
-                                    transactionType = 
camt53doc.pickString("//*[local-name()='Ntry']//*[local-name()='CdtDbtInd']")
-                                    currency = 
camt53doc.pickString("//*[local-name()='Ntry']//*[local-name()='Amt']/@Ccy")
-                                    amount = 
camt53doc.pickString("//*[local-name()='Ntry']//*[local-name()='Amt']")
-                                    status = 
camt53doc.pickString("//*[local-name()='Ntry']//*[local-name()='Sts']")
-                                    bookingDate = 
parseDashedDate(camt53doc.pickString("//*[local-name()='BookgDt']//*[local-name()='Dt']")).millis
-                                    nexusUser = extractNexusUser(id)
-                                    creditorName = 
camt53doc.pickString("//*[local-name()='RltdPties']//*[local-name()='Dbtr']//*[local-name()='Nm']")
-                                    creditorIban = 
camt53doc.pickString("//*[local-name()='CdtrAcct']//*[local-name()='IBAN']")
-                                    debitorName = 
camt53doc.pickString("//*[local-name()='RltdPties']//*[local-name()='Dbtr']//*[local-name()='Nm']")
-                                    debitorIban = 
camt53doc.pickString("//*[local-name()='DbtrAcct']//*[local-name()='IBAN']")
-                                    counterpartBic = 
camt53doc.pickString("//*[local-name()='RltdAgts']//*[local-name()='BIC']")
-                                }
-                            }
+                        /** mark payment as 'submitted' */
+                        transaction {
+                            val payment = Pain001Entity.findById(body.uuid) ?: 
throw NexusError(
+                                HttpStatusCode.InternalServerError,
+                                "Severe internal error: could not find payment 
in DB after having submitted it to the bank"
+                            )
+                            payment.submitted = true
                         }
                         call.respondText(
-                            "C53 data persisted into the database (WIP).",
+                            "CCT message submitted to the bank",
                             ContentType.Text.Plain,
                             HttpStatusCode.OK
                         )
                     }
-                    is EbicsDownloadBankErrorResult -> {
-                        call.respond(
-                            HttpStatusCode.BadGateway,
-                            EbicsErrorJson(EbicsErrorDetailJson("bankError", 
response.returnCode.errorCode))
-                        )
-                    }
+                    else -> throw NexusError(
+                        HttpStatusCode.NotImplemented,
+                        "Bank transport ${body.transport} is not implemented"
+                    )
                 }
                 return@post
             }
-            post("/ebics/subscribers/{id}/collect-transactions-c54") {
-                // FIXME(florian): Download C54 and store the result in the 
right database table
+            /**
+             * Shows information about one particular prepared payment.
+             */
+            get("/bank-accounts/{accountid}/prepared-payments/{uuid}") {
+                return@get
             }
             /**
-             * This endpoint downloads bank account information associated 
with the
-             * calling EBICS subscriber.
+             * Adds a new prepared payment.
              */
-            post("/ebics/subscribers/{id}/fetch-accounts") {
-                val nexusUser = extractNexusUser((call.parameters["id"]))
-                val paramsJson = call.receive<EbicsStandardOrderParamsJson>()
-                val orderParams = paramsJson.toOrderParams()
-                val subscriberData = 
getSubscriberDetailsFromNexusUserId(nexusUser.id.value)
-                val response = doEbicsDownloadTransaction(client, 
subscriberData, "HTD", orderParams)
-                when (response) {
-                    is EbicsDownloadSuccessResult -> {
-                        val payload = 
XMLUtil.convertStringToJaxb<HTDResponseOrderData>(response.orderData.toString(Charsets.UTF_8))
-                        transaction {
-                            payload.value.partnerInfo.accountInfoList?.forEach 
{
-                                val bankAccount = BankAccountEntity.new(id = 
it.id) {
-                                    accountHolder = it.accountHolder
-                                    iban = 
extractFirstIban(it.accountNumberList) ?: throw 
NexusError(HttpStatusCode.NotFound, reason = "bank gave no IBAN")
-                                    bankCode = 
extractFirstBic(it.bankCodeList) ?: throw NexusError(HttpStatusCode.NotFound, 
reason = "bank gave no BIC")
-                                }
-                                BankAccountMapEntity.new {
-                                    ebicsSubscriber = 
getEbicsSubscriberFromUser(nexusUser)
-                                    this.nexusUser = nexusUser
-                                    this.bankAccount = bankAccount
-                                }
-                            }
-
-                        }
-                        call.respondText(
-                            response.orderData.toString(Charsets.UTF_8),
-                            ContentType.Text.Plain,
-                            HttpStatusCode.OK
-                        )
-                    }
-                    is EbicsDownloadBankErrorResult -> {
-                        call.respond(
-                            HttpStatusCode.BadGateway,
-                            EbicsErrorJson(EbicsErrorDetailJson("bankError", 
response.returnCode.errorCode))
-                        )
-                    }
-                }
+            post("/bank-accounts/{accountid}/prepared-payments") {
                 return@post
             }
-
-            /** EBICS MESSAGES / DEBUG */
-
-            // FIXME: some messages include a ZIPped payload.
-            post("/ebics/subscribers/{id}/send{MSG}") {
-                val id = expectId(call.parameters["id"])
-                val MSG = expectId(call.parameters["MSG"])
-                val paramsJson = call.receive<EbicsStandardOrderParamsJson>()
-                val orderParams = paramsJson.toOrderParams()
-                println("$MSG order params: $orderParams")
-                val subscriberData = getSubscriberDetailsFromNexusUserId(id)
-                val response = doEbicsDownloadTransaction(
-                    client,
-                    subscriberData,
-                    MSG,
-                    orderParams
-                )
-                when (response) {
-                    is EbicsDownloadSuccessResult -> {
-                        call.respondText(
-                            response.orderData.toString(Charsets.UTF_8),
-                            ContentType.Text.Plain,
-                            HttpStatusCode.OK
-                        )
-                    }
-                    is EbicsDownloadBankErrorResult -> {
-                        call.respond(
-                            HttpStatusCode.BadGateway,
-                            EbicsErrorJson(EbicsErrorDetailJson("bankError", 
response.returnCode.errorCode))
-                        )
-                    }
-                }
+            /**
+             * Downloads new transactions from the bank.
+             */
+            post("/bank-accounts/{accountid}/collected-transactions") {
                 return@post
             }
-            get("/ebics/{id}/sendHEV") {
-                val id = expectId(call.parameters["id"])
-                val subscriberData = getSubscriberDetailsFromNexusUserId(id)
-                val request = makeEbicsHEVRequest(subscriberData)
-                val response = client.postToBank(subscriberData.ebicsUrl, 
request)
-                val versionDetails = parseEbicsHEVResponse(response)
-                call.respond(
-                    HttpStatusCode.OK,
-                    EbicsHevResponseJson(versionDetails.versions.map { 
ebicsVersionSpec ->
-                        ProtocolAndVersionJson(
-                            ebicsVersionSpec.protocol,
-                            ebicsVersionSpec.version
-                        )
-                    })
-                )
+            /**
+             * Queries list of transactions ALREADY downloaded from the bank.
+             */
+            get("/bank-accounts/{accountid}/collected-transactions") {
                 return@get
             }
-            post("/ebics/subscribers/{id}/sendINI") {
-                val id = expectId(call.parameters["id"])
-                val subscriberData = getSubscriberDetailsFromNexusUserId(id)
-                val iniRequest = makeEbicsIniRequest(subscriberData)
-                val responseStr = client.postToBank(
-                    subscriberData.ebicsUrl,
-                    iniRequest
-                )
-                val resp = 
parseAndDecryptEbicsKeyManagementResponse(subscriberData, responseStr)
-                if (resp.technicalReturnCode != EbicsReturnCode.EBICS_OK) {
-                    throw 
NexusError(HttpStatusCode.InternalServerError,"Unexpected INI response code: 
${resp.technicalReturnCode}")
-                }
-                call.respondText(
-                    "Bank accepted signature key\n",
-                    ContentType.Text.Plain, HttpStatusCode.OK
-                )
+            /**
+             * Adds a new bank transport.
+             */
+            post("/bank-transports") {
                 return@post
             }
-
-            post("/ebics/subscribers/{id}/sendHIA") {
-                val id = expectId(call.parameters["id"])
-                val subscriberData = getSubscriberDetailsFromNexusUserId(id)
-                val hiaRequest = makeEbicsHiaRequest(subscriberData)
-                val responseStr = client.postToBank(
-                    subscriberData.ebicsUrl,
-                    hiaRequest
-                )
-                val resp = 
parseAndDecryptEbicsKeyManagementResponse(subscriberData, responseStr)
-                if (resp.technicalReturnCode != EbicsReturnCode.EBICS_OK) {
-                    throw 
NexusError(HttpStatusCode.InternalServerError,"Unexpected HIA response code: 
${resp.technicalReturnCode}")
-                }
-                call.respondText(
-                    "Bank accepted authentication and encryption keys\n",
-                    ContentType.Text.Plain,
-                    HttpStatusCode.OK
-                )
+            /**
+             * Sends to the bank a message "MSG" according to the transport
+             * "transportName".  Does not alterate any DB table.
+             */
+            post("/bank-transports/{transportName}/send{MSG}") {
                 return@post
             }
-
-            /** PLUGINS */
-            /* Taler class will initialize all the relevant handlers.  */
-            Taler(this)
+            /**
+             * Sends the bank a message "MSG" according to the transport
+             * "transportName".  DOES alterate DB tables.
+             */
+            post("/bank-transports/{transportName}/sync{MSG}") {
+                return@post
+            }
+            /**
+             * Hello endpoint.
+             */
+            get("/") {
+                call.respondText("Hello by nexus!\n")
+                return@get
+            }
         }
     }
     logger.info("Up and running")
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/Main2.kt 
b/nexus/src/main/kotlin/tech/libeufin/nexus/Main2.kt
deleted file mode 100644
index e5d6cfe..0000000
--- a/nexus/src/main/kotlin/tech/libeufin/nexus/Main2.kt
+++ /dev/null
@@ -1,181 +0,0 @@
-package tech.libeufin.nexus
-
-/*
- * This file is part of LibEuFin.
- * Copyright (C) 2019 Stanisci and Dold.
-
- * LibEuFin is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation; either version 3, or
- * (at your option) any later version.
-
- * LibEuFin is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero General
- * Public License for more details.
-
- * You should have received a copy of the GNU Affero General Public
- * License along with LibEuFin; see the file COPYING.  If not, see
- * <http://www.gnu.org/licenses/>
- */
-
-import io.ktor.application.ApplicationCallPipeline
-import io.ktor.application.call
-import io.ktor.application.install
-import io.ktor.client.HttpClient
-import io.ktor.features.*
-import io.ktor.gson.gson
-import io.ktor.http.ContentType
-import io.ktor.http.HttpStatusCode
-import io.ktor.request.ApplicationReceivePipeline
-import io.ktor.request.ApplicationReceiveRequest
-import io.ktor.request.receive
-import io.ktor.request.uri
-import io.ktor.response.respond
-import io.ktor.response.respondText
-import io.ktor.routing.get
-import io.ktor.routing.post
-import io.ktor.routing.routing
-import io.ktor.server.engine.embeddedServer
-import io.ktor.server.netty.Netty
-import io.ktor.util.KtorExperimentalAPI
-import kotlinx.coroutines.io.ByteReadChannel
-import kotlinx.coroutines.io.jvm.javaio.toByteReadChannel
-import kotlinx.coroutines.io.jvm.javaio.toInputStream
-import kotlinx.io.core.ExperimentalIoApi
-import org.jetbrains.exposed.sql.and
-import org.jetbrains.exposed.sql.transactions.transaction
-import org.joda.time.DateTime
-import org.slf4j.Logger
-import org.slf4j.LoggerFactory
-import org.slf4j.event.Level
-import tech.libeufin.util.*
-import tech.libeufin.util.ebics_h004.HTDResponseOrderData
-import java.text.DateFormat
-import java.text.SimpleDateFormat
-import java.util.*
-import java.util.zip.InflaterInputStream
-import javax.crypto.EncryptedPrivateKeyInfo
-import javax.sql.rowset.serial.SerialBlob
-
-
-data class NexusError(val statusCode: HttpStatusCode, val reason: String) : 
Exception()
-
-val logger: Logger = LoggerFactory.getLogger("tech.libeufin.nexus")
-
-fun isProduction(): Boolean {
-    return System.getenv("NEXUS_PRODUCTION") != null
-}
-
-@ExperimentalIoApi
-@KtorExperimentalAPI
-fun main() {
-    dbCreateTables()
-    val client = HttpClient() {
-        expectSuccess = false // this way, it does not throw exceptions on != 
200 responses.
-    }
-    val server = embeddedServer(Netty, port = 5001) {
-
-        install(CallLogging) {
-            this.level = Level.DEBUG
-            this.logger = tech.libeufin.nexus.logger
-        }
-        install(ContentNegotiation) {
-            gson {
-                setDateFormat(DateFormat.LONG)
-                setPrettyPrinting()
-            }
-        }
-        install(StatusPages) {
-            exception<NexusError> { cause ->
-                logger.error("Exception while handling '${call.request.uri}'", 
cause)
-                call.respondText(
-                    cause.reason,
-                    ContentType.Text.Plain,
-                    cause.statusCode
-                )
-            }
-            exception<UtilError> { cause ->
-                logger.error("Exception while handling '${call.request.uri}'", 
cause)
-                call.respondText(
-                    cause.reason,
-                    ContentType.Text.Plain,
-                    cause.statusCode
-                )
-            }
-            exception<Exception> { cause ->
-                logger.error("Uncaught exception while handling 
'${call.request.uri}'", cause)
-                logger.error(cause.toString())
-                call.respondText(
-                    "Internal server error",
-                    ContentType.Text.Plain,
-                    HttpStatusCode.InternalServerError
-                )
-            }
-        }
-
-        intercept(ApplicationCallPipeline.Fallback) {
-            if (this.call.response.status() == null) {
-                call.respondText("Not found (no route matched).\n", 
ContentType.Text.Plain, HttpStatusCode.NotFound)
-                return@intercept finish()
-            }
-        }
-
-        receivePipeline.intercept(ApplicationReceivePipeline.Before) {
-            if (this.context.request.headers["Content-Encoding"] == "deflate") 
{
-                logger.debug("About to inflate received data")
-                val deflated = this.subject.value as ByteReadChannel
-                val inflated = InflaterInputStream(deflated.toInputStream())
-                proceedWith(ApplicationReceiveRequest(this.subject.typeInfo, 
inflated.toByteReadChannel()))
-                return@intercept
-            }
-            proceed()
-            return@intercept
-        }
-
-        routing {
-
-            /** GENERAL / DEBUG ENDPOINTS */
-
-            get("/") {
-                call.respondText("Hello by nexus!\n")
-                return@get
-            }
-            get("/user") {
-                return@get
-            }
-            post("/users") {
-                return@post
-            }
-            get("/bank-accounts") {
-                return@get
-            }
-            post("/bank-accounts/{accountid}/prepared-payments/submit") {
-                return@post
-            }
-            get("/bank-accounts/{accountid}/prepared-payments/{uuid}") {
-                return@get
-            }
-            post("/bank-accounts/{accountid}/prepared-payments") {
-                return@post
-            }
-            post("/bank-accounts/{accountid}/collected-transactions") {
-                return@post
-            }
-            get("/bank-accounts/{accountid}/collected-transactions") {
-                return@post
-            }
-            post("/bank-transports") {
-                return@post
-            }
-            post("/bank-transports/{transportName}/send{MSG}") {
-                return@post
-            }
-            post("/bank-transports/{transportName}/sync{MSG}") {
-                return@post
-            }
-        }
-        logger.info("Up and running")
-        server.start(wait = true)
-    }
-}
\ 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/MainDeprecated.kt
similarity index 99%
copy from nexus/src/main/kotlin/tech/libeufin/nexus/Main.kt
copy to nexus/src/main/kotlin/tech/libeufin/nexus/MainDeprecated.kt
index e0ae928..547f0b2 100644
--- a/nexus/src/main/kotlin/tech/libeufin/nexus/Main.kt
+++ b/nexus/src/main/kotlin/tech/libeufin/nexus/MainDeprecated.kt
@@ -58,15 +58,6 @@ import java.util.zip.InflaterInputStream
 import javax.crypto.EncryptedPrivateKeyInfo
 import javax.sql.rowset.serial.SerialBlob
 
-
-data class NexusError(val statusCode: HttpStatusCode, val reason: String) : 
Exception()
-
-val logger: Logger = LoggerFactory.getLogger("tech.libeufin.nexus")
-
-fun isProduction(): Boolean {
-    return System.getenv("NEXUS_PRODUCTION") != null
-}
-
 @ExperimentalIoApi
 @KtorExperimentalAPI
 fun main() {
diff --git a/util/src/main/kotlin/DBTypes.kt b/util/src/main/kotlin/DBTypes.kt
index c564e29..f86b70b 100644
--- a/util/src/main/kotlin/DBTypes.kt
+++ b/util/src/main/kotlin/DBTypes.kt
@@ -1,8 +1,10 @@
 package tech.libeufin.util
 
+import org.jetbrains.exposed.dao.IdTable
 import org.jetbrains.exposed.dao.IntIdTable
 import org.jetbrains.exposed.sql.Column
 import org.jetbrains.exposed.sql.ColumnType
+import org.jetbrains.exposed.sql.Table
 import java.math.BigDecimal
 import java.math.RoundingMode
 
@@ -15,15 +17,10 @@ class BadAmount(badValue: Any?) : Exception("Value 
'${badValue}' is not a valid
  */
 typealias Amount = BigDecimal
 
-open class IntIdTableWithAmount : IntIdTable() {
-
-    class AmountColumnType : ColumnType() {
-        override fun sqlType(): String  = "DECIMAL(${NUMBER_MAX_DIGITS}, 
${SCALE_TWO})"
-
+class AmountColumnType : ColumnType() {
+    override fun sqlType(): String  = "DECIMAL(${NUMBER_MAX_DIGITS}, 
${SCALE_TWO})"
         override fun valueFromDB(value: Any): Any {
-
             val valueFromDB = super.valueFromDB(value)
-
             try {
                 return when (valueFromDB) {
                     is BigDecimal -> valueFromDB.setScale(SCALE_TWO, 
RoundingMode.UNNECESSARY)
@@ -55,13 +52,12 @@ open class IntIdTableWithAmount : IntIdTable() {
             }
             return super.valueToDB(value)
         }
-    }
+}
 
-    /**
-     * Make sure the number entered by upper layers does not need any rounding
-     * to conform to scale == 2
-     */
-    fun amount(name: String): Column<Amount> {
-        return registerColumn(name, AmountColumnType())
-    }
+/**
+ * Make sure the number entered by upper layers does not need any rounding
+ * to conform to scale == 2
+ */
+fun IdTable<*>.amount(name: String): Column<Amount> {
+    return registerColumn(name, AmountColumnType())
 }
\ No newline at end of file

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



reply via email to

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