libeufin

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

commit 695c23c2b1a9ee05409fff3d74621393edce042b
parent d8756b27578ed67573f261467edd8d45128cda9a
Author: ms <ms@taler.net>
Date:   Sat,  7 Aug 2021 15:30:49 +0200

Sanity checks for strings representing amounts.

Diffstat:
Msandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt | 14+++++++++++++-
Msandbox/src/main/kotlin/tech/libeufin/sandbox/bankAccount.kt | 5+++--
Msandbox/src/test/kotlin/BalanceTest.kt | 23+++++++++++++++++++++++
Mutil/src/main/kotlin/Errors.kt | 4++++
Mutil/src/main/kotlin/strings.kt | 11+++++++++++
5 files changed, 54 insertions(+), 3 deletions(-)

diff --git a/sandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt b/sandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt @@ -17,9 +17,9 @@ * <http://www.gnu.org/licenses/> */ - package tech.libeufin.sandbox +import UtilError import com.hubspot.jinjava.Jinjava import com.fasterxml.jackson.core.JsonParseException import io.ktor.application.ApplicationCallPipeline @@ -324,6 +324,18 @@ fun serverMain(dbName: String, port: Int) { ) ) } + exception<UtilError> { cause -> + logger.error("Exception while handling '${call.request.uri}'", cause) + call.respond( + cause.statusCode, + SandboxErrorJson( + error = SandboxErrorDetailJson( + type = "util-error", + description = cause.reason + ) + ) + ) + } exception<Throwable> { cause -> logger.error("Exception while handling '${call.request.uri}'", cause) call.respondText("Internal server error.", ContentType.Text.Plain, HttpStatusCode.InternalServerError) diff --git a/sandbox/src/main/kotlin/tech/libeufin/sandbox/bankAccount.kt b/sandbox/src/main/kotlin/tech/libeufin/sandbox/bankAccount.kt @@ -8,6 +8,7 @@ import org.slf4j.LoggerFactory import tech.libeufin.sandbox.BankAccountTransactionsTable.amount import tech.libeufin.util.RawPayment import tech.libeufin.util.importDateFromMillis +import tech.libeufin.util.parseDecimal import tech.libeufin.util.toDashedDate private val logger: Logger = LoggerFactory.getLogger("tech.libeufin.sandbox") @@ -19,13 +20,13 @@ fun balanceForAccount(iban: String): java.math.BigDecimal { BankAccountTransactionsTable.select { BankAccountTransactionsTable.creditorIban eq iban }.forEach { - val amount = java.math.BigDecimal(it[amount]) + val amount = parseDecimal(it[amount]) balance += amount } BankAccountTransactionsTable.select { BankAccountTransactionsTable.debtorIban eq iban }.forEach { - val amount = java.math.BigDecimal(it[amount]) + val amount = parseDecimal(it[amount]) balance -= amount } } diff --git a/sandbox/src/test/kotlin/BalanceTest.kt b/sandbox/src/test/kotlin/BalanceTest.kt @@ -65,7 +65,30 @@ class BalanceTest { it[direction] = "DBIT" it[accountServicerReference] = "test-account-servicer-reference" } + BankAccountTransactionsTable.insert { + it[account] = EntityID(0, BankAccountsTable) + it[creditorIban] = "other" + it[creditorBic] = "BIC" + it[creditorName] = "Creditor Name" + it[debtorIban] = "earns-bad-amount" + it[debtorBic] = "BIC" + it[debtorName] = "Debitor Name" + it[subject] = "deal" + it[amount] = "not a number" + it[date] = LocalDateTime.now().millis() + it[currency] = "EUR" + it[pmtInfId] = "0" + it[direction] = "DBIT" + it[accountServicerReference] = "test-account-servicer-reference" + } assert(java.math.BigDecimal.ONE == balanceForAccount("earns")) + try { + balanceForAccount("earns-bad-amount") + } catch (e: UtilError) { + return@transaction + } + // here the expected exception wasn't thrown. + assert(false) } } } diff --git a/util/src/main/kotlin/Errors.kt b/util/src/main/kotlin/Errors.kt @@ -1,3 +1,4 @@ +import io.ktor.http.* import kotlin.system.exitProcess /* @@ -19,6 +20,9 @@ import kotlin.system.exitProcess * <http://www.gnu.org/licenses/> */ +data class UtilError(val statusCode: HttpStatusCode, val reason: String) : + Exception("$reason (HTTP status $statusCode)") + /** * Helper function that wraps throwable code and * (1) prints the error message and (2) terminates diff --git a/util/src/main/kotlin/strings.kt b/util/src/main/kotlin/strings.kt @@ -19,8 +19,10 @@ package tech.libeufin.util +import UtilError import io.ktor.http.HttpStatusCode import java.math.BigInteger +import java.math.BigDecimal import java.util.* fun ByteArray.toHexString() : String { @@ -61,6 +63,7 @@ fun base64ToBytes(encoding: String): ByteArray { return Base64.getDecoder().decode(encoding) } +// used mostly in RSA math, never as amount. fun BigInteger.toUnsignedHexString(): String { val signedValue = this.toByteArray() require(this.signum() > 0) { "number must be positive" } @@ -96,6 +99,14 @@ data class AmountWithCurrency( val amount: Amount ) +fun parseDecimal(decimalStr: String): BigDecimal { + return try { + BigDecimal(decimalStr) + } catch (e: NumberFormatException) { + throw UtilError(HttpStatusCode.BadRequest, "Bad string amount given: $decimalStr") + } +} + fun parseAmount(amount: String): AmountWithCurrency { val match = Regex("([A-Z]+):([0-9]+(\\.[0-9]+)?)").find(amount) ?: throw EbicsProtocolError(HttpStatusCode.BadRequest, "invalid amount: $amount")