summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Dold <florian@dold.me>2021-08-07 16:10:25 +0200
committerFlorian Dold <florian@dold.me>2021-08-07 16:10:35 +0200
commit05ddacd80641db9ebd00ba6bb20aa8200c8b76f8 (patch)
treef6830f6cb04ea55f127744ee29d2ef524216190d
parent695c23c2b1a9ee05409fff3d74621393edce042b (diff)
downloadlibeufin-05ddacd80641db9ebd00ba6bb20aa8200c8b76f8.tar.gz
libeufin-05ddacd80641db9ebd00ba6bb20aa8200c8b76f8.tar.bz2
libeufin-05ddacd80641db9ebd00ba6bb20aa8200c8b76f8.zip
check amount, catch exceptions when refunding
-rw-r--r--debian/changelog6
-rw-r--r--nexus/src/main/kotlin/tech/libeufin/nexus/DB.kt3
-rw-r--r--nexus/src/main/kotlin/tech/libeufin/nexus/Taler.kt25
-rw-r--r--nexus/src/main/kotlin/tech/libeufin/nexus/server/NexusServer.kt1
-rw-r--r--sandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt17
-rw-r--r--util/src/main/kotlin/amounts.kt28
6 files changed, 68 insertions, 12 deletions
diff --git a/debian/changelog b/debian/changelog
index 6cddc2e1..7666d599 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+libeufin (0.0.1-9) unstable; urgency=medium
+
+ * Various bugfixes.
+
+ -- Florian Dold <florian@dold.me> Sat, 07 Aug 2021 16:09:59 +0200
+
libeufin (0.0.1-8) unstable; urgency=medium
* Various bugfixes.
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/DB.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/DB.kt
index 75c5f880..8919024a 100644
--- a/nexus/src/main/kotlin/tech/libeufin/nexus/DB.kt
+++ b/nexus/src/main/kotlin/tech/libeufin/nexus/DB.kt
@@ -69,6 +69,9 @@ class TalerInvalidIncomingPaymentEntity(id: EntityID<Long>) : LongEntity(id) {
var payment by NexusBankTransactionEntity referencedOn TalerInvalidIncomingPaymentsTable.payment
var timestampMs by TalerInvalidIncomingPaymentsTable.timestampMs
+ // FIXME: This should probably not be called refunded, and
+ // we should have a foreign key to the payment that sends the
+ // money back.
var refunded by TalerInvalidIncomingPaymentsTable.refunded
}
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/Taler.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/Taler.kt
index 33f09651..33403da2 100644
--- a/nexus/src/main/kotlin/tech/libeufin/nexus/Taler.kt
+++ b/nexus/src/main/kotlin/tech/libeufin/nexus/Taler.kt
@@ -43,7 +43,9 @@ import tech.libeufin.util.*
import kotlin.math.abs
import kotlin.math.min
-/** Payment initiating data structures: one endpoint "$BASE_URL/transfer". */
+/**
+ * Request body for "$TWG_BASE_URL/transfer".
+ */
data class TalerTransferRequest(
val request_uid: String,
val amount: String,
@@ -94,7 +96,9 @@ data class GnunetTimestamp(
val t_ms: Long
)
-/** Sort query results in descending order for negative deltas, and ascending otherwise. */
+/**
+ * Sort query results in descending order for negative deltas, and ascending otherwise.
+ */
fun <T : Entity<Long>> SizedIterable<T>.orderTaler(delta: Int): List<T> {
return if (delta < 0) {
this.sortedByDescending { it.id }
@@ -165,7 +169,7 @@ fun customConverter(body: Any): String {
fun extractReservePubFromSubject(rawSubject: String): String? {
val re = "\\b[a-z0-9A-Z]{52}\\b".toRegex()
val result = re.find(rawSubject.replace("[\n]+".toRegex(), "")) ?: return null
- return result.value.toUpperCase()
+ return result.value.uppercase()
}
private fun getTalerFacadeState(fcid: String): TalerFacadeStateEntity {
@@ -185,7 +189,7 @@ private fun getTalerFacadeBankAccount(fcid: String): NexusBankAccountEntity {
val facadeState = getTalerFacadeState(fcid)
return NexusBankAccountEntity.findByName(facadeState.bankAccount) ?: throw NexusError(
HttpStatusCode.NotFound,
- "The facade: ${fcid} doesn't manage bank account: ${facadeState.bankAccount}"
+ "The facade: $fcid doesn't manage bank account: ${facadeState.bankAccount}"
)
}
@@ -356,7 +360,7 @@ fun maybePrepareRefunds(bankAccount: NexusBankAccountEntity, lastSeenId: Long) {
throw NexusError(HttpStatusCode.InternalServerError, "Unexpected void payment, cannot refund")
}
val debtorAccount = paymentData.batches[0].batchTransactions[0].details.debtorAccount
- if (debtorAccount == null || debtorAccount.iban == null) {
+ if (debtorAccount?.iban == null) {
logger.error("Could not find a IBAN to refund in transaction (AcctSvcrRef): ${paymentData.accountServicerRef}, aborting refund")
throw NexusError(HttpStatusCode.InternalServerError, "IBAN to refund not found")
}
@@ -441,7 +445,12 @@ fun ingestTalerTransactions(bankAccountId: String) {
}
lastId = it.id.value
}
- maybePrepareRefunds(bankAccount, facadeState.highestSeenMessageSerialId)
+ try {
+ // FIXME: This currently does not do proper error handing.
+ maybePrepareRefunds(bankAccount, facadeState.highestSeenMessageSerialId)
+ } catch (e: Exception) {
+ logger.warn("sending refund payment failed", e);
+ }
facadeState.highestSeenMessageSerialId = lastId
}
@@ -561,8 +570,8 @@ fun talerFacadeRoutes(route: Route, httpClient: HttpClient) {
route.get("/config") {
val facadeId = ensureNonNull(call.parameters["fcid"])
call.request.requirePermission(
- PermissionQuery("facade", facadeId, "facade.talerWireGateway.transfer"),
- PermissionQuery("facade", facadeId, "facade.talerWireGateway.history")
+ PermissionQuery("facade", facadeId, "facade.talerwiregateway.transfer"),
+ PermissionQuery("facade", facadeId, "facade.talerwiregateway.history")
)
call.respond(object {
val version = "0.0.0"
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/server/NexusServer.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/server/NexusServer.kt
index 3c20fbf1..4742d99b 100644
--- a/nexus/src/main/kotlin/tech/libeufin/nexus/server/NexusServer.kt
+++ b/nexus/src/main/kotlin/tech/libeufin/nexus/server/NexusServer.kt
@@ -29,7 +29,6 @@ import com.fasterxml.jackson.databind.exc.MismatchedInputException
import com.fasterxml.jackson.module.kotlin.KotlinModule
import com.fasterxml.jackson.module.kotlin.MissingKotlinParameterException
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
-import execThrowableOrTerminate
import io.ktor.application.*
import io.ktor.client.*
import io.ktor.features.*
diff --git a/sandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt b/sandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt
index 08a11535..9201fa38 100644
--- a/sandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt
+++ b/sandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt
@@ -89,6 +89,7 @@ import tech.libeufin.sandbox.BankAccountTransactionsTable.pmtInfId
import tech.libeufin.util.*
import tech.libeufin.util.ebics_h004.EbicsResponse
import tech.libeufin.util.ebics_h004.EbicsTypes
+import validatePlainAmount
import java.net.BindException
import java.util.*
import kotlin.random.Random
@@ -107,15 +108,16 @@ class Config : CliktCommand("Insert one configuration into the database") {
helpFormatter = CliktHelpFormatter(showDefaultValues = true)
}
}
+
private val hostnameOption by argument(
- "HOSTNAME", help="hostname that serves this configuration"
+ "HOSTNAME", help = "hostname that serves this configuration"
)
private val currencyOption by option("--currency").default("EUR")
private val bankDebtLimitOption by option("--bank-debt-limit").int().default(1000000)
private val usersDebtLimitOption by option("--users-debt-limit").int().default(1000)
private val allowRegistrationsOption by option(
"--allow-registrations",
- help="(default: true)" /* mentioning here as help message did not. */
+ help = "(default: true)" /* mentioning here as help message did not. */
).flag(default = true)
override fun run() {
@@ -141,6 +143,7 @@ class ResetTables : CliktCommand("Drop all the tables from the database") {
helpFormatter = CliktHelpFormatter(showDefaultValues = true)
}
}
+
override fun run() {
val dbConnString = getDbConnFromEnv(SANDBOX_DB_ENV_VAR_NAME)
execThrowableOrTerminate {
@@ -223,6 +226,7 @@ class SandboxCommand : CliktCommand(invokeWithoutSubcommand = true, printHelpOnE
init {
versionOption(getVersion())
}
+
override fun run() = Unit
}
@@ -369,7 +373,7 @@ fun serverMain(dbName: String, port: Int) {
transaction {
// check if username is taken.
- var maybeUser = SandboxUserEntity.find {
+ val maybeUser = SandboxUserEntity.find {
SandboxUsersTable.username eq username
}.firstOrNull()
// Will be converted to a HTML response.
@@ -434,6 +438,7 @@ fun serverMain(dbName: String, port: Int) {
val version = "0.0.0-dev.0"
})
}
+
// only reason for a post is to hide the iban (to some degree.)
post("/admin/payments/camt") {
val body = call.receiveJson<CamtParams>()
@@ -448,6 +453,12 @@ fun serverMain(dbName: String, port: Int) {
val body = call.receiveJson<IncomingPaymentInfo>()
// FIXME: generate nicer UUID!
val accountLabel = ensureNonNull(call.parameters["label"])
+ if (!validatePlainAmount(body.amount)) {
+ throw SandboxError(
+ HttpStatusCode.BadRequest,
+ "invalid amount (should be plain amount without currency)"
+ )
+ }
transaction {
val account = getBankAccountFromLabel(accountLabel)
val randId = getRandomString(16)
diff --git a/util/src/main/kotlin/amounts.kt b/util/src/main/kotlin/amounts.kt
new file mode 100644
index 00000000..04543f81
--- /dev/null
+++ b/util/src/main/kotlin/amounts.kt
@@ -0,0 +1,28 @@
+import io.ktor.http.*
+import tech.libeufin.util.AmountWithCurrency
+import tech.libeufin.util.EbicsProtocolError
+
+/*
+ * This file is part of LibEuFin.
+ * Copyright (C) 2021 Taler Systems S.A.
+ *
+ * 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/>
+ */
+
+val re = Regex("^([0-9]+(\\.[0-9]+)?)$")
+
+fun validatePlainAmount(plainAmount: String): Boolean {
+ return re.matches(plainAmount)
+}