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