libeufin

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

commit 7c2203541512c699ac622d50101cb01059d4569c
parent 4c5b0777547c726cde56b7979e116bcf96c994fd
Author: Marcello Stanisci <stanisci.m@gmail.com>
Date:   Mon,  6 Apr 2020 16:49:31 +0200

Move Taler logic in a dedicate file.

Diffstat:
Mnexus/src/main/kotlin/tech/libeufin/nexus/Main.kt | 92++++++++-----------------------------------------------------------------------
Anexus/src/main/kotlin/tech/libeufin/nexus/taler.kt | 98+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 107 insertions(+), 83 deletions(-)

diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/Main.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/Main.kt @@ -29,7 +29,6 @@ import io.ktor.features.StatusPages import io.ktor.gson.gson import io.ktor.http.ContentType import io.ktor.http.HttpStatusCode -import io.ktor.http.cio.websocket.CloseReason import io.ktor.request.receive import io.ktor.request.uri import io.ktor.response.respond @@ -39,10 +38,6 @@ import io.ktor.routing.post import io.ktor.routing.routing import io.ktor.server.engine.embeddedServer import io.ktor.server.netty.Netty -import net.taler.wallet.crypto.Base32Crockford -import org.apache.commons.compress.archivers.zip.ZipFile -import org.apache.commons.compress.utils.SeekableInMemoryByteChannel -import org.jetbrains.exposed.exceptions.ExposedSQLException import org.jetbrains.exposed.sql.StdOutSqlLogger import org.jetbrains.exposed.sql.addLogger import org.jetbrains.exposed.sql.and @@ -52,16 +47,12 @@ import org.slf4j.Logger import org.slf4j.LoggerFactory import org.slf4j.event.Level import tech.libeufin.util.* -import tech.libeufin.util.ebics_h004.EbicsRequest import tech.libeufin.util.ebics_h004.EbicsTypes -import tech.libeufin.util.ebics_h004.HKDResponseOrderData import tech.libeufin.util.ebics_h004.HTDResponseOrderData -import java.lang.StringBuilder import java.security.interfaces.RSAPublicKey import java.text.DateFormat import java.text.SimpleDateFormat import java.time.Instant -import java.time.LocalDate import java.time.ZoneId import java.time.ZonedDateTime import java.time.format.DateTimeFormatter @@ -94,7 +85,9 @@ val logger: Logger = LoggerFactory.getLogger("tech.libeufin.nexus") fun getSubscriberEntityFromId(id: String): EbicsSubscriberEntity { return transaction { - EbicsSubscriberEntity.findById(id) ?: throw NexusError(HttpStatusCode.NotFound, "Subscriber not found from id '$id'") + EbicsSubscriberEntity.findById(id) ?: throw NexusError( + HttpStatusCode.NotFound, "Subscriber not found from id '$id'" + ) } } @@ -145,7 +138,9 @@ fun getSubscriberDetailsFromBankAccount(bankAccountId: String): EbicsClientSubsc fun getSubscriberDetailsFromId(id: String): EbicsClientSubscriberDetails { return transaction { - val subscriber = EbicsSubscriberEntity.findById(id) ?: throw NexusError(HttpStatusCode.NotFound, "subscriber not found from id '$id'") + val subscriber = EbicsSubscriberEntity.findById(id) ?: throw NexusError( + HttpStatusCode.NotFound, "subscriber not found from id '$id'" + ) var bankAuthPubValue: RSAPublicKey? = null if (subscriber.bankAuthenticationPublicKey != null) { bankAuthPubValue = CryptoUtil.loadRsaPublicKey( @@ -624,79 +619,10 @@ fun main() { return@get } - post("/ebics/taler/{id}/accounts/{acctid}/refund-invalid-payments") { - transaction { - val subscriber = expectIdTransaction(call.parameters["id"]) - val acctid = expectAcctidTransaction(call.parameters["acctid"]) - if (acctid.subscriber.id != subscriber.id) { - throw NexusError( - HttpStatusCode.Forbidden, - "Such subscriber (${subscriber.id}) can't drive such account (${acctid.id})" - ) - } - TalerIncomingPaymentEntry.find { - TalerIncomingPayments.processed eq false and (TalerIncomingPayments.valid eq false) - }.forEach { - createPain001entry( - Pain001Data( - creditorName = it.payment.debitorName, - creditorIban = it.payment.debitorIban, - creditorBic = it.payment.counterpartBic, - sum = calculateRefund(it.payment.amount), - subject = "Taler refund" - ), - acctid.id.value - ) - it.processed = true - } - } - return@post - } - /** - * VERY taler-related behaviour, where the Nexus differentiates good - * incoming transactions (those with a valid subject, i.e. a public key), - * and invalid ones (the rest). - */ - post("/ebics/taler/{id}/digest-incoming-transactions") { - val id = expectId(call.parameters["id"]) - // first find highest ID value of already processed rows. - transaction { - // avoid re-processing raw payments - val latest = TalerIncomingPaymentEntry.all().sortedByDescending { - it.payment.id - }.firstOrNull() - val payments = if (latest == null) { - EbicsRawBankTransactionEntry.find { - EbicsRawBankTransactionsTable.nexusSubscriber eq id - } - } else { - EbicsRawBankTransactionEntry.find { - EbicsRawBankTransactionsTable.id.greater(latest.id) and - (EbicsRawBankTransactionsTable.nexusSubscriber eq id) - } - } - payments.forEach { - if (CryptoUtil.checkValidEddsaPublicKey(it.unstructuredRemittanceInformation)) { - TalerIncomingPaymentEntry.new { - payment = it - valid = true - } - } else { - TalerIncomingPaymentEntry.new { - payment = it - valid = false - } - } - } - } - call.respondText ( - "New raw payments Taler-processed", - ContentType.Text.Plain, - HttpStatusCode.OK - ) - return@post - } + /* Taler class will initialize all the relevant handlers. */ + Taler(this) + post("/ebics/subscribers/{id}/collect-transactions-c53") { val id = expectId(call.parameters["id"]) val paramsJson = call.receive<EbicsStandardOrderParamsJson>() diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/taler.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/taler.kt @@ -0,0 +1,97 @@ +package tech.libeufin.nexus + +import io.ktor.application.Application +import io.ktor.application.call +import io.ktor.http.ContentType +import io.ktor.http.HttpStatusCode +import io.ktor.response.respondText +import io.ktor.routing.Route +import io.ktor.routing.post +import org.jetbrains.exposed.sql.and +import org.jetbrains.exposed.sql.transactions.transaction +import tech.libeufin.util.CryptoUtil + +class Taler(app: Route) { + + init { + digest(app) + refund(app) + } + + fun digest(app: Route) { + app.post("/ebics/taler/{id}/digest-incoming-transactions") { + val id = expectId(call.parameters["id"]) + // first find highest ID value of already processed rows. + transaction { + // avoid re-processing raw payments + val latest = TalerIncomingPaymentEntry.all().sortedByDescending { + it.payment.id + }.firstOrNull() + + val payments = if (latest == null) { + EbicsRawBankTransactionEntry.find { + EbicsRawBankTransactionsTable.nexusSubscriber eq id + } + } else { + EbicsRawBankTransactionEntry.find { + EbicsRawBankTransactionsTable.id.greater(latest.id) and + (EbicsRawBankTransactionsTable.nexusSubscriber eq id) + } + } + payments.forEach { + if (CryptoUtil.checkValidEddsaPublicKey(it.unstructuredRemittanceInformation)) { + TalerIncomingPaymentEntry.new { + payment = it + valid = true + } + } else { + TalerIncomingPaymentEntry.new { + payment = it + valid = false + } + } + } + } + call.respondText ( + "New raw payments Taler-processed", + ContentType.Text.Plain, + HttpStatusCode.OK + ) + return@post + } + + + } + + fun refund(app: Route) { + + app.post("/ebics/taler/{id}/accounts/{acctid}/refund-invalid-payments") { + transaction { + val subscriber = expectIdTransaction(call.parameters["id"]) + val acctid = expectAcctidTransaction(call.parameters["acctid"]) + if (acctid.subscriber.id != subscriber.id) { + throw NexusError( + HttpStatusCode.Forbidden, + "Such subscriber (${subscriber.id}) can't drive such account (${acctid.id})" + ) + } + TalerIncomingPaymentEntry.find { + TalerIncomingPayments.processed eq false and (TalerIncomingPayments.valid eq false) + }.forEach { + createPain001entry( + Pain001Data( + creditorName = it.payment.debitorName, + creditorIban = it.payment.debitorIban, + creditorBic = it.payment.counterpartBic, + sum = calculateRefund(it.payment.amount), + subject = "Taler refund" + ), + acctid.id.value + ) + it.processed = true + } + } + return@post + } + } +} +\ No newline at end of file