[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[libeufin] branch master updated: Checking big amounts.
From: |
gnunet |
Subject: |
[libeufin] branch master updated: Checking big amounts. |
Date: |
Fri, 29 Sep 2023 14:26:08 +0200 |
This is an automated email from the git hooks/post-receive script.
ms pushed a commit to branch master
in repository libeufin.
The following commit(s) were added to refs/heads/master by this push:
new 642d36b0 Checking big amounts.
642d36b0 is described below
commit 642d36b0b738311dd0e12212f664a237bd64138c
Author: MS <ms@taler.net>
AuthorDate: Fri Sep 29 14:23:17 2023 +0200
Checking big amounts.
Checking that debt limits are honored and that gigantic
amounts fail soon at parsing time.
---
.../tech/libeufin/bank/CorebankApiHandlers.kt | 28 +++++++++-----
.../src/main/kotlin/tech/libeufin/bank/Database.kt | 7 ++--
bank/src/test/kotlin/LibeuFinApiTest.kt | 44 ++++++++++++++++++++++
bank/src/test/kotlin/TalerApiTest.kt | 25 +++++++-----
database-versioning/procedures.sql | 1 +
5 files changed, 82 insertions(+), 23 deletions(-)
diff --git a/bank/src/main/kotlin/tech/libeufin/bank/CorebankApiHandlers.kt
b/bank/src/main/kotlin/tech/libeufin/bank/CorebankApiHandlers.kt
index fc3ca211..b11f29ac 100644
--- a/bank/src/main/kotlin/tech/libeufin/bank/CorebankApiHandlers.kt
+++ b/bank/src/main/kotlin/tech/libeufin/bank/CorebankApiHandlers.kt
@@ -240,6 +240,8 @@ fun Routing.accountsMgmtHandlers(db: Database, ctx:
BankApplicationContext) {
val accountName = call.expectUriComponent("USERNAME")
if (c.login != accountName) throw unauthorized("User ${c.login} not
allowed to withdraw for account '${accountName}'")
val req = call.receive<BankAccountCreateWithdrawalRequest>() //
Checking that the user has enough funds.
+ if(req.amount.currency != ctx.currency)
+ throw badRequest("Wrong currency: ${req.amount.currency}")
val b = db.bankAccountGetFromOwnerId(c.expectRowId())
?: throw internalServerError("Customer '${c.login}' lacks bank
account.")
if (!isBalanceEnough(
@@ -375,26 +377,34 @@ fun Routing.accountsMgmtHandlers(db: Database, ctx:
BankApplicationContext) {
// Creates a bank transaction.
post("/accounts/{USERNAME}/transactions") {
- val c = call.authenticateBankRequest(db, TokenScope.readwrite) ?:
throw unauthorized()
+ val c: Customer = call.authenticateBankRequest(db,
TokenScope.readwrite) ?: throw unauthorized()
val resourceName = call.expectUriComponent("USERNAME") // admin has no
rights here.
if ((c.login != resourceName) && (call.getAuthToken() == null)) throw
forbidden()
val txData = call.receive<BankAccountTransactionCreate>()
val payto = parsePayto(txData.payto_uri) ?: throw badRequest("Invalid
creditor Payto")
val paytoWithoutParams = stripIbanPayto(txData.payto_uri)
val subject = payto.message ?: throw badRequest("Wire transfer lacks
subject")
- val debtorId = c.dbRowId
- ?: throw internalServerError("Debtor database ID not found") //
This performs already a SELECT on the bank account, like the wire transfer will
do as well later!
+ val debtorBankAccount = db.bankAccountGetFromOwnerId(c.expectRowId())
+ ?: throw internalServerError("Debtor bank account not found")
+ if (txData.amount.currency != ctx.currency) throw badRequest(
+ "Wrong currency: ${txData.amount.currency}",
+ talerErrorCode = TalerErrorCode.TALER_EC_GENERIC_CURRENCY_MISMATCH
+ )
+ if (!isBalanceEnough(
+ balance = debtorBankAccount.expectBalance(),
+ due = txData.amount,
+ hasBalanceDebt = debtorBankAccount.hasDebt,
+ maxDebt = debtorBankAccount.maxDebt
+ ))
+ throw conflict(hint = "Insufficient balance.", talerEc =
TalerErrorCode.TALER_EC_BANK_UNALLOWED_DEBIT)
logger.info("creditor payto: $paytoWithoutParams")
- val creditorCustomerData =
db.bankAccountGetFromInternalPayto(paytoWithoutParams) ?: throw notFound(
+ val creditorBankAccount =
db.bankAccountGetFromInternalPayto(paytoWithoutParams) ?: throw notFound(
"Creditor account not found",
TalerErrorCode.TALER_EC_BANK_UNKNOWN_ACCOUNT
)
- if (txData.amount.currency != ctx.currency) throw badRequest(
- "Wrong currency: ${txData.amount.currency}", talerErrorCode =
TalerErrorCode.TALER_EC_GENERIC_CURRENCY_MISMATCH
- )
val dbInstructions = BankInternalTransaction(
- debtorAccountId = debtorId,
- creditorAccountId = creditorCustomerData.owningCustomerId,
+ debtorAccountId = debtorBankAccount.expectRowId(),
+ creditorAccountId = creditorBankAccount.expectRowId(),
subject = subject,
amount = txData.amount,
transactionDate = Instant.now()
diff --git a/bank/src/main/kotlin/tech/libeufin/bank/Database.kt
b/bank/src/main/kotlin/tech/libeufin/bank/Database.kt
index 07ae1bd3..a402462c 100644
--- a/bank/src/main/kotlin/tech/libeufin/bank/Database.kt
+++ b/bank/src/main/kotlin/tech/libeufin/bank/Database.kt
@@ -21,6 +21,7 @@
package tech.libeufin.bank
import org.postgresql.jdbc.PgConnection
+import org.postgresql.util.PSQLException
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import tech.libeufin.util.getJdbcConnectionFromPg
@@ -176,10 +177,8 @@ class Database(private val dbConfig: String, private val
bankCurrency: String) {
stmt.execute()
} catch (e: SQLException) {
logger.error(e.message)
- // NOTE: it seems that _every_ error gets the 0 code.
- if (e.errorCode == 0) return false
- // rethrowing, not to hide other types of errors.
- throw e
+ if (e.sqlState == "23505") return false // unique_violation
+ throw e // rethrowing, not to hide other types of errors.
}
return true
}
diff --git a/bank/src/test/kotlin/LibeuFinApiTest.kt
b/bank/src/test/kotlin/LibeuFinApiTest.kt
index a1d29720..eb44f06b 100644
--- a/bank/src/test/kotlin/LibeuFinApiTest.kt
+++ b/bank/src/test/kotlin/LibeuFinApiTest.kt
@@ -130,6 +130,50 @@ class LibeuFinApiTest {
}
val obj: BankAccountTransactionInfo =
Json.decodeFromString(r.bodyAsText())
assert(obj.subject == "payout")
+ // Testing the wrong currency.
+ val wrongCurrencyResp = client.post("/accounts/foo/transactions") {
+ expectSuccess = false
+ basicAuth("foo", "pw")
+ contentType(ContentType.Application.Json)
+ // expectSuccess = true
+ setBody(
+ """{
+ "payto_uri": "payto://iban/AC${barId}?message=payout",
+ "amount": "EUR:3.3"
+ }
+ """.trimIndent()
+ )
+ }
+ assert(wrongCurrencyResp.status == HttpStatusCode.BadRequest)
+ // Surpassing the debt limit.
+ val unallowedDebtResp = client.post("/accounts/foo/transactions") {
+ expectSuccess = false
+ basicAuth("foo", "pw")
+ contentType(ContentType.Application.Json)
+ // expectSuccess = true
+ setBody(
+ """{
+ "payto_uri": "payto://iban/AC${barId}?message=payout",
+ "amount": "KUDOS:555"
+ }
+ """.trimIndent()
+ )
+ }
+ assert(unallowedDebtResp.status == HttpStatusCode.Conflict)
+ val bigAmount = client.post("/accounts/foo/transactions") {
+ expectSuccess = false
+ basicAuth("foo", "pw")
+ contentType(ContentType.Application.Json)
+ // expectSuccess = true
+ setBody(
+ """{
+ "payto_uri": "payto://iban/AC${barId}?message=payout",
+ "amount": "KUDOS:${"5".repeat(200)}"
+ }
+ """.trimIndent()
+ )
+ }
+ assert(bigAmount.status == HttpStatusCode.BadRequest)
}
}
diff --git a/bank/src/test/kotlin/TalerApiTest.kt
b/bank/src/test/kotlin/TalerApiTest.kt
index a78a7a1a..37270b9d 100644
--- a/bank/src/test/kotlin/TalerApiTest.kt
+++ b/bank/src/test/kotlin/TalerApiTest.kt
@@ -53,11 +53,6 @@ class TalerApiTest {
assert(db.bankAccountCreate(bankAccountFoo) != null)
assert(db.customerCreate(customerBar) != null)
assert(db.bankAccountCreate(bankAccountBar) != null)
- // Give the exchange reasonable debt allowance:
- assert(db.bankAccountSetMaxDebt(
- 1L,
- TalerAmount(1000, 0, "KUDOS")
- ))
// Do POST /transfer.
testApplication {
application {
@@ -68,17 +63,29 @@ class TalerApiTest {
"request_uid": "entropic 0",
"wtid": "entropic 1",
"exchange_base_url": "http://exchange.example.com/",
- "amount": "KUDOS:33",
+ "amount": "KUDOS:55",
"credit_account": "BAR-IBAN-ABC"
}
""".trimIndent()
+ // Checking exchange debt constraint.
+ val resp =
client.post("/accounts/foo/taler-wire-gateway/transfer") {
+ basicAuth("foo", "pw")
+ contentType(ContentType.Application.Json)
+ expectSuccess = false
+ setBody(req)
+ }
+ assert(resp.status == HttpStatusCode.Conflict)
+ // Giving debt allowance and checking the OK case.
+ assert(db.bankAccountSetMaxDebt(
+ 1L,
+ TalerAmount(1000, 0, "KUDOS")
+ ))
client.post("/accounts/foo/taler-wire-gateway/transfer") {
basicAuth("foo", "pw")
contentType(ContentType.Application.Json)
expectSuccess = true
setBody(req)
}
- // println(resp.bodyAsText())
// check idempotency
client.post("/accounts/foo/taler-wire-gateway/transfer") {
basicAuth("foo", "pw")
@@ -86,7 +93,6 @@ class TalerApiTest {
expectSuccess = true
setBody(req)
}
- // println(idemResp.bodyAsText())
// Trigger conflict due to reused request_uid
val r = client.post("/accounts/foo/taler-wire-gateway/transfer") {
basicAuth("foo", "pw")
@@ -103,8 +109,7 @@ class TalerApiTest {
""".trimIndent())
}
assert(r.status == HttpStatusCode.Conflict)
- /* Triggering currency mismatch. This mainly tests
- * the TalerAmount "@Contextual" parser. */
+ // Triggering currency mismatch
val currencyMismatchResp =
client.post("/accounts/foo/taler-wire-gateway/transfer") {
basicAuth("foo", "pw")
contentType(ContentType.Application.Json)
diff --git a/database-versioning/procedures.sql
b/database-versioning/procedures.sql
index 25cc8df8..652219ba 100644
--- a/database-versioning/procedures.sql
+++ b/database-versioning/procedures.sql
@@ -146,6 +146,7 @@ SELECT
IF (maybe_balance_insufficient)
THEN
out_exchange_balance_insufficient=TRUE;
+ RETURN;
END IF;
out_exchange_balance_insufficient=FALSE;
INSERT
--
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [libeufin] branch master updated: Checking big amounts.,
gnunet <=