libeufin

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

commit 6ec304b214ef21445175fac36f861237de4d0aaa
parent 554a31357786dc80cd5db5310b184ca532747566
Author: Antoine A <>
Date:   Fri, 10 Nov 2023 13:52:10 +0000

Improve cashout API

Diffstat:
Mbank/src/main/kotlin/tech/libeufin/bank/Authentication.kt | 13-------------
Mbank/src/main/kotlin/tech/libeufin/bank/CoreBankApi.kt | 2+-
Mbank/src/main/kotlin/tech/libeufin/bank/helpers.kt | 30++++++++++++++++++++++++++++--
Mbank/src/test/kotlin/CoreBankApiTest.kt | 16++++++++++++++++
Mbank/src/test/kotlin/helpers.kt | 2++
5 files changed, 47 insertions(+), 16 deletions(-)

diff --git a/bank/src/main/kotlin/tech/libeufin/bank/Authentication.kt b/bank/src/main/kotlin/tech/libeufin/bank/Authentication.kt @@ -75,19 +75,6 @@ val PipelineContext<Unit, ApplicationCall>.isAdmin: Boolean get() = call.isAdmin val ApplicationCall.username: String get() = expectUriComponent("USERNAME") val ApplicationCall.isAdmin: Boolean get() = attributes.getOrNull(AUTH_IS_ADMIN) ?: false -private fun Route.intercept(callback: Route.() -> Unit, interceptor: suspend PipelineContext<Unit, ApplicationCall>.() -> Unit): Route { - val subRoute = createChild(object : RouteSelector() { - override fun evaluate(context: RoutingResolveContext, segmentIndex: Int): RouteSelectorEvaluation = - RouteSelectorEvaluation.Constant - }) - subRoute.intercept(ApplicationCallPipeline.Plugins) { - interceptor() - proceed() - } - - callback(subRoute) - return subRoute -} /** * This function tries to authenticate the call according * to the scheme that is mentioned in the Authorization header. diff --git a/bank/src/main/kotlin/tech/libeufin/bank/CoreBankApi.kt b/bank/src/main/kotlin/tech/libeufin/bank/CoreBankApi.kt @@ -466,7 +466,7 @@ private fun Routing.coreBankWithdrawalApi(db: Database, ctx: BankConfig) { } } -private fun Routing.coreBankCashoutApi(db: Database, ctx: BankConfig) { +private fun Routing.coreBankCashoutApi(db: Database, ctx: BankConfig) = conditional(ctx.haveCashout) { val TAN_RETRY_COUNTER: Int = 3; val TAN_VALIDITY_PERIOD: Duration = Duration.ofHours(1) val TAN_RETRANSMISSION_PERIOD: Duration = Duration.ofMinutes(1) diff --git a/bank/src/main/kotlin/tech/libeufin/bank/helpers.kt b/bank/src/main/kotlin/tech/libeufin/bank/helpers.kt @@ -24,7 +24,12 @@ import io.ktor.server.application.* import io.ktor.server.plugins.* import io.ktor.server.request.* import io.ktor.server.util.* +import io.ktor.server.routing.Route +import io.ktor.server.routing.RouteSelector +import io.ktor.server.routing.RoutingResolveContext +import io.ktor.server.routing.RouteSelectorEvaluation import io.ktor.util.valuesOf +import io.ktor.util.pipeline.PipelineContext import net.taler.common.errorcodes.TalerErrorCode import net.taler.wallet.crypto.Base32Crockford import org.slf4j.Logger @@ -156,4 +161,25 @@ suspend fun maybeCreateAdminAccount(db: Database, ctx: BankConfig, pw: String? = CustomerCreationResult.CONFLICT_PAY_TO -> false CustomerCreationResult.SUCCESS -> true } -} -\ No newline at end of file +} + +fun Route.intercept(callback: Route.() -> Unit, interceptor: suspend PipelineContext<Unit, ApplicationCall>.() -> Unit): Route { + val subRoute = createChild(object : RouteSelector() { + override fun evaluate(context: RoutingResolveContext, segmentIndex: Int): RouteSelectorEvaluation = + RouteSelectorEvaluation.Constant + }) + subRoute.intercept(ApplicationCallPipeline.Plugins) { + interceptor() + proceed() + } + + callback(subRoute) + return subRoute +} + +fun Route.conditional(implemented: Boolean, callback: Route.() -> Unit): Route = + intercept(callback) { + if (!implemented) { + throw libeufinError(HttpStatusCode.NotImplemented, "API not implemented", TalerErrorCode.END) + } + } +\ No newline at end of file diff --git a/bank/src/test/kotlin/CoreBankApiTest.kt b/bank/src/test/kotlin/CoreBankApiTest.kt @@ -1505,6 +1505,9 @@ class CoreBankCashoutApiTest { val resp = json<ConversionResponse>() assertEquals(TalerAmount("FIAT:1.247"), resp.amount_credit) } + // Not implemented (yet) + client.get("/cashout-rate?amount_credit=FIAT:1") + .assertNotImplemented() // Too small client.get("/cashout-rate?amount_debit=KUDOS:0.08") @@ -1539,6 +1542,9 @@ class CoreBankCashoutApiTest { assertEquals(TalerAmount("KUDOS:$converted"), resp.amount_credit) } } + // Not implemented (yet) + client.get("/cashin-rate?amount_credit=KUDOS:1") + .assertNotImplemented() // No amount client.get("/cashin-rate") @@ -1557,4 +1563,14 @@ class CoreBankCashoutApiTest { client.get("/cashin-rate?amount_credit=FIAT:1") .assertBadRequest(TalerErrorCode.GENERIC_CURRENCY_MISMATCH) } + + @Test + fun notImplemented() = bankSetup("test_restrict.conf") { _ -> + client.get("/cashin-rate") + .assertNotImplemented() + client.get("/cashout-rate") + .assertNotImplemented() + client.get("/accounts/customer/cashouts") + .assertNotImplemented() + } } \ No newline at end of file diff --git a/bank/src/test/kotlin/helpers.kt b/bank/src/test/kotlin/helpers.kt @@ -185,6 +185,8 @@ suspend fun HttpResponse.assertBadRequest(err: TalerErrorCode? = null): HttpResp = assertStatus(HttpStatusCode.BadRequest, err) suspend fun HttpResponse.assertForbidden(err: TalerErrorCode? = null): HttpResponse = assertStatus(HttpStatusCode.Forbidden, err) +suspend fun HttpResponse.assertNotImplemented(err: TalerErrorCode? = null): HttpResponse + = assertStatus(HttpStatusCode.NotImplemented, err) suspend fun HttpResponse.assertErr(code: TalerErrorCode): HttpResponse {