commit 7bbfbcb64e05315f4cbd70c361df63faf95a9275
parent cf3fbbcd2b029dac65d628c1ae6654faafaa32f4
Author: Antoine A <>
Date: Thu, 12 Oct 2023 14:58:14 +0000
Simpler and stricter amount parser
Diffstat:
2 files changed, 22 insertions(+), 25 deletions(-)
diff --git a/bank/src/main/kotlin/tech/libeufin/bank/TalerCommon.kt b/bank/src/main/kotlin/tech/libeufin/bank/TalerCommon.kt
@@ -235,26 +235,20 @@ class TalerAmount {
constructor(encoded: String) {
fun badAmount(hint: String): Exception =
badRequest(hint, TalerErrorCode.TALER_EC_BANK_BAD_FORMAT_AMOUNT)
-
- if (encoded.isEmpty()) throw badAmount("Empty amount")
- val currencySplit: List<String> = encoded.split(':', limit = 2)
- if (currencySplit.size != 2) throw badAmount("Missing value")
- currency = currencySplit[0].trimStart()
- if (currency.length > 12) throw badAmount("Currency too big")
- val dotSplit: List<String> = currencySplit[1].split('.', limit = 2)
-
- value = dotSplit[0].toLongOrNull() ?: throw badAmount("Invalid value")
- if (value > MAX_SAFE_INTEGER) throw badAmount("Value specified in amount is too large")
-
- if (dotSplit.size == 2) {
- if (dotSplit[1].length > 8) throw badAmount("Fractional value too precise")
- var tmp: Int = dotSplit[1].toIntOrNull() ?: throw badAmount("Invalid fractional value")
- repeat(8 - dotSplit[1].length) {
+
+ val match = PATTERN.matchEntire(encoded) ?: throw badAmount("Invalid amount format");
+ val (currency, value, frac) = match.destructured
+ this.currency = currency
+ this.value = value.toLongOrNull() ?: throw badAmount("Invalid value")
+ if (this.value > MAX_SAFE_INTEGER) throw badAmount("Value specified in amount is too large")
+ this.frac = if (frac.isEmpty()) {
+ 0
+ } else {
+ var tmp = frac.toIntOrNull() ?: throw badAmount("Invalid fractional value")
+ repeat(8 - frac.length) {
tmp *= 10
}
- frac = tmp
- } else {
- frac = 0
+ tmp
}
}
@@ -314,6 +308,7 @@ class TalerAmount {
companion object {
const val FRACTION_BASE = 100000000
+ private val PATTERN = Regex("([A-Z]{1,11}):([0-9]+)(?:\\.([0-9]{0,8}))?");
}
}
diff --git a/bank/src/test/kotlin/AmountTest.kt b/bank/src/test/kotlin/AmountTest.kt
@@ -75,18 +75,20 @@ class AmountTest {
fun parseValid() {
assertEquals(TalerAmount("EUR:4"), TalerAmount(4L, 0, "EUR"))
assertEquals(TalerAmount("EUR:0.02"), TalerAmount(0L, 2000000, "EUR"))
- assertEquals(TalerAmount(" EUR:4.12"), TalerAmount(4L, 12000000, "EUR"))
- assertEquals(TalerAmount(" *LOCAL:4444.1000"), TalerAmount(4444L, 10000000, "*LOCAL"))
+ assertEquals(TalerAmount("EUR:4.12"), TalerAmount(4L, 12000000, "EUR"))
+ assertEquals(TalerAmount("LOCAL:4444.1000"), TalerAmount(4444L, 10000000, "LOCAL"))
}
@Test
fun parseInvalid() {
- assertException("Empty amount") {TalerAmount("")}
- assertException("Missing value") {TalerAmount("EUR")}
- assertException("Currency too big") {TalerAmount("AZERTYUIOPQSD:")}
+ assertException("Invalid amount format") {TalerAmount("")}
+ assertException("Invalid amount format") {TalerAmount("EUR")}
+ assertException("Invalid amount format") {TalerAmount("eur:12")}
+ assertException("Invalid amount format") {TalerAmount(" EUR:12")}
+ assertException("Invalid amount format") {TalerAmount("AZERTYUIOPQSD:12")}
assertException("Value specified in amount is too large") {TalerAmount("EUR:${Long.MAX_VALUE}")}
- assertException("Fractional value too precise") {TalerAmount("EUR:4.000000000")}
- assertException("Invalid fractional value") {TalerAmount("EUR:4.4a")}
+ assertException("Invalid amount format") {TalerAmount("EUR:4.000000000")}
+ assertException("Invalid amount format") {TalerAmount("EUR:4.4a")}
}
@Test