libeufin

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

commit 31063cc9f4e38e5baa61a018e13a7c0943fb485d
parent 61f5dcc1d217b5eb169cf46ef24e5d760598fe54
Author: Antoine A <>
Date:   Wed, 28 May 2025 18:13:03 +0200

nexus: fix WG /transfer removing the receiver-name

Diffstat:
Mbank/src/main/kotlin/tech/libeufin/bank/api/CoreBankApi.kt | 4++--
Mbank/src/main/kotlin/tech/libeufin/bank/api/WireGatewayApi.kt | 2+-
Mcommon/src/main/kotlin/TalerCommon.kt | 24++++++++----------------
Mcommon/src/main/kotlin/api/server.kt | 17+++++++++++++++--
Mnexus/src/main/kotlin/tech/libeufin/nexus/api/WireGatewayApi.kt | 4++--
Mnexus/src/main/kotlin/tech/libeufin/nexus/db/ExchangeDAO.kt | 2+-
Mnexus/src/test/kotlin/WireGatewayApiTest.kt | 9++++++++-
7 files changed, 37 insertions(+), 25 deletions(-)

diff --git a/bank/src/main/kotlin/tech/libeufin/bank/api/CoreBankApi.kt b/bank/src/main/kotlin/tech/libeufin/bank/api/CoreBankApi.kt @@ -231,7 +231,7 @@ suspend fun createAccount( when (cfg.wireMethod) { WireMethod.IBAN -> { - req.payto_uri?.expectRequestIban() + req.payto_uri?.expectIban() var retry = if (req.payto_uri == null) IBAN_ALLOCATION_RETRY_COUNTER else 0 while (true) { @@ -247,7 +247,7 @@ suspend fun createAccount( } WireMethod.X_TALER_BANK -> { if (req.payto_uri != null) { - val payto = req.payto_uri.expectRequestXTalerBank() + val payto = req.payto_uri.expectXTalerBank() if (payto.username != req.username) throw badRequest("Expected a payto uri for '${req.username}' got one for '${payto.username}'") } diff --git a/bank/src/main/kotlin/tech/libeufin/bank/api/WireGatewayApi.kt b/bank/src/main/kotlin/tech/libeufin/bank/api/WireGatewayApi.kt @@ -144,7 +144,7 @@ fun Routing.wireGatewayApi(db: Database, cfg: BankConfig) { throw notExchange(call.username) val params = AccountCheckParams.extract(call.request.queryParameters) - val account = params.account.expectRequestIban() + val account = params.account.expectIban() val info = db.account.checkInfo(account) ?: throw unknownAccount(account.canonical) call.respond(info) diff --git a/common/src/main/kotlin/TalerCommon.kt b/common/src/main/kotlin/TalerCommon.kt @@ -320,6 +320,14 @@ sealed class Payto { } } + fun expectIbanFull(): IbanPayto { + val payto = expectIban() + if (payto.receiverName == null) { + throw CommonError.Payto("expectd a full IBAN payto got no receiver-name") + } + return payto + } + fun expectIban(): IbanPayto { return when (this) { is IbanPayto -> this @@ -327,14 +335,6 @@ sealed class Payto { } } - fun expectRequestIban(): IbanPayto { - try { - return expectIban() - } catch (e: Exception) { - throw BadRequestException(e.message ?: "", e) - } - } - fun expectXTalerBank(): XTalerBankPayto { return when (this) { is XTalerBankPayto -> this @@ -342,14 +342,6 @@ sealed class Payto { } } - fun expectRequestXTalerBank(): XTalerBankPayto { - try { - return expectXTalerBank() - } catch (e: Exception) { - throw BadRequestException(e.message ?: "", e) - } - } - override fun equals(other: Any?): Boolean { if (this === other) return true if (other !is Payto) return false diff --git a/common/src/main/kotlin/api/server.kt b/common/src/main/kotlin/api/server.kt @@ -217,7 +217,7 @@ fun Application.talerApi(logger: Logger, routes: Routing.() -> Unit) { while (rootCause?.cause != null) rootCause = rootCause.cause // Telling apart invalid JSON vs missing parameter vs invalid parameter. - val talerErrorCode = when { + val errorCode = when { cause is MissingRequestParameterException -> TalerErrorCode.GENERIC_PARAMETER_MISSING cause is ParameterConversionException -> @@ -232,7 +232,20 @@ fun Application.talerApi(logger: Logger, routes: Routing.() -> Unit) { call.err( HttpStatusCode.BadRequest, rootCause?.message, - talerErrorCode, + errorCode, + null + ) + } + is CommonError -> { + val errorCode = when (cause) { + is CommonError.AmountFormat -> TalerErrorCode.BANK_BAD_FORMAT_AMOUNT + is CommonError.AmountNumberTooBig -> TalerErrorCode.BANK_NUMBER_TOO_BIG + is CommonError.Payto -> TalerErrorCode.GENERIC_JSON_INVALID + } + call.err( + HttpStatusCode.BadRequest, + cause.message, + errorCode, null ) } diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/api/WireGatewayApi.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/api/WireGatewayApi.kt @@ -48,7 +48,7 @@ fun Routing.wireGatewayApi(db: Database, cfg: NexusConfig) = conditional(cfg.wir post("/taler-wire-gateway/transfer") { val req = call.receive<TransferRequest>() cfg.checkCurrency(req.amount) - req.credit_account.expectRequestIban() + req.credit_account.expectIbanFull() val endToEndId = randEbicsId() val res = db.exchange.transfer( req, @@ -118,7 +118,7 @@ fun Routing.wireGatewayApi(db: Database, cfg: NexusConfig) = conditional(cfg.wir metadata: IncomingSubject ) { cfg.checkCurrency(amount) - val debitAccount = debitAccount.expectRequestIban() + val debitAccount = debitAccount.expectIban() val timestamp = Instant.now() val res = db.payment.registerTalerableIncoming(IncomingPayment( amount = amount, diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/db/ExchangeDAO.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/db/ExchangeDAO.kt @@ -127,7 +127,7 @@ class ExchangeDAO(private val db: Database) { bind(subject) bind(req.amount) bind(req.exchange_base_url.url) - bind(req.credit_account.canonical) + bind(req.credit_account.toString()) bind(endToEndId) bind(timestamp) one { diff --git a/nexus/src/test/kotlin/WireGatewayApiTest.kt b/nexus/src/test/kotlin/WireGatewayApiTest.kt @@ -107,10 +107,17 @@ class WireGatewayApiTest { } }.assertBadRequest() + // Missing receiver-name + client.postA("/taler-wire-gateway/transfer") { + json(valid_req) { + "credit_account" to "payto://iban/CH7389144832588726658" + } + }.assertBadRequest() + // Bad payto kind client.postA("/taler-wire-gateway/transfer") { json(valid_req) { - "credit_account" to "payto://x-taler-bank/bank.hostname.test/bar" + "credit_account" to "payto://x-taler-bank/bank.hostname.test/bar?receiver-name=Mr+Tom" } }.assertBadRequest()